use syn; use quote; use super::{attr_get_single_list_arg}; #[derive(Clone,Debug)] enum StructAttribute { RRTypeName(quote::Tokens), RRClass(quote::Tokens), } 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..]; if a.is_sugared_doc { continue; } match a.value.name() { "RRTypeName" => { return Some(StructAttribute::RRTypeName(attr_get_single_list_arg(a))); }, "RRClass" => { return Some(StructAttribute::RRClass(attr_get_single_list_arg(a))); }, _ => (), } } None } } pub fn build(ast: &syn::DeriveInput) -> quote::Tokens { if !ast.generics.ty_params.is_empty() { panic!("Type parameters not supported for deriving RRData"); } if !ast.generics.where_clause.predicates.is_empty() { panic!("Where clauses not supported for deriving RRData"); } if !ast.generics.lifetimes.is_empty() { panic!("Lifetimes not supported for deriving RRData"); } let name = &ast.ident; let mut name_str = None; let mut rr_class = None; for attr in StructAttributeParser(&ast.attrs) { match attr { StructAttribute::RRTypeName(name) => { assert_eq!(name_str, None, "only one RRTypeName attribute allowed"); name_str = Some(name); }, StructAttribute::RRClass(c) => { assert_eq!(rr_class, None, "only one RRTypeName attribute allowed"); rr_class = Some(c); }, } } let name_str = name_str.unwrap_or_else(|| { let name_str: &str = name.as_ref(); quote!{#name_str} }); let rr_class = rr_class.unwrap_or_else(|| quote!{ANY}); let test_mod_name = syn::Ident::from(format!("test_rr_{}", name)); quote!{ impl ::dnsbox_base::ser::RRData for #name { fn clone_box(&self) -> Box<::dnsbox_base::ser::RRData> { Box::new(self.clone() as #name) as _ } fn as_any(&self) -> &::std::any::Any { self as _ } } impl ::dnsbox_base::ser::StaticRRData for #name { 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; } // #[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::(); } } } }