1extern crate proc_macro;
2extern crate quote;
3extern crate syn;
4extern crate proc_macro2;
5
6use proc_macro::TokenStream;
7use proc_macro2::Span;
8
9use syn::*;
10use quote::quote;
11
12#[proc_macro_derive(ReParse, attributes(re_parse))]
13pub fn re_parse_macro_derive(item: TokenStream) -> TokenStream {
14 let mut item = parse_macro_input!(item as DeriveInput);
15
16 let regex = item.attrs.iter()
17 .flat_map(|x| x.parse_meta() )
18 .filter_map(|x| match x { Meta::List(y) => Some(y), _ => None })
19 .filter(|x| x.ident == "re_parse" )
20 .flat_map(|x| x.nested.into_iter() )
21 .filter_map(|x| match x { NestedMeta::Meta(y) => Some(y), _ => None })
22 .filter_map(|x| match x { Meta::NameValue(y) => Some(y), _ => None })
23 .find(|x| x.ident == "regex" )
24 .and_then(|x| match x.lit { Lit::Str(y) => Some(y.value()), _ => None })
25 .unwrap();
26
27 let item_ident = &item.ident;
28
29 let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
30
31 let impl_inner = quote! {
32 impl #impl_generics std::str::FromStr for #item_ident #ty_generics #where_clause {
33 type Err = _re_parse::Error;
34 fn from_str(s: &str) -> Result<Self, Self::Err> {
35 _re_parse::lazy_static! {
36 static ref RE: _re_parse::Regex = Regex::new(#regex).unwrap();
37 }
38
39 Ok(_re_parse::with_pattern_from_str(&*RE, s)?)
40 }
41 }
42 };
43
44 let dummy_const = Ident::new(
47 &format!("_IMPL_FromStr_FOR_{}", item.ident.to_string()),
48 Span::call_site()
49 );
50
51 let out = quote!{
52 #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
53 const #dummy_const: () = {
54 #[allow(unknown_lints)]
55 #[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
56 extern crate re_parse as _re_parse;
57 #impl_inner
58 };
59 };
60
61 out.into()
62}