use crate::core::config::{BridgeBinding, TraitBridgeConfig};
use crate::core::ir::{ApiSurface, FieldDef, FunctionDef, TypeDef, TypeRef};
pub fn bridge_handle_path(api: &ApiSurface, bridge: &TraitBridgeConfig, core_import: &str) -> String {
let alias = bridge.type_alias.as_deref().unwrap_or(&bridge.trait_name);
api.types
.iter()
.find(|typ| typ.name == alias && !typ.rust_path.is_empty())
.map(|typ| typ.rust_path.replace('-', "_"))
.or_else(|| api.excluded_type_paths.get(alias).map(|path| path.replace('-', "_")))
.unwrap_or_else(|| format!("{core_import}::{alias}"))
}
pub fn bridge_wrapper_name(prefix: &str, bridge: &TraitBridgeConfig) -> String {
format!("{}{}Bridge", prefix, bridge.trait_name)
}
pub fn is_bridge_handle_type_ref(ty: &TypeRef, bridges: &[TraitBridgeConfig]) -> bool {
bridges
.iter()
.filter_map(|bridge| bridge.type_alias.as_deref())
.any(|alias| field_type_matches_alias(ty, alias))
}
pub fn is_trait_bridge_managed_fn(func_name: &str, bridges: &[TraitBridgeConfig]) -> bool {
bridges.iter().any(|b| b.clear_fn.as_deref() == Some(func_name))
}
pub fn find_bridge_param<'a>(
func: &FunctionDef,
bridges: &'a [TraitBridgeConfig],
) -> Option<(usize, &'a TraitBridgeConfig)> {
for (idx, param) in func.params.iter().enumerate() {
let named = match ¶m.ty {
TypeRef::Named(n) => Some(n.as_str()),
TypeRef::Optional(inner) => {
if let TypeRef::Named(n) = inner.as_ref() {
Some(n.as_str())
} else {
None
}
}
_ => None,
};
for bridge in bridges {
if bridge.bind_via != BridgeBinding::FunctionParam {
continue;
}
if let Some(type_name) = named {
if bridge.type_alias.as_deref() == Some(type_name) {
return Some((idx, bridge));
}
}
if bridge.param_name.as_deref() == Some(param.name.as_str()) {
return Some((idx, bridge));
}
}
}
None
}
#[derive(Debug, Clone)]
pub struct BridgeFieldMatch<'a> {
pub param_index: usize,
pub param_name: String,
pub options_type: String,
pub param_is_optional: bool,
pub field_name: String,
pub field: &'a FieldDef,
pub bridge: &'a TraitBridgeConfig,
}
pub fn find_bridge_field<'a>(
func: &FunctionDef,
types: &'a [TypeDef],
bridges: &'a [TraitBridgeConfig],
) -> Option<BridgeFieldMatch<'a>> {
fn unwrap_named(ty: &TypeRef) -> Option<(&str, bool)> {
match ty {
TypeRef::Named(n) => Some((n.as_str(), false)),
TypeRef::Optional(inner) => {
if let TypeRef::Named(n) = inner.as_ref() {
Some((n.as_str(), true))
} else {
None
}
}
_ => None,
}
}
for (idx, param) in func.params.iter().enumerate() {
let Some((type_name, is_optional)) = unwrap_named(¶m.ty) else {
continue;
};
let Some(type_def) = types.iter().find(|t| t.name == type_name) else {
continue;
};
for bridge in bridges {
if bridge.bind_via != BridgeBinding::OptionsField {
continue;
}
if bridge.options_type.as_deref() != Some(type_name) {
continue;
}
let field_name = bridge.resolved_options_field();
for field in &type_def.fields {
let matches_name = field_name.is_some_and(|n| field.name == n);
let matches_alias = bridge
.type_alias
.as_deref()
.is_some_and(|alias| field_type_matches_alias(&field.ty, alias));
if matches_name || matches_alias {
return Some(BridgeFieldMatch {
param_index: idx,
param_name: param.name.clone(),
options_type: type_name.to_string(),
param_is_optional: is_optional,
field_name: field.name.clone(),
field,
bridge,
});
}
}
}
}
None
}
fn field_type_matches_alias(field_ty: &TypeRef, alias: &str) -> bool {
match field_ty {
TypeRef::Named(n) => n == alias,
TypeRef::Optional(inner) | TypeRef::Vec(inner) => field_type_matches_alias(inner, alias),
_ => false,
}
}