use proc_macro2::TokenStream;
use crate::implementation::ImplementationContext;
use crate::models::Enumeration;
pub use implementation::{declare_runtime_configurable, implement_runtime_configurable};
#[cfg(feature = "runtime_configurable")]
mod implementation {
extern crate alloc;
use super::*;
use convert_case::{Case, Casing};
use quote::{format_ident, quote};
use syn::Ident;
use alloc::string::ToString;
use alloc::vec::Vec;
fn ident_to_snake(ident: &Ident) -> Ident {
let span = ident.span();
let new_name = ident.to_string().to_case(Case::Snake);
Ident::new(&new_name, span)
}
fn make_matcher_ident(ident: &Ident) -> Ident {
format_ident!("{}Matcher", ident)
}
pub fn declare_runtime_configurable(enumeration: &Enumeration) -> syn::Result<TokenStream> {
let enum_ident = &enumeration.ident;
let matcher_ident = make_matcher_ident(&enumeration.ident);
let variants = enumeration.variants().iter().clone().map(|e| &e.ident);
let attribute_idents = variants.clone().map(ident_to_snake).collect::<Vec<Ident>>();
Ok(quote! {
struct #matcher_ident<T>{
_convert_from_type: core::marker::PhantomData<T>,
#(pub #attribute_idents: alloc::boxed::Box<dyn Fn(&T) -> bool>),*,
}
impl<T> #matcher_ident<T> {
pub fn try_into_enum(&self, value: &T) -> core::result::Result<#enum_ident, ::matched_enums_types::UnmatchedError>{
#(if (self.#attribute_idents)(value) {
return Ok(#enum_ident::#variants);
}
)*
Err(::matched_enums_types::UnmatchedError{})
}
}
})
}
pub fn implement_runtime_configurable(
context: &ImplementationContext,
) -> syn::Result<TokenStream> {
let ImplementationContext {
ident,
match_arms,
value_type,
variant_idents,
..
} = context;
let matcher_ident = make_matcher_ident(ident);
let attribute_idents = variant_idents.iter().map(ident_to_snake);
Ok(quote! {
impl Default for #matcher_ident<#value_type> {
fn default() -> Self {
Self{
#(#attribute_idents: alloc::boxed::Box::new(|&value| matches!(value, #match_arms))),*,
_convert_from_type: Default::default(),
}
}
}
})
}
}
#[cfg(not(feature = "runtime_configurable"))]
mod implementation {
use super::*;
pub fn declare_runtime_configurable(enumeration: &Enumeration) -> syn::Result<TokenStream> {
Err(syn::Error::new(
enumeration.span(),
"Feature `runtime_configurable` must be enabled for to implement its behavior",
))
}
pub fn implement_runtime_configurable(
context: &ImplementationContext,
) -> syn::Result<TokenStream> {
Err(syn::Error::new(
context.ident.span(),
"Feature `runtime_configurable` must be enabled for to implement its behavior",
))
}
}