use crate::attr_get_single_list_arg; #[derive(Clone, Debug)] enum StructAttribute { RRTypeName(proc_macro2::TokenStream), RRClass(proc_macro2::TokenStream), } struct StructAttributeParser<'a>(pub &'a [syn::Attribute]); impl<'a> Iterator for StructAttributeParser<'a> { type Item = StructAttribute; fn next(&mut self) -> Option { while !self.0.is_empty() { let a = &self.0[0]; self.0 = &self.0[1..]; let meta = match a.interpret_meta() { Some(m) => m, _ => continue, }; if meta.name() == "RRTypeName" { return Some(StructAttribute::RRTypeName(attr_get_single_list_arg(&meta))); } if meta.name() == "RRClass" { return Some(StructAttribute::RRClass(attr_get_single_list_arg(&meta))); } } None } } pub fn rrdata_derive(s: synstructure::Structure) -> proc_macro2::TokenStream { let name = &s.ast().ident; let mut name_str = None; let mut rr_class = None; for attr in StructAttributeParser(&s.ast().attrs) { match attr { StructAttribute::RRTypeName(name) => { assert!(name_str.is_none(), "only one RRTypeName attribute allowed"); name_str = Some(name); }, StructAttribute::RRClass(c) => { assert!(rr_class.is_none(), "only one RRTypeName attribute allowed"); rr_class = Some(c); }, } } let name_str = name_str.unwrap_or_else(|| { let name_str = format!("{}", name); quote! {#name_str} }); let rr_class = rr_class.unwrap_or_else(|| quote! {ANY}); let test_mod_name = syn::Ident::new(&format!("test_rr_{}", name), proc_macro2::Span::call_site()); let impl_rrdata = s.unbound_impl( quote!(::dnsbox_base::ser::RRData), quote! { fn clone_box(&self) -> Box<::dnsbox_base::ser::RRData> { Box::new(self.clone() as Self) as _ } fn as_any(&self) -> &::std::any::Any { self as _ } fn as_box_any(self: Box) -> Box { self as _ } }, ); let impl_static_rrdata = s.unbound_impl( quote!(::dnsbox_base::ser::StaticRRData), quote! { const TYPE: ::dnsbox_base::common_types::Type = ::dnsbox_base::common_types::types::#name; const NAME: &'static str = #name_str; const CLASS: ::dnsbox_base::common_types::Class = ::dnsbox_base::common_types::classes::#rr_class; }, ); quote! { #impl_rrdata #impl_static_rrdata // #[cfg(test)] #[allow(non_snake_case, unused_imports)] mod #test_mod_name { use dnsbox_base::records::registry; use dnsbox_base::common_types::types; use dnsbox_base::ser::StaticRRData; #[test] fn test_registry() { registry::check_registration::(); } } } }