rust-dnsbox/lib/dnsbox-derive/src/dns_text_data.rs

79 lines
2.5 KiB
Rust

use proc_macro2::TokenStream;
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 _;
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!{})
}
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"),
}
}