autoimpl_derive/
lib.rs

1#![crate_type = "proc-macro"]
2
3#[macro_use]
4extern crate proc_macro_hack;
5
6#[macro_use]
7extern crate quote;
8
9extern crate syn;
10extern crate proc_macro;
11
12use syn::Item;
13use syn::ItemKind::Trait;
14use quote::Tokens;
15use quote::ToTokens;
16
17proc_macro_item_impl! {
18    /// Generates a default blanket impl for a generic trait that gets passed into
19    /// `generate_auto_impl_impl`, with the same type parameters and type bounds as its trait.
20    ///
21    /// # Arguments
22    ///
23    /// * `input` - A string slice of the trait source.
24    pub fn generate_auto_impl_impl(input: &str) -> String {
25        let item = syn::parse_item(input).unwrap();
26
27        let name = &item.ident;
28        match item.node {
29            Trait(_, _, _, _) => {},
30            _ => panic!("Cannot expand type {} since it's not a trait!", name)
31        }
32
33        let mut expanded = expand_trait(&item);
34        expanded.append(expand_impl(&item).as_str());
35
36        // Return the generated impl and its trait as a String
37        expanded.parse().unwrap()
38    }
39}
40
41/// Returns the Tokens of the trait that gets passed into `autoimpl!`
42fn expand_trait(ast: &Item) -> Tokens {
43    let mut tokens = Tokens::new();
44    ast.to_tokens(&mut tokens);
45    tokens
46}
47
48/// Generates a default impl of the trait that gets passed into `autoimpl!`, with the same type
49/// arguments and generic bounds as its trait.
50fn expand_impl(ast: &Item) -> Tokens {
51    // Used in the quasi-quotation below as `#name`
52    let name = &ast.ident;
53
54    match ast.node {
55        Trait(_, ref generics, _, _) => {
56            let (impl_generics, _, where_clause) = generics.split_for_impl();
57
58            if generics.ty_params.is_empty() {
59                panic!("Cannot auto-implement {} since it does not have any type parameters!",
60                       name)
61            }
62
63            quote! {
64                impl #impl_generics #name #impl_generics for T #where_clause {}
65            }
66        }
67        _ => {
68            panic!("Cannot expand type {} implementation since it's not a trait!",
69                   name)
70        }
71    }
72}