1#![doc = include_str!("../README.md")]
2
3extern crate proc_macro;
4extern crate proc_macro2;
5extern crate quote;
6
7use std::collections::HashSet;
8
9use quote::{quote, ToTokens};
10use syn::{parse_macro_input, punctuated::Punctuated, spanned::Spanned};
11
12mod default;
15mod derive;
16mod types;
17mod utils;
18
19struct Args {
22 default: Option<syn::Path>,
23 derives: HashSet<types::Type>,
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) = types::Type::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]
104pub fn blanket(
105 args: proc_macro::TokenStream,
106 input: proc_macro::TokenStream,
107) -> proc_macro::TokenStream {
108 let trait_ = parse_macro_input!(input as syn::ItemTrait);
110 let args = parse_macro_input!(args as syn::Meta);
111 let args = match Args::from_meta(&args) {
113 Ok(args) => args,
114 Err(e) => {
115 let err = e.to_compile_error();
116 return proc_macro::TokenStream::from(quote!(#err #trait_));
117 }
118 };
119 let mut out = proc_macro2::TokenStream::new();
121 match args.default {
124 None => out.extend(quote!(#trait_)),
125 Some(d) => match default::defer_trait_methods(trait_.clone(), d) {
126 Ok(trait_) => out.extend(quote!(#trait_)),
127 Err(err) => out.extend(err.to_compile_error()),
128 },
129 };
130 for d in args.derives {
132 match d.defer_trait_methods(&trait_) {
133 Ok(item) => out.extend(quote!(#item)),
134 Err(e) => out.extend(e.to_compile_error()),
135 }
136 }
137 proc_macro::TokenStream::from(out)
139}