update derive code to use synstructure/proc_macro2 and recent crate versions

This commit is contained in:
Stefan Bühler 2019-07-02 15:27:08 +02:00
parent 174314cbcb
commit 1c7e385937
8 changed files with 269 additions and 192 deletions

38
Cargo.lock generated
View File

@ -143,8 +143,10 @@ dependencies = [
name = "dnsbox-derive" name = "dnsbox-derive"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (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]] [[package]]
@ -344,11 +346,6 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "quote" name = "quote"
version = "0.6.12" version = "0.6.12"
@ -517,16 +514,6 @@ name = "stable_deref_trait"
version = "1.1.1" version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "syn" name = "syn"
version = "0.15.39" version = "0.15.39"
@ -537,14 +524,6 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "synstructure" name = "synstructure"
version = "0.10.2" version = "0.10.2"
@ -752,11 +731,6 @@ dependencies = [
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.1.0" 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 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 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 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 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 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" "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.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 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 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 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 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 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" "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-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-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 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 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.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" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"

View File

@ -5,6 +5,26 @@ use std::io::{Cursor, Read};
use std::mem::size_of; use std::mem::size_of;
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
impl DnsPacketData for () {
fn deserialize(_data: &mut Cursor<Bytes>) -> Result<Self> {
Ok(())
}
fn serialize(&self, _context: &mut DnsPacketWriteContext, _packet: &mut Vec<u8>) -> Result<()> {
Ok(())
}
}
impl<T: ?Sized> DnsPacketData for std::marker::PhantomData<T> {
fn deserialize(_data: &mut Cursor<Bytes>) -> Result<Self> {
Ok(std::marker::PhantomData)
}
fn serialize(&self, _context: &mut DnsPacketWriteContext, _packet: &mut Vec<u8>) -> Result<()> {
Ok(())
}
}
impl DnsPacketData for u8 { impl DnsPacketData for u8 {
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> { fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
check_enough_data!(data, size_of::<Self>(), "u8"); check_enough_data!(data, size_of::<Self>(), "u8");
@ -95,4 +115,20 @@ mod tests {
fn test_u16() { fn test_u16() {
assert!(deserialize::<u16>(b"\x80\x08").unwrap() == 0x8008); assert!(deserialize::<u16>(b"\x80\x08").unwrap() == 0x8008);
} }
#[derive(super::DnsPacketData, PartialEq, Eq, Debug)]
struct Unit;
#[test]
fn test_unit() {
assert_eq!(deserialize::<Unit>(b"").unwrap(), Unit);
}
#[derive(super::DnsPacketData, PartialEq, Eq, Debug)]
struct Tuple(u16);
#[test]
fn test_tuple() {
assert_eq!(deserialize::<Tuple>(b"\x04\xd2").unwrap(), Tuple(1234));
}
} }

View File

@ -2,6 +2,26 @@ use std::fmt;
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field}; use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
impl DnsTextData for () {
fn dns_parse(_context: &DnsTextContext, _data: &mut &str) -> crate::errors::Result<Self> {
Ok(())
}
fn dns_format(&self, _f: &mut DnsTextFormatter) -> fmt::Result {
Ok(())
}
}
impl<T: ?Sized> DnsTextData for std::marker::PhantomData<T> {
fn dns_parse(_context: &DnsTextContext, _data: &mut &str) -> crate::errors::Result<Self> {
Ok(std::marker::PhantomData)
}
fn dns_format(&self, _f: &mut DnsTextFormatter) -> fmt::Result {
Ok(())
}
}
/* only decimal representations are used for numbers */ /* only decimal representations are used for numbers */
impl DnsTextData for u8 { impl DnsTextData for u8 {
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result<Self> { fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result<Self> {
@ -98,4 +118,20 @@ mod tests {
) )
); );
} }
#[derive(DnsTextData, PartialEq, Eq, Debug)]
struct Unit;
#[test]
fn test_unit() {
assert_eq!(deserialize::<Unit>("").unwrap(), Unit);
}
#[derive(DnsTextData, PartialEq, Eq, Debug)]
struct Tuple(u16);
#[test]
fn test_tuple() {
assert_eq!(deserialize::<Tuple>("1234").unwrap(), Tuple(1234));
}
} }

