1use proc_macro_error::{abort, proc_macro_error};
2use quote::quote;
3use quote::ToTokens;
4use syn::spanned::Spanned;
5
6mod captures;
7mod impl_enum;
8mod impl_struct;
9
10#[proc_macro_error]
35#[proc_macro_derive(FromRegex, attributes(from_regex))]
36pub fn derive_regex(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
37 let input = syn::parse_macro_input!(input as syn::DeriveInput);
38 Item::from(&input).into_token_stream().into()
39}
40
41#[proc_macro_error]
43#[proc_macro_derive(FromStr, attributes(from_regex))]
44pub fn derive_str(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
45 let input = syn::parse_macro_input!(input as syn::DeriveInput);
46 let ident = input.ident.clone();
47 let item = Item::from(&input);
48
49 let stream = quote! {
50 #item
51 impl std::str::FromStr for #ident {
52 type Err = ();
53 fn from_str(s: &str) -> Result<Self, Self::Err> {
54 Self::from_regex(s).ok_or(())
55 }
56 }
57 };
58
59 stream.into()
60}
61
62const ATTRIBUTE: &str = "from_regex";
63
64enum Item<'a> {
65 Enum(impl_enum::Item<'a>),
66 Struct(impl_struct::Item<'a>),
67}
68
69impl<'a> From<&'a syn::DeriveInput> for Item<'a> {
70 fn from(input: &'a syn::DeriveInput) -> Self {
71 let syn::DeriveInput {
72 data, attrs, ident, ..
73 } = input;
74 match data {
75 syn::Data::Enum(data_enum) => Item::Enum(impl_enum::Item::new(
76 ident,
77 &attrs,
78 data_enum.variants.iter(),
79 )),
80 syn::Data::Struct(syn::DataStruct { fields, .. }) => {
81 Item::Struct(impl_struct::Item::new(ident, &attrs, &fields))
82 }
83 syn::Data::Union(syn::DataUnion { union_token, .. }) => {
84 abort!(union_token.span(), "Unsupported item type")
85 }
86 }
87 }
88}
89
90impl<'a> ToTokens for Item<'a> {
91 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
92 match self {
93 Item::Enum(item) => item.to_tokens(tokens),
94 Item::Struct(item) => item.to_tokens(tokens),
95 }
96 }
97}
98
99struct Attributes<'a> {
101 iter: core::slice::Iter<'a, syn::Attribute>,
102 list: Option<syn::punctuated::IntoIter<syn::NestedMeta>>,
103}
104impl<'a> From<&'a [syn::Attribute]> for Attributes<'a> {
105 fn from(attrs: &'a [syn::Attribute]) -> Self {
106 Self {
107 iter: attrs.iter(),
108 list: None,
109 }
110 }
111}
112impl<'a> Iterator for Attributes<'a> {
113 type Item = syn::NestedMeta;
114 fn next(&mut self) -> Option<Self::Item> {
115 if let Some(list) = &mut self.list {
117 if let Some(nested) = list.next() {
118 return Some(nested);
119 }
120 }
121
122 loop {
123 let next = self.iter.next()?;
125 if let syn::Meta::List(list) = next.parse_meta().expect("failed to parse attr meta") {
126 if list.path.is_ident(ATTRIBUTE) {
127 let mut list = list.nested.into_iter();
130 if let Some(next) = list.next() {
131 self.list = Some(list);
132 return Some(next);
133 }
134 }
135 }
136 }
137 }
138}