use {
crate::{
analysis::traits::format_brand_name,
core::{
config::Config,
constants::{
traits,
types,
},
},
hm::{
HmAst,
ast_builder::HmAstBuilder,
},
support::{
TypeVisitor,
last_path_segment,
},
},
std::collections::{
HashMap,
HashSet,
},
syn::{
GenericArgument,
PathArguments,
ReturnType,
TraitBound,
Type,
},
};
pub fn type_to_hm(
ty: &Type,
fn_bounds: &HashMap<String, HmAst>,
generic_names: &HashSet<String>,
config: &Config,
) -> HmAst {
let mut visitor = HmAstBuilder {
fn_bounds,
generic_names,
config,
};
visitor.visit(ty)
}
pub(crate) fn is_phantom_data_path(type_path: &syn::TypePath) -> bool {
if let Some(segment) = type_path.path.segments.last() {
segment.ident == types::PHANTOM_DATA
} else {
false
}
}
pub(crate) fn is_smart_pointer(name: &str) -> bool {
types::SMART_POINTERS.contains(&name)
}
pub(crate) fn get_smart_pointer_inner(segment: &syn::PathSegment) -> Option<&syn::Type> {
if let PathArguments::AngleBracketed(args) = &segment.arguments
&& let Some(GenericArgument::Type(inner_ty)) = args.args.first()
{
return Some(inner_ty);
}
None
}
pub fn trait_bound_to_hm_type(
trait_bound: &TraitBound,
fn_bounds: &HashMap<String, HmAst>,
generic_names: &HashSet<String>,
config: &Config,
) -> HmAst {
let Some(segment) = last_path_segment(&trait_bound.path) else {
return HmAst::Variable("trait".to_string());
};
let name = segment.ident.to_string();
if traits::FN_TRAITS.contains(&name.as_str()) {
return trait_bound_to_hm_arrow(trait_bound, fn_bounds, generic_names, config);
}
let name = if generic_names.contains(&name) || name == types::SELF {
name.to_lowercase()
} else {
format_brand_name(&name, config)
};
if let PathArguments::AngleBracketed(args) = &segment.arguments {
let mut arg_types = Vec::new();
for arg in &args.args {
match arg {
GenericArgument::Type(ty) => {
arg_types.push(type_to_hm(ty, fn_bounds, generic_names, config));
}
GenericArgument::AssocType(assoc) => {
arg_types.push(type_to_hm(&assoc.ty, fn_bounds, generic_names, config));
}
_ => {}
}
}
if !arg_types.is_empty() {
return HmAst::Constructor(name, arg_types);
}
}
HmAst::Variable(name)
}
pub fn trait_bound_to_hm_arrow(
trait_bound: &TraitBound,
fn_bounds: &HashMap<String, HmAst>,
generic_names: &HashSet<String>,
config: &Config,
) -> HmAst {
let Some(segment) = last_path_segment(&trait_bound.path) else {
return HmAst::Variable("fn".to_string());
};
if let PathArguments::Parenthesized(args) = &segment.arguments {
let _ = &trait_bound.lifetimes;
let inputs: Vec<HmAst> =
args.inputs.iter().map(|t| type_to_hm(t, fn_bounds, generic_names, config)).collect();
let output = match &args.output {
ReturnType::Default => HmAst::Unit,
ReturnType::Type(_, ty) => type_to_hm(ty, fn_bounds, generic_names, config),
};
let input_ty = if inputs.is_empty() {
HmAst::Unit
} else if inputs.len() == 1 {
#[expect(clippy::indexing_slicing, reason = "inputs.len() == 1 checked above")]
inputs[0].clone()
} else {
HmAst::Tuple(inputs)
};
HmAst::Arrow(Box::new(input_ty), Box::new(output))
} else {
HmAst::Variable("fn".to_string())
}
}