use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use crate::common::*;
use crate::tiers::*;
pub(crate) fn magetypes_impl(
mut input_fn: LightFn,
tiers: &[ResolvedTier],
rite_flag: bool,
in_impl: bool,
defines: &[String],
) -> TokenStream {
input_fn.attrs.retain(|attr| {
!["arcane", "rite", "magetypes"]
.iter()
.any(|name| attr.path().is_ident(name))
});
let fn_name = &input_fn.sig.ident;
let define_preamble: proc_macro2::TokenStream = {
let aliases = defines.iter().map(|name| {
let ident = quote::format_ident!("{name}");
quote! {
#[allow(non_camel_case_types, dead_code)]
type #ident = ::magetypes::simd::generic::#ident<Token>;
}
});
quote! { #(#aliases)* }
};
let has_dispatch = tokens_contain_ident(&input_fn.body, &["incant", "dispatch_variant"]);
let tokenless_rite = rite_flag
&& has_dispatch
&& crate::token_discovery::find_token_param(&input_fn.sig).is_none()
&& !input_fn.sig.inputs.iter().any(|arg| {
let syn::FnArg::Typed(param) = arg else {
return false;
};
matches!(
crate::token_discovery::extract_token_type_info(¶m.ty),
Some(crate::token_discovery::TokenTypeInfo::Generic(name)) if name == "Token"
)
});
let mut variants = Vec::with_capacity(tiers.len());
for tier in tiers {
let mut variant_fn = input_fn.clone();
variant_fn.sig.ident = quote::format_ident!("{}_{}", fn_name, tier.suffix);
if !defines.is_empty() {
let original_body = &variant_fn.body;
variant_fn.body = quote! {
#define_preamble
#original_body
};
}
if has_dispatch {
let ctx = crate::rewrite::CallerContext {
tier_suffix: tier.suffix.to_string(),
target_arch: tier.target_arch,
token_ident: quote::format_ident!("_"),
has_token: false,
derive_token: tokenless_rite && tier.target_arch.is_none(),
};
variant_fn.body = crate::rewrite::rewrite_incant_in_body(variant_fn.body, &ctx);
}
let variant_tokens = if tier.token_path.is_empty() {
variant_fn.to_token_stream()
} else {
let concrete_tokens: proc_macro2::TokenStream = tier
.token_path
.parse()
.expect("tier token_path must be valid tokens");
replace_ident_in_tokens(variant_fn.to_token_stream(), "Token", &concrete_tokens)
};
let cfg_guard = tier.variant_cfg_guard();
variants.push(if !tier.is_fallback() {
let wrapper = if rite_flag {
let tier_name = quote::format_ident!("{}", tier.name);
quote! { #[archmage::rite(#tier_name, import_intrinsics)] }
} else if in_impl {
quote! { #[archmage::arcane(in_impl)] }
} else {
quote! { #[archmage::arcane] }
};
quote! {
#cfg_guard
#wrapper
#variant_tokens
}
} else {
quote! {
#cfg_guard
#variant_tokens
}
});
}
let output = quote! {
#(#variants)*
};
output
}