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

89 lines
2.2 KiB
Rust
Raw Normal View History

use proc_macro2::TokenStream;
pub fn attribute_native_enum(
native_type: TokenStream,
structure: synstructure::Structure,
) -> TokenStream {
let ast = structure.ast();
let in_attrs = ast.attrs.iter().map(|a| quote!{#a}).collect::<TokenStream>();
let in_vis = &ast.vis;
let name = &ast.ident;
let known_name = syn::Ident::new(&format!("{}Known", name), proc_macro2::Span::call_site());
let enumdata = match &ast.data {
syn::Data::Enum(de) => de,
_ => panic!("not an enum"),
};
let known_enum;
{
let variants = &enumdata.variants;
let doc_str = format!("Known enum variants of [`{}`]\n\n[`{}`]: struct.{}.html\n", name, name, name);
known_enum = quote! {
#[doc = #doc_str]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(#native_type)]
#[allow(non_camel_case_types)]
#in_vis enum #known_name {
#variants
}
}
}
let mut consts = TokenStream::new();
let mut convert = TokenStream::new();
for variant in &enumdata.variants {
let variant_attrs = variant.attrs.iter().map(|a| quote!{#a}).collect::<TokenStream>();
let disc_name = &variant.ident;
let disc = variant.discriminant.as_ref().map(|(_, d)| quote!{#d}).unwrap_or_else(|| quote!{
#known_name::#disc_name as #native_type
});
consts.extend(quote! {
#variant_attrs
pub const #disc_name: Self = #name(#disc);
});
convert.extend(quote! {
Self::#disc_name => #known_name::#disc_name,
});
}
quote! {
#known_enum
#in_attrs
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#in_vis struct #name(pub #native_type);
impl #name {
#consts
/// Try converting to known enum values
pub fn into_known(self) -> Option<#known_name> {
Some(
#[allow(unreachable_patterns)]
match self {
#convert
_ => return None,
}
)
}
}
impl core::fmt::Debug for #name {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self.into_known() {
Some(v) => v.fmt(f),
None => f.debug_tuple(stringify!(#name)).field(&self.0).finish(),
}
}
}
impl From<#known_name> for #name {
fn from(v: #known_name) -> Self {
#name(v as #native_type)
}
}
}
}