View File

@ -8,5 +8,7 @@ edition = "2018"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
syn = "0.11" syn = "0.15.39"
quote = "0.3" quote = "0.6.12"
synstructure = "0.10.2"
proc-macro2 = "0.4.30"

View File

@ -1,59 +1,80 @@
use syn; use proc_macro2::TokenStream;
use quote;
pub fn build(ast: &syn::DeriveInput) -> quote::Tokens { fn derive_impl(s: &synstructure::Structure, parse_fields: TokenStream, serialize_fields: TokenStream) -> TokenStream {
let fields = match ast.body { s.gen_impl(quote!{
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"),
};
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)] #[allow(unused_imports)]
fn deserialize(_data: &mut ::std::io::Cursor<::dnsbox_base::_bytes::Bytes>) -> ::dnsbox_base::errors::Result<Self> {
use dnsbox_base::_failure::ResultExt; use dnsbox_base::_failure::ResultExt;
#[allow(unused_imports)]
use dnsbox_base::ser::packet::DnsPacketData; use dnsbox_base::ser::packet::DnsPacketData;
Ok(#name{ #parse_fields })
gen impl DnsPacketData for @Self {
fn deserialize(_data: &mut ::std::io::Cursor<::dnsbox_base::_bytes::Bytes>) -> ::dnsbox_base::errors::Result<Self> {
Ok(#parse_fields)
} }
#[allow(unused_imports)] #[allow(unused_imports)]
fn serialize(&self, _context: &mut ::dnsbox_base::ser::packet::DnsPacketWriteContext, _packet: &mut Vec<u8>) -> ::dnsbox_base::errors::Result<()> { fn serialize(&self, _context: &mut ::dnsbox_base::ser::packet::DnsPacketWriteContext, _packet: &mut Vec<u8>) -> ::dnsbox_base::errors::Result<()> {
use dnsbox_base::_failure::ResultExt;
use dnsbox_base::ser::packet::DnsPacketData;
#serialize_fields #serialize_fields
Ok(()) 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"),
} }
} }

View File

@ -1,56 +1,78 @@
use syn; use proc_macro2::TokenStream;
use quote;
pub fn build(ast: &syn::DeriveInput) -> quote::Tokens { fn derive_impl(s: &synstructure::Structure, parse_fields: TokenStream, format_fields: TokenStream) -> TokenStream {
let fields = match ast.body { s.gen_impl(quote!{
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!{
#[allow(unused_imports)] #[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<Self> { fn dns_parse(_context: &::dnsbox_base::ser::text::DnsTextContext, _data: &mut &str) -> ::dnsbox_base::errors::Result<Self> {
use dnsbox_base::_failure::ResultExt; Ok(#parse_fields)
use dnsbox_base::ser::text::DnsTextData;
Ok(#name{ #parse_fields })
} }
fn dns_format(&self, f: &mut ::dnsbox_base::ser::text::DnsTextFormatter) -> ::std::fmt::Result { 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}; use std::fmt::{self, Write};
#format_fields #format_fields
Ok(()) 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"),
} }
} }

View File

@ -1,34 +1,40 @@
#![recursion_limit="128"] #![recursion_limit="128"]
extern crate proc_macro; #[macro_use]
extern crate syn; extern crate synstructure;
#[macro_use] #[macro_use]
extern crate quote; extern crate quote;
extern crate proc_macro2;
use proc_macro::TokenStream; mod rrdata;
mod dns_packet_data; mod dns_packet_data;
mod dns_text_data; mod dns_text_data;
mod rrdata;
fn attr_get_single_list_arg(attr: &syn::Attribute) -> quote::Tokens { decl_derive!([DnsPacketData] => dns_packet_data::derive);
match attr.value { decl_derive!([DnsTextData] => dns_text_data::derive);
syn::MetaItem::List(_, ref l) => { decl_derive!([RRData, attributes(RRTypeName, RRClass)] => rrdata::rrdata_derive);
if l.len() != 1 {
panic!("{:?} attribute requires exactly one argument", attr.name());
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} quote!{#arg}
}, },
syn::MetaItem::NameValue(_, ref l) => { syn::Meta::NameValue(nv) => {
quote!{#l} let lit = &nv.lit;
}, quote!{#lit}
_ => {
panic!("{:?} argument requires one argument like: [#{}(...)]", attr.name(), attr.name());
}, },
} }
} }
/*
#[proc_macro_derive(DnsPacketData)] #[proc_macro_derive(DnsPacketData)]
pub fn derive_dns_packet_data(input: TokenStream) -> TokenStream { pub fn derive_dns_packet_data(input: TokenStream) -> TokenStream {
let s = input.to_string(); let s = input.to_string();
@ -51,13 +57,4 @@ pub fn derive_dns_text_data(input: TokenStream) -> TokenStream {
gen.parse().unwrap() 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()
}

View File

@ -1,12 +1,9 @@
use syn; use crate::attr_get_single_list_arg;
use quote;
use super::{attr_get_single_list_arg};
#[derive(Clone,Debug)] #[derive(Clone,Debug)]
enum StructAttribute { enum StructAttribute {
RRTypeName(quote::Tokens), RRTypeName(proc_macro2::TokenStream),
RRClass(quote::Tokens), RRClass(proc_macro2::TokenStream),
} }
struct StructAttributeParser<'a>(pub &'a [syn::Attribute]); struct StructAttributeParser<'a>(pub &'a [syn::Attribute]);
@ -17,76 +14,72 @@ impl<'a> Iterator for StructAttributeParser<'a> {
while !self.0.is_empty() { while !self.0.is_empty() {
let a = &self.0[0]; let a = &self.0[0];
self.0 = &self.0[1..]; self.0 = &self.0[1..];
if a.is_sugared_doc { continue; } let meta = match a.interpret_meta() {
match a.value.name() { Some(m) => m,
"RRTypeName" => { _ => continue,
return Some(StructAttribute::RRTypeName(attr_get_single_list_arg(a))); };
}, if meta.name() == "RRTypeName" {
"RRClass" => { return Some(StructAttribute::RRTypeName(attr_get_single_list_arg(&meta)));
return Some(StructAttribute::RRClass(attr_get_single_list_arg(a))); }
}, if meta.name() == "RRClass" {
_ => (), return Some(StructAttribute::RRClass(attr_get_single_list_arg(&meta)));
} }
} }
None None
} }
} }
pub fn build(ast: &syn::DeriveInput) -> quote::Tokens { pub fn rrdata_derive(s: synstructure::Structure) -> proc_macro2::TokenStream {
if !ast.generics.ty_params.is_empty() { let name = &s.ast().ident;
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 name_str = None;
let mut rr_class = None; let mut rr_class = None;
for attr in StructAttributeParser(&ast.attrs) { for attr in StructAttributeParser(&s.ast().attrs) {
match attr { match attr {
StructAttribute::RRTypeName(name) => { 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); name_str = Some(name);
}, },
StructAttribute::RRClass(c) => { 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); rr_class = Some(c);
}, },
} }
} }
let name_str = name_str.unwrap_or_else(|| { let name_str = name_str.unwrap_or_else(|| {
let name_str: &str = name.as_ref(); let name_str = format!("{}", name);
quote!{#name_str} quote!{#name_str}
}); });
let rr_class = rr_class.unwrap_or_else(|| quote!{ANY}); 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!{ let impl_rrdata = s.unbound_impl(
impl ::dnsbox_base::ser::RRData for #name { quote!(::dnsbox_base::ser::RRData),
quote! {
fn clone_box(&self) -> Box<::dnsbox_base::ser::RRData> { 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 { fn as_any(&self) -> &::std::any::Any {
self as _ 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 TYPE: ::dnsbox_base::common_types::Type = ::dnsbox_base::common_types::types::#name;
const NAME: &'static str = #name_str; const NAME: &'static str = #name_str;
const CLASS: ::dnsbox_base::common_types::Class = ::dnsbox_base::common_types::classes::#rr_class; const CLASS: ::dnsbox_base::common_types::Class = ::dnsbox_base::common_types::classes::#rr_class;
} },
);
quote! {
#impl_rrdata
#impl_static_rrdata
// #[cfg(test)] // #[cfg(test)]
#[allow(non_snake_case, unused_imports)] #[allow(non_snake_case, unused_imports)]