From 1c7e385937125196a4d514ec4f8c1fe9dbfbd49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Tue, 2 Jul 2019 15:27:08 +0200 Subject: [PATCH] update derive code to use synstructure/proc_macro2 and recent crate versions --- Cargo.lock | 38 +------ lib/dnsbox-base/src/ser/packet/std_impls.rs | 36 +++++++ lib/dnsbox-base/src/ser/text/std_impls.rs | 36 +++++++ lib/dnsbox-derive/Cargo.toml | 6 +- lib/dnsbox-derive/src/dns_packet_data.rs | 113 ++++++++++++-------- lib/dnsbox-derive/src/dns_text_data.rs | 108 +++++++++++-------- lib/dnsbox-derive/src/lib.rs | 49 ++++----- lib/dnsbox-derive/src/rrdata.rs | 75 ++++++------- 8 files changed, 269 insertions(+), 192 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f14487..04801c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,8 +143,10 @@ dependencies = [ name = "dnsbox-derive" version = "0.1.0" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -344,11 +346,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "quote" version = "0.6.12" @@ -517,16 +514,6 @@ name = "stable_deref_trait" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.15.39" @@ -537,14 +524,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "synstructure" version = "0.10.2" @@ -752,11 +731,6 @@ dependencies = [ "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.1.0" @@ -840,7 +814,6 @@ dependencies = [ "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -863,9 +836,7 @@ dependencies = [ "checksum smallvec 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f90c5e5fe535e48807ab94fc611d323935f39d4660c52b26b96446a7b33aef10" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2ffcf4bcfc641413fa0f1427bf8f91dfc78f56a6559cbf50e04837ae442a87" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" @@ -882,7 +853,6 @@ dependencies = [ "checksum tokio-trace-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9c8a256d6956f7cb5e2bdfe8b1e8022f1a09206c6c2b1ba00f3b746b260c613" "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" diff --git a/lib/dnsbox-base/src/ser/packet/std_impls.rs b/lib/dnsbox-base/src/ser/packet/std_impls.rs index f17f4bc..1a143fe 100644 --- a/lib/dnsbox-base/src/ser/packet/std_impls.rs +++ b/lib/dnsbox-base/src/ser/packet/std_impls.rs @@ -5,6 +5,26 @@ use std::io::{Cursor, Read}; use std::mem::size_of; use std::net::{Ipv4Addr, Ipv6Addr}; +impl DnsPacketData for () { + fn deserialize(_data: &mut Cursor) -> Result { + Ok(()) + } + + fn serialize(&self, _context: &mut DnsPacketWriteContext, _packet: &mut Vec) -> Result<()> { + Ok(()) + } +} + +impl DnsPacketData for std::marker::PhantomData { + fn deserialize(_data: &mut Cursor) -> Result { + Ok(std::marker::PhantomData) + } + + fn serialize(&self, _context: &mut DnsPacketWriteContext, _packet: &mut Vec) -> Result<()> { + Ok(()) + } +} + impl DnsPacketData for u8 { fn deserialize(data: &mut Cursor) -> Result { check_enough_data!(data, size_of::(), "u8"); @@ -95,4 +115,20 @@ mod tests { fn test_u16() { assert!(deserialize::(b"\x80\x08").unwrap() == 0x8008); } + + #[derive(super::DnsPacketData, PartialEq, Eq, Debug)] + struct Unit; + + #[test] + fn test_unit() { + assert_eq!(deserialize::(b"").unwrap(), Unit); + } + + #[derive(super::DnsPacketData, PartialEq, Eq, Debug)] + struct Tuple(u16); + + #[test] + fn test_tuple() { + assert_eq!(deserialize::(b"\x04\xd2").unwrap(), Tuple(1234)); + } } diff --git a/lib/dnsbox-base/src/ser/text/std_impls.rs b/lib/dnsbox-base/src/ser/text/std_impls.rs index 2a380b3..9ffdd38 100644 --- a/lib/dnsbox-base/src/ser/text/std_impls.rs +++ b/lib/dnsbox-base/src/ser/text/std_impls.rs @@ -2,6 +2,26 @@ use std::fmt; use std::net::{Ipv4Addr, Ipv6Addr}; use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field}; +impl DnsTextData for () { + fn dns_parse(_context: &DnsTextContext, _data: &mut &str) -> crate::errors::Result { + Ok(()) + } + + fn dns_format(&self, _f: &mut DnsTextFormatter) -> fmt::Result { + Ok(()) + } +} + +impl DnsTextData for std::marker::PhantomData { + fn dns_parse(_context: &DnsTextContext, _data: &mut &str) -> crate::errors::Result { + Ok(std::marker::PhantomData) + } + + fn dns_format(&self, _f: &mut DnsTextFormatter) -> fmt::Result { + Ok(()) + } +} + /* only decimal representations are used for numbers */ impl DnsTextData for u8 { fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result { @@ -98,4 +118,20 @@ mod tests { ) ); } + + #[derive(DnsTextData, PartialEq, Eq, Debug)] + struct Unit; + + #[test] + fn test_unit() { + assert_eq!(deserialize::("").unwrap(), Unit); + } + + #[derive(DnsTextData, PartialEq, Eq, Debug)] + struct Tuple(u16); + + #[test] + fn test_tuple() { + assert_eq!(deserialize::("1234").unwrap(), Tuple(1234)); + } } diff --git a/lib/dnsbox-derive/Cargo.toml b/lib/dnsbox-derive/Cargo.toml index ee9b1d0..ee89b12 100644 --- a/lib/dnsbox-derive/Cargo.toml +++ b/lib/dnsbox-derive/Cargo.toml @@ -8,5 +8,7 @@ edition = "2018" proc-macro = true [dependencies] -syn = "0.11" -quote = "0.3" +syn = "0.15.39" +quote = "0.6.12" +synstructure = "0.10.2" +proc-macro2 = "0.4.30" diff --git a/lib/dnsbox-derive/src/dns_packet_data.rs b/lib/dnsbox-derive/src/dns_packet_data.rs index 1654937..dcd07cf 100644 --- a/lib/dnsbox-derive/src/dns_packet_data.rs +++ b/lib/dnsbox-derive/src/dns_packet_data.rs @@ -1,59 +1,80 @@ -use syn; -use quote; +use proc_macro2::TokenStream; -pub fn build(ast: &syn::DeriveInput) -> quote::Tokens { - let fields = match ast.body { - syn::Body::Enum(_) => panic!("Deriving DnsPacketData not supported for enum types"), - syn::Body::Struct(syn::VariantData::Struct(ref s)) => s, - syn::Body::Struct(_) => panic!("Deriving DnsPacketData not supported for unit / tuple struct types"), - }; +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; - if !ast.generics.ty_params.is_empty() { - panic!("Type parameters not supported for deriving DnsPacketData"); - } - - if !ast.generics.where_clause.predicates.is_empty() { - panic!("Where clauses not supported for deriving DnsPacketData"); - } - - if !ast.generics.lifetimes.is_empty() { - panic!("Lifetimes not supported for deriving DnsPacketData"); - } - - let name = &ast.ident; - - let mut parse_fields = quote!{}; - let mut serialize_fields = quote!{}; - for field in fields { - let field_name = field.ident.as_ref().unwrap(); - let parse_ctx_msg = format!("failed parsing field {}::{}", name, field_name); - let serialize_ctx_msg = format!("failed serializing field {}::{}", name, field_name); - - parse_fields = quote!{#parse_fields - #field_name: DnsPacketData::deserialize(_data).context(#parse_ctx_msg)?, - }; - - serialize_fields = quote!{#serialize_fields - self.#field_name.serialize(_context, _packet).context(#serialize_ctx_msg)?; - }; - } - - quote!{ - impl ::dnsbox_base::ser::packet::DnsPacketData for #name { - #[allow(unused_imports)] + gen impl DnsPacketData for @Self { fn deserialize(_data: &mut ::std::io::Cursor<::dnsbox_base::_bytes::Bytes>) -> ::dnsbox_base::errors::Result { - use dnsbox_base::_failure::ResultExt; - use dnsbox_base::ser::packet::DnsPacketData; - Ok(#name{ #parse_fields }) + Ok(#parse_fields) } #[allow(unused_imports)] fn serialize(&self, _context: &mut ::dnsbox_base::ser::packet::DnsPacketWriteContext, _packet: &mut Vec) -> ::dnsbox_base::errors::Result<()> { - use dnsbox_base::_failure::ResultExt; - use dnsbox_base::ser::packet::DnsPacketData; #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() { + 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"), } } diff --git a/lib/dnsbox-derive/src/dns_text_data.rs b/lib/dnsbox-derive/src/dns_text_data.rs index f99f280..dad620a 100644 --- a/lib/dnsbox-derive/src/dns_text_data.rs +++ b/lib/dnsbox-derive/src/dns_text_data.rs @@ -1,56 +1,78 @@ -use syn; -use quote; +use proc_macro2::TokenStream; -pub fn build(ast: &syn::DeriveInput) -> quote::Tokens { - let fields = match ast.body { - syn::Body::Enum(_) => panic!("Deriving DnsTextData not supported for enum types"), - syn::Body::Struct(syn::VariantData::Struct(ref s)) => s, - syn::Body::Struct(_) => panic!("Deriving DnsTextData not supported for unit / tuple struct types"), - }; - - if !ast.generics.ty_params.is_empty() { - panic!("Type parameters not supported for deriving DnsTextData"); - } - - if !ast.generics.where_clause.predicates.is_empty() { - panic!("Where clauses not supported for deriving DnsTextData"); - } - - if !ast.generics.lifetimes.is_empty() { - panic!("Lifetimes not supported for deriving DnsTextData"); - } - - let name = &ast.ident; - - let mut parse_fields = quote!{}; - let mut format_fields = quote!{}; - for field in fields { - let field_name = field.ident.as_ref().unwrap(); - - parse_fields = quote!{#parse_fields - #field_name: DnsTextData::dns_parse(_context, _data).with_context(|_| format!("failed parsing field {}::{}", stringify!(#name), stringify!(#field_name)))?, - }; - - format_fields = quote!{#format_fields - DnsTextData::dns_format(&self.#field_name, f)?; - }; - } - - quote!{ +fn derive_impl(s: &synstructure::Structure, parse_fields: TokenStream, format_fields: TokenStream) -> TokenStream { + s.gen_impl(quote!{ #[allow(unused_imports)] - impl ::dnsbox_base::ser::text::DnsTextData for #name { + use dnsbox_base::_failure::ResultExt as _; + #[allow(unused_imports)] + use dnsbox_base::ser::text::DnsTextData as _; + + gen impl ::dnsbox_base::ser::text::DnsTextData for @Self { fn dns_parse(_context: &::dnsbox_base::ser::text::DnsTextContext, _data: &mut &str) -> ::dnsbox_base::errors::Result { - use dnsbox_base::_failure::ResultExt; - use dnsbox_base::ser::text::DnsTextData; - Ok(#name{ #parse_fields }) + Ok(#parse_fields) } fn dns_format(&self, f: &mut ::dnsbox_base::ser::text::DnsTextFormatter) -> ::std::fmt::Result { - use dnsbox_base::ser::text::DnsTextData; use std::fmt::{self, Write}; #format_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 format_fields = quote!{}; + for field in &fields.named { + let field_name = field.ident.as_ref().unwrap(); + + parse_fields.extend(quote!{ + #field_name: DnsTextData::dns_parse(_context, _data) + .with_context(|e| format!("failed parsing field {}::{}: {}", stringify!(#name), stringify!(#field_name), e))?, + }); + + format_fields.extend(quote!{ + DnsTextData::dns_format(&self.#field_name, f)?; + }); + } + + derive_impl(s, quote!{#name{ #parse_fields }}, format_fields) +} + +fn derive_unnamed(s: &synstructure::Structure, fields: &syn::FieldsUnnamed) -> TokenStream { + let name = &s.ast().ident; + + let mut parse_fields = quote!{}; + let mut format_fields = quote!{}; + for field in 0..fields.unnamed.len() { + parse_fields.extend(quote!{ + DnsTextData::dns_parse(_context, _data) + .with_context(|e| format!("failed parsing field {}::{}: {}", stringify!(#name), #field, e))?, + }); + + format_fields.extend(quote!{ + DnsTextData::dns_format(&self.#field, f)?; + }); + } + + derive_impl(s, quote!{#name(#parse_fields)}, format_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 DnsTextData not supported for non struct types"), } } diff --git a/lib/dnsbox-derive/src/lib.rs b/lib/dnsbox-derive/src/lib.rs index f0f82c3..8d674f5 100644 --- a/lib/dnsbox-derive/src/lib.rs +++ b/lib/dnsbox-derive/src/lib.rs @@ -1,34 +1,40 @@ #![recursion_limit="128"] -extern crate proc_macro; -extern crate syn; +#[macro_use] +extern crate synstructure; #[macro_use] extern crate quote; +extern crate proc_macro2; -use proc_macro::TokenStream; - +mod rrdata; mod dns_packet_data; mod dns_text_data; -mod rrdata; -fn attr_get_single_list_arg(attr: &syn::Attribute) -> quote::Tokens { - match attr.value { - syn::MetaItem::List(_, ref l) => { - if l.len() != 1 { - panic!("{:?} attribute requires exactly one argument", attr.name()); +decl_derive!([DnsPacketData] => dns_packet_data::derive); +decl_derive!([DnsTextData] => dns_text_data::derive); +decl_derive!([RRData, attributes(RRTypeName, RRClass)] => rrdata::rrdata_derive); + + +fn attr_get_single_list_arg(attr_meta: &syn::Meta) -> proc_macro2::TokenStream { + match attr_meta { + syn::Meta::Word(_) => { + panic!("{:?} attribute requires an argument", attr_meta.name()) + }, + syn::Meta::List(l) => { + if l.nested.len() != 1 { + panic!("{:?} attribute requires exactly one argument", attr_meta.name()); } - let arg = &l[0]; + let arg = *l.nested.first().unwrap().value(); quote!{#arg} }, - syn::MetaItem::NameValue(_, ref l) => { - quote!{#l} - }, - _ => { - panic!("{:?} argument requires one argument like: [#{}(...)]", attr.name(), attr.name()); + syn::Meta::NameValue(nv) => { + let lit = &nv.lit; + quote!{#lit} }, } } +/* #[proc_macro_derive(DnsPacketData)] pub fn derive_dns_packet_data(input: TokenStream) -> TokenStream { let s = input.to_string(); @@ -51,13 +57,4 @@ pub fn derive_dns_text_data(input: TokenStream) -> TokenStream { gen.parse().unwrap() } -#[proc_macro_derive(RRData, attributes(RRTypeName, RRClass))] -pub fn derive_rr_data(input: TokenStream) -> TokenStream { - let s = input.to_string(); - - let ast = syn::parse_derive_input(&s).unwrap(); - - let gen = rrdata::build(&ast); - - gen.parse().unwrap() -} +*/ \ No newline at end of file diff --git a/lib/dnsbox-derive/src/rrdata.rs b/lib/dnsbox-derive/src/rrdata.rs index da27917..dd655f9 100644 --- a/lib/dnsbox-derive/src/rrdata.rs +++ b/lib/dnsbox-derive/src/rrdata.rs @@ -1,12 +1,9 @@ -use syn; -use quote; - -use super::{attr_get_single_list_arg}; +use crate::attr_get_single_list_arg; #[derive(Clone,Debug)] enum StructAttribute { - RRTypeName(quote::Tokens), - RRClass(quote::Tokens), + RRTypeName(proc_macro2::TokenStream), + RRClass(proc_macro2::TokenStream), } struct StructAttributeParser<'a>(pub &'a [syn::Attribute]); @@ -17,76 +14,72 @@ impl<'a> Iterator for StructAttributeParser<'a> { 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))); - }, - _ => (), + 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 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; - +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(&ast.attrs) { + for attr in StructAttributeParser(&s.ast().attrs) { match attr { StructAttribute::RRTypeName(name) => { - assert_eq!(name_str, None, "only one RRTypeName attribute allowed"); + assert!(name_str.is_none(), "only one RRTypeName attribute allowed"); name_str = Some(name); }, StructAttribute::RRClass(c) => { - assert_eq!(rr_class, None, "only one RRTypeName attribute allowed"); + 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: &str = name.as_ref(); + let name_str = format!("{}", name); quote!{#name_str} }); let rr_class = rr_class.unwrap_or_else(|| quote!{ANY}); - let test_mod_name = syn::Ident::from(format!("test_rr_{}", name)); + let test_mod_name = syn::Ident::new(&format!("test_rr_{}", name), proc_macro2::Span::call_site()); - quote!{ - impl ::dnsbox_base::ser::RRData for #name { + 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 #name) as _ + Box::new(self.clone() as Self) as _ } fn as_any(&self) -> &::std::any::Any { self as _ } - } + }, + ); - impl ::dnsbox_base::ser::StaticRRData for #name { + 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)]