I am writing a macro for a struct and implementing a method based on the field type. e.g. u8
, Array
or str
.
let us say I have this enum represented as u32
.
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ServerGreetingMode {
Unavailable = 0,
Unauthenticated = 1,
Authenticated = 2,
Encrypted = 4,
}
And I am applying a macro ToBytes
on a struct field
#[repr(packed)]
#[derive(ToBytes, Debug, Clone, Copy)]
pub struct ServerGreetingFrame {
pub unused: [u8; 12],
pub mode: ServerGreetingMode,
pub challenge: [u8; 16],
pub salt: [u8; 16],
pub count: u32,
pub mbz: [u8; 12],
}
I am able to get it to a part where I am getting the type as ServerGreetingMode
but I am unable to tell if it is an enum or not.
Here is my current implementation.
#[proc_macro_derive(ToBytes)]
pub fn derive(tokens: TokenStream) -> TokenStream {
let tokens_item = tokens.clone();
let items = syn::parse_macro_input!(tokens_item as syn::Item);
let output = match items {
syn::Item::Struct(item) => {
let name = &item.ident;
let statements = match &item.fields {
syn::Fields::Named(ref fields) => {
// eprint!("{:#?}", field);
let vary_by_type = fields.named.iter().map(|field| {
let field_name = &field.ident;
let field_type = &field.ty;
let statement = match field_type {
syn::Type::Array(syn::TypeArray { elem, .. }) => {
let ty = elem.as_ref();
match ty {
syn::Type::Path(typepath)
if typepath.qself.is_none()
&& typepath.path.leading_colon.is_none()
&& typepath.path.segments.len() == 1 && typepath.path.is_ident("u8") =>
{
quote! {
bytes.extend_from_slice(&self.#field_name);
}
},
_ => todo!(),
}
}
syn::Type::Path(ty) if ty.path.clone().is_ident("u32") => {
quote! {
bytes.extend_from_slice(&(self.#field_name as u32).to_be_bytes().to_vec());
}
},
_ => todo!(),
};
statement
});
vary_by_type
}
_ => todo!(),
};
quote! {
impl #name {
fn to_bytes(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::new();
#(
#statements
)*
bytes
}
}
}
}
_ => todo!(),
};
output.into()
// let s = syn::parse_macro_input!(tokens_struct as syn::ItemStruct);
// let n = &s.ident;
// let expanded = quote! {
// impl #n {
// fn to_bytes(&self) -> Vec<u8> {
// let mut bytes: Vec<u8> = Vec::new();
// bytes
// }
// }
// };
// expanded.into()
}
Thanks.