use crate::validation::{
AsExprPath, check_injectivity, enum_type_of_expr, find_and_validate, surjectivity_check_arms,
};
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use syn::ItemFn;
pub fn impl_surjective_macro(attr: &str, func: &ItemFn) -> TokenStream2 {
let arms = find_and_validate(attr, func);
let output_type = enum_type_of_expr(arms[0].body.as_expr_path());
let check_arms = surjectivity_check_arms(arms);
let check_fn_name = format_ident!("surjectivity_check_{}", func.sig.ident);
quote! {
#func
#[expect(dead_code)]
fn #check_fn_name(output: #output_type) {
match output {
#(#check_arms)*
}
}
}
}
pub fn impl_injective_macro(attr: &str, func: &ItemFn) -> TokenStream2 {
let arms = find_and_validate(attr, func);
if let Some(err) = check_injectivity(arms) {
return err;
}
quote! { #func }
}
pub fn impl_bijective_macro(attr: &str, func: &ItemFn) -> TokenStream2 {
let arms = find_and_validate(attr, func);
if let Some(err) = check_injectivity(arms) {
return err;
}
let output_type = enum_type_of_expr(arms[0].body.as_expr_path());
let check_arms = surjectivity_check_arms(arms);
let check_fn_name = format_ident!("bijectivity_check_{}", func.sig.ident);
quote! {
#func
#[expect(dead_code)]
fn #check_fn_name(output: #output_type) {
match output {
#(#check_arms)*
}
}
}
}