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}