首页 > 解决方案 > 使用 syn 获取 proc_macro_derive 结构的枚举字段的属性

问题描述

我正在为结构编写宏并实现基于字段类型的方法。例如u8Arraystr

假设我将此枚举表示为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()
}

谢谢。

标签: rustrust-proc-macrossyn

解决方案


推荐阅读