use {
crate::{
analysis::traits::{
TraitCategory,
classify_trait,
},
core::{
config::Config,
constants::macros,
},
hkt::ApplyInput,
},
syn::{
GenericArgument,
PathArguments,
},
};
pub struct FnBrandInfo {
pub inputs: Vec<syn::Type>,
pub output: syn::Type,
}
pub fn get_fn_brand_info(
type_path: &syn::TypePath,
config: &Config,
) -> Option<FnBrandInfo> {
if let Some(_qself) = &type_path.qself
&& type_path.path.segments.len() >= 2
{
#[expect(clippy::indexing_slicing, reason = "segments.len() >= 2 checked above")]
let trait_name = type_path.path.segments[0].ident.to_string();
if let TraitCategory::FnBrand = classify_trait(&trait_name, config) {
let last_segment = type_path.path.segments.last()?;
if let PathArguments::AngleBracketed(args) = &last_segment.arguments {
let mut type_args: Vec<_> = args
.args
.iter()
.filter_map(|arg| {
if let GenericArgument::Type(t) = arg { Some(t.clone()) } else { None }
})
.collect();
if !type_args.is_empty() {
let output = type_args.pop()?;
return Some(FnBrandInfo {
inputs: type_args,
output,
});
}
}
}
}
None
}
pub fn get_apply_macro_parameters(
type_macro: &syn::TypeMacro
) -> Option<(syn::Type, Vec<syn::Type>)> {
if type_macro.mac.path.is_ident(macros::APPLY_MACRO)
&& let Ok(apply_input) = syn::parse2::<ApplyInput>(type_macro.mac.tokens.clone())
{
let brand = apply_input.brand;
let args: Vec<_> = apply_input
.args
.args
.iter()
.filter_map(|arg| {
if let syn::GenericArgument::Type(t) = arg { Some(t.clone()) } else { None }
})
.collect();
return Some((brand, args));
}
None
}