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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
extern crate proc_macro; extern crate syn; #[macro_use] extern crate quote; use proc_macro::TokenStream; #[proc_macro_derive(EnumError)] pub fn enum_error(input: TokenStream) -> TokenStream { let s = input.to_string(); let ast = syn::parse_macro_input(&s).unwrap(); let gen = impl_enum_error(&ast); gen.parse().unwrap() } fn impl_from_traits(name: &syn::Ident, variants: &Vec<syn::Variant>) -> quote::Tokens { let impls = variants.iter() .map(|var| { let v = &var.ident; let cont = match var.data { syn::VariantData::Tuple(ref c) => c, _ => unreachable!(), }; assert!(cont.len() == 1, "Single Tuple is required"); let ctype = &cont[0].ty; quote!{ impl From<#ctype> for #name { fn from(val: #ctype) -> Self { #name::#v(val) } } } }); quote!{ #(#impls)* } } fn impl_error(name: &syn::Ident, variants: &Vec<syn::Variant>) -> quote::Tokens { let snips = variants.iter() .map(|var| { let v = &var.ident; quote!{ #name::#v(ref err) => err.description() } }); quote!{ impl ::std::error::Error for #name { fn description(&self) -> &str { match *self { #(#snips), * } } } } } fn impl_display(name: &syn::Ident, variants: &Vec<syn::Variant>) -> quote::Tokens { let snips = variants.iter() .map(|var| { let v = &var.ident; quote!{ #name::#v(ref err) => err.fmt(f) } }); quote!{ impl ::std::fmt::Display for Error { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match *self { #(#snips), * } } } } } fn impl_enum_error(ast: &syn::MacroInput) -> quote::Tokens { let name = &ast.ident; let ref variants = match ast.body { syn::Body::Enum(ref variants) => variants, syn::Body::Struct(_) => unreachable!(), }; let mut token = quote::Tokens::new(); token.append_all(&[impl_from_traits(&name, &variants), impl_display(&name, &variants), impl_error(&name, &variants)]); token }