parent
174314cbcb
commit
1c7e385937
@ -1,59 +1,80 @@
|
||||
use syn;
|
||||
use quote;
|
||||
|
||||
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");
|
||||
}
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
if !ast.generics.where_clause.predicates.is_empty() {
|
||||
panic!("Where clauses not supported for deriving DnsPacketData");
|
||||
}
|
||||
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.lifetimes.is_empty() {
|
||||
panic!("Lifetimes not supported for deriving DnsPacketData");
|
||||
}
|
||||
gen impl DnsPacketData for @Self {
|
||||
fn deserialize(_data: &mut ::std::io::Cursor<::dnsbox_base::_bytes::Bytes>) -> ::dnsbox_base::errors::Result<Self> {
|
||||
Ok(#parse_fields)
|
||||
}
|
||||
|
||||
let name = &ast.ident;
|
||||
#[allow(unused_imports)]
|
||||
fn serialize(&self, _context: &mut ::dnsbox_base::ser::packet::DnsPacketWriteContext, _packet: &mut Vec<u8>) -> ::dnsbox_base::errors::Result<()> {
|
||||
#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 {
|
||||
for field in &fields.named {
|
||||
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)?,
|
||||
};
|
||||
parse_fields.extend(quote!{
|
||||
#field_name: DnsPacketData::deserialize(_data)
|
||||
.with_context(|e| format!("failed parsing field {}::{}: {}", stringify!(#name), stringify!(#field_name), e))?,
|
||||
});
|
||||
|
||||
serialize_fields = quote!{#serialize_fields
|
||||
self.#field_name.serialize(_context, _packet).context(#serialize_ctx_msg)?;
|
||||
};
|
||||
serialize_fields.extend(quote!{
|
||||
self.#field_name.serialize(_context, _packet)
|
||||
.with_context(|e| format!("failed serializing field {}::{}: {}", stringify!(#name), stringify!(#field_name), e))?;
|
||||
});
|
||||
}
|
||||
|
||||
quote!{
|
||||
impl ::dnsbox_base::ser::packet::DnsPacketData for #name {
|
||||
#[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::ser::packet::DnsPacketData;
|
||||
Ok(#name{ #parse_fields })
|
||||
}
|
||||
derive_impl(s, quote!{#name{ #parse_fields }}, serialize_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_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;
|
||||
|
||||
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");
|
||||
}
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
if !ast.generics.where_clause.predicates.is_empty() {
|
||||
panic!("Where clauses not supported for deriving DnsTextData");
|
||||
}
|
||||
fn derive_impl(s: &synstructure::Structure, parse_fields: TokenStream, format_fields: TokenStream) -> TokenStream {
|
||||
s.gen_impl(quote!{
|
||||
#[allow(unused_imports)]
|
||||
use dnsbox_base::_failure::ResultExt as _;
|
||||
#[allow(unused_imports)]
|
||||
use dnsbox_base::ser::text::DnsTextData as _;
|
||||
|
||||
if !ast.generics.lifetimes.is_empty() {
|
||||
panic!("Lifetimes not supported for deriving DnsTextData");
|
||||
}
|
||||
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> {
|
||||
Ok(#parse_fields)
|
||||
}
|
||||
|
||||
fn dns_format(&self, f: &mut ::dnsbox_base::ser::text::DnsTextFormatter) -> ::std::fmt::Result {
|
||||
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!{})
|
||||
}
|
||||
|
||||
let name = &ast.ident;
|
||||
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 {
|
||||
for field in &fields.named {
|
||||
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)))?,
|
||||
};
|
||||
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 = quote!{#format_fields
|
||||
format_fields.extend(quote!{
|
||||
DnsTextData::dns_format(&self.#field_name, f)?;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
quote!{
|
||||
#[allow(unused_imports)]
|
||||
impl ::dnsbox_base::ser::text::DnsTextData for #name {
|
||||
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 })
|
||||
}
|
||||
derive_impl(s, quote!{#name{ #parse_fields }}, format_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_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"),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue