use proc_macro2::TokenStream; fn derive_impl(s: &synstructure::Structure, parse_fields: TokenStream, serialize_fields: TokenStream) -> TokenStream { s.gen_impl(quote!{ #[allow(unused_imports)] use dnsbox_base::_failure::ResultExt; #[allow(unused_imports)] use dnsbox_base::ser::packet::DnsPacketData; gen impl DnsPacketData for @Self { fn deserialize(_data: &mut ::std::io::Cursor<::dnsbox_base::_bytes::Bytes>) -> ::dnsbox_base::errors::Result { Ok(#parse_fields) } #[allow(unused_imports)] fn serialize(&self, _context: &mut ::dnsbox_base::ser::packet::DnsPacketWriteContext, _packet: &mut Vec) -> ::dnsbox_base::errors::Result<()> { #serialize_fields Ok(()) } } }) } fn derive_unit(s: &synstructure::Structure) -> TokenStream { let name = &s.ast().ident; derive_impl(s, quote!{#name}, quote!{}) } fn derive_named(s: &synstructure::Structure, fields: &syn::FieldsNamed) -> TokenStream { let name = &s.ast().ident; let mut parse_fields = quote!{}; let mut serialize_fields = quote!{}; for field in &fields.named { let field_name = field.ident.as_ref().unwrap(); parse_fields.extend(quote!{ #field_name: DnsPacketData::deserialize(_data) .with_context(|e| format!("failed parsing field {}::{}: {}", stringify!(#name), stringify!(#field_name), e))?, }); serialize_fields.extend(quote!{ self.#field_name.serialize(_context, _packet) .with_context(|e| format!("failed serializing field {}::{}: {}", stringify!(#name), stringify!(#field_name), e))?; }); } derive_impl(s, quote!{#name{ #parse_fields }}, serialize_fields) } fn derive_unnamed(s: &synstructure::Structure, fields: &syn::FieldsUnnamed) -> TokenStream { let name = &s.ast().ident; let mut parse_fields = quote!{}; let mut serialize_fields = quote!{}; for field in 0..fields.unnamed.len() { let field = syn::Index::from(field); parse_fields.extend(quote!{ DnsPacketData::deserialize(_data) .with_context(|e| format!("failed parsing field {}::{}: {}", stringify!(#name), #field, e))?, }); serialize_fields.extend(quote!{ self.#field.serialize(_context, _packet) .with_context(|e| format!("failed serializing field {}::{}: {}", stringify!(#name), #field, e))?; }); } derive_impl(s, quote!{#name(#parse_fields)}, serialize_fields) } pub fn derive(s: synstructure::Structure) -> TokenStream { let ast = s.ast(); match &ast.data { syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Unit, .. }) => derive_unit(&s), syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Named(fields), .. }) => derive_named(&s, fields), syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Unnamed(fields), .. }) => derive_unnamed(&s, fields), _ => panic!("Deriving DnsPacketData not supported for non struct types"), } }