Reputation: 760
Trying to make my own Serialize
trait and derive macro, I'm stuck when I need to access the fields of an enum.
For example, on the enum variant :
enum MyEnum {
MyVariant(f32, u16, u16)
}
I would like to do :
fn Serialize(self) -> Vec<u8> {
match self {
MyEnum::MyVariant(field0, field1, field2) => {
let mut result = Vec::<u8>::new();
result.append(&mut field0.Serialize());
result.append(&mut field1.Serialize());
result.append(&mut field1.Serialize());
result
}
}
}
The idea is that I'll implement the Serialize trait on basic data types, and it then can be extended to various structs and enums.
But I don't know how to create variable names for the fields (the field0, field1, field2) in a derive macro, and then use them.
This is what I'm up to so far :
// create the fields argument tokens (this is "field0, field1, field2")
let mut fields_name = TokenStream2::new();
// operation of fields (this is result.append(field0.Serialize(); [...])
let mut fields_serialization = TokenStream2::new();
// counter to create numbered names for fields
let mut counter = 0;
for _field in &fields.unnamed { // fields is of type &FieldsUnnamed here
if counter == 0 {
fields_name.extend(quote!{
format!("field{}", #counter)
})
}
else {
fields_name.extend(quote!{
, format!("field{}", #counter)
})
}
fields_serialization.extend(quote_spanned! {variant.span()=>
result.append(&mut format!("field{}", #counter).Serialize());
});
counter += 1;
}
quote_spanned! {variant.span()=>
#name::#variant_name (#fields_name) => {
let mut result = Vec::new();
#fields_serialization
result
},
}
I understand that with the format macro, I'll end up with a string token and it doesn't work. But I have no idea how to get all my enum variants fields and operate on them, as I found very little information about it online.
Upvotes: 2
Views: 995
Reputation: 15012
I'd recommend using .enumerate()
and utilizing the repetition features of quote:
let mut field_name: Vec<_> = fields.unnamed.iter().enumerate().map(|(i, _)| {
format_ident!("field{}", i)
}).collect();
quote_spanned! {variant.span()=>
#name::#variant_name (#(#field_name,)*) => {
let mut result = Vec::new();
#(
result.append(&mut #field_name.Serialize());
)*
result
},
}
BTW, in Rust, the standard style is for only types to be capitalized. All methods should be lower_snake_case
.
Upvotes: 1