Hello, everyone! Thanks in advance.
I am trying to implement a Procedural Macro for an Enum. The idea is very simple: Different Variants within the Enum are classified into three groups (i.e., physical, personal, operational). I want to derive(ElementKind)
using attributes(personal, physical, operational)
. Now, I am having some trouble iterating Variants... this is my first time developing proc_macros
, but I did not find this issue when iterating Fields in a Struct.
Anyway, I am doing the following:
#[proc_macro_derive(ElementKind, attributes(personal, physical, operational))]
pub fn derive_kind(input: TokenStream) -> TokenStream {
// Parse the input tokens into a syntax tree
let ast = parse_macro_input!(input as DeriveInput);
match ast.data {
syn::Data::Struct(_) => derive_struct_kind(ast), // This is unimplmented!()
syn::Data::Enum(_)=>derive_struct_enum(ast),
_ => {
panic!("#name ::: can only be implemented in Structs and Enum");
}
}
}
Then, just to show one case, the function derive_struct_kind()
is the following:
fn derive_struct_enum(ast: syn::DeriveInput) -> TokenStream {
let enum_name = &ast.ident;
// Get structure fields or panic (THIS WORKS)
let variants = if let syn::Data::Enum(syn::DataEnum {
ref variants,
..
}) = ast.data
{
variants
} else {
panic!("THIS IS A BUG: Expecting an Enum");
};
// Sort variants (THIS WORKS)
let mut physical = variants.iter().filter(|v|{
let att_names : Vec<String> = v.attrs.iter().map(|a|{
format!("{}",a.path.segments[0].ident)
}).collect();
att_names.contains(&"physical".to_string())
}).map(|x|{x});
let is_physical_doc = format!("Checks whether a {} is of kind Physical", enum_name);
TokenStream::from(quote!{
impl #enum_name {
#[doc = #is_physical_doc]
pub fn is_physical(&self)->bool{
#physical // THIS FAILS!!!!!! ... I know this will not compile. I will fix this syntax when I get this to expand, at least
}
}
})
}
The error I am getting is the trait 'ToTokens
is not implemented for Map<Filter<syn::punctuated::Iter<'_, Variant>, [closure@src/lib.rs:21:53: 26:10]>, [closure@src/lib.rs:26:16: 26:22]>'
.
What am I doing wrong? When the map to be tokenized is Map<Filter<syn::punctuated::Iter<'_, Field>,...
it seems to work. What am I missing?
I would appreciate your help. (I have tried reading stuff, searching in this forum, and several "patterns" of implementing the same Macro, and I always end up with a similar error...)
Best!