1#![cfg_attr(feature = "_doc", feature(doc_cfg, external_doc))]
2#![cfg_attr(feature = "_doc", doc(include = "../README.md"))]
3
4extern crate proc_macro;
5extern crate proc_macro2;
6extern crate quote;
7
8use std::collections::HashSet;
9
10use quote::{quote, ToTokens};
11use syn::{parse_macro_input, punctuated::Punctuated, spanned::Spanned};
12
13mod default;
16mod derive;
17mod utils;
18
19struct Args {
22 default: Option<syn::Path>,
23 derives: HashSet<derive::Derive>,
24}
25
26impl Args {
27 fn from_meta(arg: &syn::Meta) -> syn::Result<Self> {
28 let mut default = None;
29 let mut derives = HashSet::new();
30
31 match arg {
32 syn::Meta::List(ref l) if l.path.to_token_stream().to_string() == "derive" => {
33 let types = l.parse_args_with(
34 Punctuated::<syn::Path, syn::Token![,]>::parse_separated_nonempty,
35 )?;
36 for pair in types.into_pairs() {
37 if let Some(d) = derive::Derive::from_path(pair.value()) {
38 derives.insert(d);
39 } else {
40 return Err(syn::Error::new(
41 pair.span(),
42 "unknown blanket derive option",
43 ));
44 }
45 }
46 }
47 syn::Meta::NameValue(ref n) if n.path.to_token_stream().to_string() == "default" => {
48 match n.value {
49 syn::Expr::Lit(ref lit) => {
50 if let syn::Lit::Str(ref s) = lit.lit {
51 match syn::parse_str(&s.value()) {
52 Ok(path) if default.is_none() => {
53 default = Some(path);
54 }
55 Ok(_) => {
56 return Err(syn::Error::new(
57 s.span(),
58 "duplicate default module given",
59 ))
60 }
61 Err(_) => {
62 return Err(syn::Error::new(
63 s.span(),
64 "expected module identifier",
65 ))
66 }
67 }
68 } else {
69 return Err(syn::Error::new(lit.lit.span(), "expected string literal"));
70 }
71 }
72 syn::Expr::Path(ref expr) => {
73 if default.replace(expr.path.clone()).is_some() {
74 return Err(syn::Error::new(
75 n.span(),
76 "duplicate default module given",
77 ));
78 }
79 }
80 _ => {
81 return Err(syn::Error::new(
82 n.value.span(),
83 "expected path or string literal",
84 ));
85 }
86 }
87 }
88 _ => return Err(syn::Error::new(arg.span(), "unexpected argument")),
89 }
90
91 Ok(Self { default, derives })
92 }
93}
94
95#[proc_macro_attribute]
98pub fn blanket(
99 args: proc_macro::TokenStream,
100 input: proc_macro::TokenStream,
101) -> proc_macro::TokenStream {
102 let trait_ = parse_macro_input!(input as syn::ItemTrait);
104 let args = parse_macro_input!(args as syn::Meta);
105 let args = match Args::from_meta(&args) {
107 Ok(args) => args,
108 Err(e) => {
109 let err = e.to_compile_error();
110 return proc_macro::TokenStream::from(quote!(#err #trait_));
111 }
112 };
113 let mut out = proc_macro2::TokenStream::new();
115 match args.default {
118 None => out.extend(quote!(#trait_)),
119 Some(d) => match default::defer_trait_methods(trait_.clone(), d) {
120 Ok(trait_) => out.extend(quote!(#trait_)),
121 Err(err) => out.extend(err.to_compile_error()),
122 },
123 };
124 for d in args.derives {
126 match d.defer_trait_methods(&trait_) {
127 Ok(item) => out.extend(quote!(#item)),
128 Err(e) => out.extend(e.to_compile_error()),
129 }
130 }
131 proc_macro::TokenStream::from(out)
133}