err_gen/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{
6    self,
7    DeriveInput,
8    TypeTuple,
9};
10
11#[proc_macro_attribute]
12pub fn err_gen(attr: TokenStream, input: TokenStream) -> TokenStream {
13    use syn::Data::*;
14
15    let attr_ast: TypeTuple = syn::parse(attr).unwrap();
16    let input_ast: DeriveInput = syn::parse(input).unwrap();
17
18    let raw_enum = match input_ast.data {
19        Enum(data_enum) => data_enum,
20        _ => panic!("input must be an enum"),
21    };
22
23    let name = &input_ast.ident;
24
25    let mut nested_variants = quote! {};
26
27    for variant in raw_enum.variants.iter() {
28        nested_variants = quote! {
29            #variant,
30            #nested_variants
31        };
32    }
33
34    let mut generated_nested_variants = quote! {};
35
36    for element in attr_ast.elems.iter() {
37        use syn::Type::*;
38        let element_name = match element {
39            Path(type_path) => type_path
40                .path
41                .segments
42                .last()
43                .expect("no variant name found")
44                .ident
45                .clone(),
46            _ => panic!("element must be a path-name"),
47        };
48
49        let gnv_display = format!("({}::{}) -> {{}}", name, element_name);
50
51        generated_nested_variants = quote! {
52            #[display(fmt = #gnv_display, _0)]
53            #element(#element),
54            #generated_nested_variants
55        }
56    }
57
58    let enum_declaration = quote! {
59        #[derive(derive_more::Display, Debug)]
60        pub enum #name {
61            #nested_variants
62            #generated_nested_variants
63        }
64
65        impl std::error::Error for #name {}
66    };
67
68    let mut impl_clauses = quote! {};
69
70    for element in attr_ast.elems.iter() {
71        impl_clauses = quote! {
72            impl From<#element> for #name {
73                fn from(e: #element) -> Self { Self::#element(e) }
74            }
75            #impl_clauses
76        };
77    }
78
79    let result = quote! {
80        #enum_declaration
81        #impl_clauses
82    };
83
84    result.into()
85}