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