update derive code to use synstructure/proc_macro2 and recent crate versions
This commit is contained in:
parent
174314cbcb
commit
1c7e385937
38
Cargo.lock
generated
38
Cargo.lock
generated
@ -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"
|
||||
|
@ -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<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 {
|
||||
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
||||
check_enough_data!(data, size_of::<Self>(), "u8");
|
||||
@ -95,4 +115,20 @@ mod tests {
|
||||
fn test_u16() {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -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<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 */
|
||||
impl DnsTextData for u8 {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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"),
|
||||
};
|
||||
|
||||
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 {
|
||||
fn derive_impl(s: &synstructure::Structure, parse_fields: TokenStream, serialize_fields: TokenStream) -> TokenStream {
|
||||
s.gen_impl(quote!{
|
||||
#[allow(unused_imports)]
|
||||
fn deserialize(_data: &mut ::std::io::Cursor<::dnsbox_base::_bytes::Bytes>) -> ::dnsbox_base::errors::Result<Self> {
|
||||
use dnsbox_base::_failure::ResultExt;
|
||||
#[allow(unused_imports)]
|
||||
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)]
|
||||
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
|
||||
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"),
|
||||
}
|
||||
}
|
||||
|
@ -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<Self> {
|
||||
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"),
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
*/
|
@ -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());
|
||||
|
||||
let impl_rrdata = s.unbound_impl(
|
||||
quote!(::dnsbox_base::ser::RRData),
|
||||
quote! {
|
||||
impl ::dnsbox_base::ser::RRData for #name {
|
||||
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)]
|
||||
|
Loading…
Reference in New Issue
Block a user