use {
crate::{
core::{
config::Config,
constants::{
brands,
macros,
markers,
traits,
},
},
hm::HmAst,
support::last_path_segment,
},
std::collections::{
HashMap,
HashSet,
},
};
const INFRASTRUCTURE_TRAITS: &[&str] =
&["Send", "Sync", "Clone", "Copy", "Debug", "Display", "Sized", "LiftFn", "SendLiftFn"];
#[derive(Debug, PartialEq)]
pub enum TraitCategory {
FnTrait,
FnBrand,
ApplyMacro,
Kind,
Dispatch,
Infrastructure,
Other(String),
}
pub fn classify_trait(
name: &str,
config: &Config,
) -> TraitCategory {
match name {
n if traits::FN_TRAITS.contains(&n) => TraitCategory::FnTrait,
n if brands::FN_BRANDS.contains(&n) => TraitCategory::FnBrand,
macros::APPLY_MACRO => TraitCategory::ApplyMacro,
n if config.apply_macro_aliases().contains(n) => TraitCategory::ApplyMacro,
n if n.starts_with(markers::KIND_PREFIX) => TraitCategory::Kind,
n if n.starts_with(markers::INFERABLE_BRAND_PREFIX) => TraitCategory::Kind,
n if n.ends_with(markers::DISPATCH_SUFFIX) => TraitCategory::Dispatch,
n if INFRASTRUCTURE_TRAITS.contains(&n) => TraitCategory::Infrastructure,
_ => TraitCategory::Other(name.to_string()),
}
}
pub fn is_semantic_type_class(name: &str) -> bool {
if traits::FN_TRAITS.contains(&name) {
return false;
}
if brands::FN_BRANDS.contains(&name) {
return false;
}
if name.starts_with(markers::KIND_PREFIX) || name.starts_with(markers::INFERABLE_BRAND_PREFIX) {
return false;
}
if name.ends_with(markers::DISPATCH_SUFFIX) {
return false;
}
if INFRASTRUCTURE_TRAITS.contains(&name) {
return false;
}
true
}
pub fn get_fn_type_from_bound(
trait_bound: &syn::TraitBound,
fn_bounds: &HashMap<String, HmAst>,
generic_names: &HashSet<String>,
config: &Config,
) -> Option<HmAst> {
let segment = last_path_segment(&trait_bound.path)?;
let name = segment.ident.to_string();
match classify_trait(&name, config) {
TraitCategory::FnTrait => Some(crate::hm::converter::trait_bound_to_hm_arrow(
trait_bound,
fn_bounds,
generic_names,
config,
)),
TraitCategory::FnBrand => Some(HmAst::Variable(markers::FN_BRAND_MARKER.to_string())),
_ => None,
}
}
pub fn format_brand_name(
name: &str,
config: &Config,
) -> String {
if let Some(mapping) = config.brand_mappings().get(name) {
return mapping.clone();
}
if let Some(stripped) = name.strip_suffix(markers::BRAND_SUFFIX) {
if stripped.is_empty() {
name.to_string()
} else {
stripped.to_string()
}
} else {
name.to_string()
}
}