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 84 85
extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; use syn::{ self, DeriveInput, TypeTuple, }; #[proc_macro_attribute] pub fn err_gen(attr: TokenStream, input: TokenStream) -> TokenStream { use syn::Data::*; let attr_ast: TypeTuple = syn::parse(attr).unwrap(); let input_ast: DeriveInput = syn::parse(input).unwrap(); let raw_enum = match input_ast.data { Enum(data_enum) => data_enum, _ => panic!("input must be an enum"), }; let name = &input_ast.ident; let mut nested_variants = quote! {}; for variant in raw_enum.variants.iter() { nested_variants = quote! { #variant, #nested_variants }; } let mut generated_nested_variants = quote! {}; for element in attr_ast.elems.iter() { use syn::Type::*; let element_name = match element { Path(type_path) => type_path .path .segments .last() .expect("no variant name found") .ident .clone(), _ => panic!("element must be a path-name"), }; let gnv_display = format!("({}::{}) -> {{}}", name, element_name); generated_nested_variants = quote! { #[display(fmt = #gnv_display, _0)] #element(#element), #generated_nested_variants } } let enum_declaration = quote! { #[derive(derive_more::Display, Debug)] pub enum #name { #nested_variants #generated_nested_variants } impl std::error::Error for #name {} }; let mut impl_clauses = quote! {}; for element in attr_ast.elems.iter() { impl_clauses = quote! { impl From<#element> for #name { fn from(e: #element) -> Self { Self::#element(e) } } #impl_clauses }; } let result = quote! { #enum_declaration #impl_clauses }; result.into() }