我正在为结构编写宏并实现基于字段类型的方法。例如u8
,Array
或str
。
假设我将此枚举表示为u32
。
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ServerGreetingMode {
Unavailable = 0,
Unauthenticated = 1,
Authenticated = 2,
Encrypted = 4,
}
我ToBytes
在结构字段上应用宏
#[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],
}
我能够将它放到我获得类型的部分,ServerGreetingMode
但我无法判断它是否是枚举。
这是我目前的实现。
#[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()
}
谢谢。