use proc_macro2::TokenStream;
use quote::quote;
use syn::{Generics, Ident, Type};
extern crate alloc;
use alloc::vec::Vec;
use crate::models::{Enumeration, MatchArm};
#[derive(Debug)]
pub struct ImplementationContext {
pub generics: Generics,
pub ident: Ident,
pub match_arms: Vec<MatchArm>,
pub value_type: Type,
pub variant_idents: Vec<Ident>,
}
impl ImplementationContext {
pub fn new(value_type: &Type, enumeration: &Enumeration) -> Self {
let generics = &enumeration.generics;
let ident = &enumeration.ident;
let mut variants = enumeration.variants().iter().collect::<Vec<_>>();
variants.sort_by(|rhs, lhs| {
rhs.get_precedence(value_type)
.cmp(&lhs.get_precedence(value_type))
});
let relevant_variants = variants
.iter()
.map(|variant| {
(
variant.ident.clone(),
variant.get_match_attr_for_or_default(value_type),
)
})
.filter(|(_, value_type)| value_type.is_some());
let match_arms = relevant_variants
.clone()
.map(|(_, arm)| arm.unwrap().arm.clone());
let variant_idents = relevant_variants.map(|(ident, _)| ident);
Self {
generics: generics.clone(),
ident: ident.clone(),
match_arms: match_arms.collect(),
value_type: value_type.clone(),
variant_idents: variant_idents.collect(),
}
}
pub fn implement_full(&self) -> TokenStream {
let Self {
generics,
ident,
match_arms,
value_type,
variant_idents,
} = &self;
quote! {
impl<#generics> From<#value_type> for #ident {
fn from(value: #value_type) -> Self {
match value {
#(#match_arms => Self::#variant_idents,)*
}
}
}
}
}
pub fn implement_partial(&self) -> TokenStream {
let Self {
generics,
ident,
match_arms,
value_type,
variant_idents,
} = &self;
quote! {
impl<#generics> TryFrom<#value_type> for #ident {
type Error = ::matched_enums_types::UnmatchedError;
fn try_from(value: #value_type) -> core::result::Result<Self, Self::Error> {
match value {
#(#match_arms => Ok(Self::#variant_idents),)*
_ => Err(Self::Error{})
}
}
}
}
}
}