csskit_derives/
lib.rs

1#![deny(warnings)]
2use proc_macro::TokenStream;
3use proc_macro2::Span;
4use syn::{AngleBracketedGenericArguments, Error, GenericArgument, PathArguments, PathSegment, Type, TypePath};
5
6mod attributes;
7mod css_feature;
8mod declaration_metadata;
9mod into_cursor;
10mod node_with_metadata;
11mod parse;
12mod peek;
13mod semantic_eq;
14mod to_cursors;
15mod to_span;
16mod visitable;
17mod where_collector;
18
19use where_collector::WhereCollector;
20
21#[cfg(test)]
22mod test;
23
24#[proc_macro_derive(ToCursors, attributes(to_cursors))]
25pub fn derive_to_cursors(stream: TokenStream) -> TokenStream {
26	let input = syn::parse(stream).unwrap();
27	to_cursors::derive(input).into()
28}
29
30#[proc_macro_derive(Parse, attributes(parse, atom))]
31pub fn derive_parse(stream: TokenStream) -> TokenStream {
32	let input = syn::parse(stream).unwrap();
33	parse::derive(input).into()
34}
35
36#[proc_macro_derive(Peek, attributes(peek, atom))]
37pub fn derive_peek(stream: TokenStream) -> TokenStream {
38	let input = syn::parse(stream).unwrap();
39	peek::derive(input).into()
40}
41
42#[proc_macro_derive(IntoCursor)]
43pub fn derive_into_cursor(stream: TokenStream) -> TokenStream {
44	let input = syn::parse(stream).unwrap();
45	into_cursor::derive(input).into()
46}
47
48#[proc_macro_derive(ToSpan)]
49pub fn derive_into_span(stream: TokenStream) -> TokenStream {
50	let input = syn::parse(stream).unwrap();
51	to_span::derive(input).into()
52}
53
54#[proc_macro_derive(Visitable, attributes(visit, queryable))]
55pub fn derive_visitable(stream: TokenStream) -> TokenStream {
56	let input = syn::parse(stream).unwrap();
57	visitable::derive(input).into()
58}
59
60#[proc_macro_derive(NodeWithMetadata, attributes(metadata))]
61pub fn derive_node_with_metadata(stream: TokenStream) -> TokenStream {
62	let input = syn::parse(stream).unwrap();
63	node_with_metadata::derive(input).into()
64}
65
66#[proc_macro_derive(ToCSSFeature, attributes(css_feature))]
67pub fn derive_css_feature(stream: TokenStream) -> TokenStream {
68	let input = syn::parse(stream).unwrap();
69	css_feature::derive(input).into()
70}
71
72#[proc_macro_derive(DeclarationMetadata, attributes(declaration_metadata))]
73pub fn derive_declaration_metadata(stream: TokenStream) -> TokenStream {
74	let input = syn::parse(stream).unwrap();
75	declaration_metadata::derive(input).into()
76}
77
78#[proc_macro_derive(SemanticEq, attributes(semantic_eq))]
79pub fn derive_semantic_eq(stream: TokenStream) -> TokenStream {
80	let input = syn::parse(stream).unwrap();
81	semantic_eq::derive(input).into()
82}
83
84fn err(span: Span, msg: &str) -> proc_macro2::TokenStream {
85	let err = Error::new(span, msg).into_compile_error();
86	quote::quote! {#err}
87}
88
89trait TypeIsOption {
90	fn is_option(&self) -> bool;
91	fn unpack_option(&self) -> Self;
92}
93
94impl TypeIsOption for Type {
95	fn is_option(&self) -> bool {
96		match self {
97			Self::Path(TypePath { path, .. }) => path.segments.last().is_some_and(|s| s.ident == "Option"),
98			_ => false,
99		}
100	}
101
102	fn unpack_option(&self) -> Self {
103		if let Self::Path(TypePath { path, .. }) = self
104			&& let Some(PathSegment {
105				ident,
106				arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }),
107				..
108			}) = path.segments.last()
109			&& ident == "Option"
110			&& args.len() == 1
111			&& let GenericArgument::Type(inner_ty) = &args[0]
112		{
113			return inner_ty.clone();
114		}
115		self.clone()
116	}
117}