unitval-derive 0.2.0

Provide values for unit enum variants
Documentation
pub use tokens::{AsUnitValTokens, FromUnitValTokens, Tokens};

use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use std::convert::TryFrom;
use syn::{Lit, Meta, MetaNameValue, Variant};

mod tokens;

const ATTR_PATH: &str = "unitval";

struct Unit<'a> {
    variant: &'a Variant,
    unitval: String,
}

impl<'a> Unit<'a> {
    pub fn as_unitval_tokens(&self) -> TokenStream {
        let ident = &self.variant.ident;
        let unitval = &self.unitval;
        quote! { Self::#ident => #unitval, }
    }

    pub fn from_unitval_tokens(&self) -> TokenStream {
        let ident = &self.variant.ident;
        let unitval = &self.unitval;
        quote! { #unitval => Ok(Self::#ident), }
    }
}

impl<'a> TryFrom<&'a Variant> for Unit<'a> {
    type Error = TokenStream;

    fn try_from(value: &'a Variant) -> Result<Self, Self::Error> {
        for attr in value.attrs.iter() {
            let meta = attr.parse_meta().map_err(|e| e.to_compile_error())?;
            let attr_ident = meta.path().get_ident().map(|i| i.to_string());
            if attr_ident.unwrap_or_default() == ATTR_PATH {
                if let Meta::NameValue(MetaNameValue { lit: Lit::Str(lit), .. }) = meta {
                    return Ok(Self { variant: value, unitval: lit.value() });
                }
            }
        }
        Err(quote_spanned! {
            value.ident.span() =>
            compile_error!("enum deriving UnitVal has variants without a specified `unitval`");
        })
    }
}