use proc_macro::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,
defines: &[String],
) -> TokenStream {
input_fn
.attrs
.retain(|attr| !attr.path().is_ident("arcane") && !attr.path().is_ident("rite"));
let fn_name = &input_fn.sig.ident;
let propagated_attrs: Vec<_> = input_fn
.attrs
.iter()
.filter(|a| !a.path().is_ident("magetypes"))
.cloned()
.collect();
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 mut variants = Vec::new();
for tier in tiers {
let mut variant_fn = input_fn.clone();
variant_fn.sig.ident = quote::format_ident!("{}_{}", fn_name, tier.suffix);
variant_fn.attrs = propagated_attrs.clone();
if !defines.is_empty() {
let original_body = &variant_fn.body;
variant_fn.body = quote! {
#define_preamble
#original_body
};
}
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 allow_attr = if tier.allow_unexpected_cfg {
quote! { #[allow(unexpected_cfgs)] }
} else {
quote! {}
};
let cfg_guard = match (tier.target_arch, &tier.feature_gate) {
(Some(arch), Some(feat)) => quote! {
#[cfg(target_arch = #arch)]
#allow_attr
#[cfg(feature = #feat)]
},
(Some(arch), None) => quote! { #[cfg(target_arch = #arch)] },
(None, Some(feat)) => quote! {
#allow_attr
#[cfg(feature = #feat)]
},
(None, None) => quote! {},
};
variants.push(if tier.name != "scalar" && tier.name != "default" {
let wrapper = if rite_flag {
quote! { #[archmage::rite(import_intrinsics)] }
} else {
quote! { #[archmage::arcane] }
};
quote! {
#cfg_guard
#wrapper
#variant_tokens
}
} else {
quote! {
#cfg_guard
#variant_tokens
}
});
}
let output = quote! {
#(#variants)*
};
output.into()
}