pleme-kindstr-derive 0.1.0

Paired round-trip derive proc-macro emitted from a tatara-rust-derive KindRoundTripSpec.
Documentation
//!GENERATED by tatara-rust-derive::KindRoundTripSpec.
//!Do not hand-edit; regenerate from the (defkind-round-trip …) source.
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Fields, LitStr};
#[proc_macro_derive(KindStr, attributes(kind))]
pub fn derive_kind_str(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let self_name = &input.ident;
    let de = match &input.data {
        Data::Enum(DataEnum { variants, .. }) => variants,
        _ => {
            return syn::Error::new_spanned(self_name, "KindStr requires an enum")
                .to_compile_error()
                .into();
        }
    };
    let mut as_str_arms = Vec::new();
    let mut from_str_arms = Vec::new();
    let mut errors = Vec::new();
    for v in de.iter() {
        let variant_name = &v.ident;
        if !matches!(v.fields, Fields::Unit) {
            errors
                .push(
                    syn::Error::new_spanned(
                            variant_name,
                            "KindStr requires unit (fieldless) variants",
                        )
                        .to_compile_error(),
                );
            continue;
        }
        let mut name = variant_name.to_string();
        let mut aliases: Vec<String> = Vec::new();
        for attr in &v.attrs {
            if !attr.path().is_ident("kind") {
                continue;
            }
            let r = attr
                .parse_nested_meta(|meta| {
                    if meta.path.is_ident("name") {
                        let s: LitStr = meta.value()?.parse()?;
                        name = s.value();
                    } else if meta.path.is_ident("alias") {
                        let s: LitStr = meta.value()?.parse()?;
                        aliases.push(s.value());
                    } else {
                        return Err(
                            meta.error("unknown `kind` key (expected name/alias/byte)"),
                        );
                    }
                    Ok(())
                });
            if let Err(e) = r {
                errors.push(e.to_compile_error());
            }
        }
        as_str_arms
            .push(
                quote! {
                    Self::# variant_name => # name,
                },
            );
        from_str_arms
            .push(
                quote! {
                    # name => ::core::option::Option::Some(Self::# variant_name),
                },
            );
        for a in &aliases {
            from_str_arms
                .push(
                    quote! {
                        # a => ::core::option::Option::Some(Self::# variant_name),
                    },
                );
        }
    }
    if !errors.is_empty() {
        let mut ts = proc_macro2::TokenStream::new();
        for e in errors {
            ts.extend(e);
        }
        return ts.into();
    }
    let expanded = quote! {
        impl # self_name { #[doc =
        "Wire string for this variant (paired inverse of `from_str_kind`)."] pub fn
        as_str(& self) -> &'static str { match self { # (# as_str_arms) * } } #[doc =
        "Parse a variant from its wire string (paired inverse of `as_str`)."] pub fn
        from_str_kind(s : & str) -> ::core::option::Option < Self > { match s { # (#
        from_str_arms) * _ => ::core::option::Option::None, } } }
    };
    TokenStream::from(expanded)
}