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()
}