matched_enums_macro 1.3.0

Contains the macro for matchable enums.
Documentation
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,
    /// NOTE: Each element overlaps with an element of `variant_idents` of the same index.
    pub match_arms: Vec<MatchArm>,
    pub value_type: Type,
    /// NOTE: Each element overlaps with an element of `match_arms` of the same index.
    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{})
                    }
                }
            }
        }
    }
}