extern crate alloc;
use alloc::vec::Vec;
use proc_macro2::Span;
use syn::{Generics, Ident, ItemEnum, Meta, parse2, spanned::Spanned};
use super::{TopLevelAttribute, Variant};
pub struct Enumeration {
pub attribute: TopLevelAttribute,
pub generics: Generics,
pub ident: Ident,
span: Span,
variants: Vec<Variant>,
}
impl Enumeration {
pub fn span(&self) -> Span {
self.span
}
pub fn variants(&self) -> &[Variant] {
&self.variants
}
}
impl TryFrom<ItemEnum> for Enumeration {
type Error = syn::Error;
fn try_from(value: ItemEnum) -> syn::Result<Self> {
const ATTR_NAME: &str = "matched_enum";
let mut enumeration = Self {
attribute: value
.attrs
.iter()
.find(|attr| attr.path().is_ident(ATTR_NAME))
.map(|attr| match &attr.meta {
Meta::List(members) => parse2::<TopLevelAttribute>(members.tokens.clone()),
_ => Err(syn::Error::new(
attr.span(),
format_args!(
"Must provide {ATTR_NAME} as a list. (e.g., `#[{ATTR_NAME}(key=val, ..)]`)"
),
)),
})
.unwrap_or(Ok(TopLevelAttribute::default()))?,
generics: value.generics.clone(),
ident: value.ident.clone(),
span: value.span(),
variants: Vec::with_capacity(value.variants.len()),
};
if enumeration.attribute.value_types.is_empty() {
return Err(syn::Error::new(
enumeration.span(),
"`value_types` may not be empty",
));
}
for variant in value.variants {
enumeration.variants.push(Variant::try_from(variant)?);
}
Ok(enumeration)
}
}
#[cfg(test)]
mod test;