use crate::core::config::TraitBridgeConfig;
use crate::core::ir::{MethodDef, TypeDef, TypeRef};
use heck::ToSnakeCase;
use std::collections::{HashMap, HashSet};
use super::bridge_wrapper_name;
pub struct TraitBridgeSpec<'a> {
pub trait_def: &'a TypeDef,
pub bridge_config: &'a TraitBridgeConfig,
pub core_import: &'a str,
pub wrapper_prefix: &'a str,
pub type_paths: HashMap<String, String>,
pub lifetime_type_names: HashSet<String>,
pub error_type: String,
pub error_constructor: String,
}
impl<'a> TraitBridgeSpec<'a> {
pub fn error_path(&self) -> String {
if self.error_type.contains("::") || self.error_type.contains('<') {
self.error_type.clone()
} else {
format!("{}::{}", self.core_import, self.error_type)
}
}
pub fn make_error(&self, msg_expr: &str) -> String {
self.error_constructor.replace("{msg}", msg_expr)
}
pub fn wrapper_name(&self) -> String {
bridge_wrapper_name(self.wrapper_prefix, self.bridge_config)
}
pub fn trait_snake(&self) -> String {
self.trait_def.name.to_snake_case()
}
pub fn trait_path(&self) -> String {
self.trait_def.rust_path.replace('-', "_")
}
pub fn required_methods(&self) -> Vec<&'a MethodDef> {
self.trait_def.methods.iter().filter(|m| !m.has_default_impl).collect()
}
pub fn optional_methods(&self) -> Vec<&'a MethodDef> {
self.trait_def.methods.iter().filter(|m| m.has_default_impl).collect()
}
}
pub fn own_vtable_methods<'a>(trait_def: &'a TypeDef, ffi_skip_methods: &[String]) -> Vec<&'a MethodDef> {
trait_def
.methods
.iter()
.filter(|method| method.trait_source.is_none() && !ffi_skip_methods.iter().any(|skip| skip == &method.name))
.collect()
}
pub fn vtable_slot_names(trait_def: &TypeDef, has_super_trait: bool, ffi_skip_methods: &[String]) -> Vec<String> {
let mut names: Vec<String> = Vec::new();
if has_super_trait {
names.extend(["name_fn", "version_fn", "initialize_fn", "shutdown_fn"].map(String::from));
}
names.extend(
own_vtable_methods(trait_def, ffi_skip_methods)
.into_iter()
.map(|method| method.name.clone()),
);
names.push("free_string".to_string());
names.push("free_user_data".to_string());
names
}
pub fn visitor_callback_methods<'a>(trait_def: &'a TypeDef, bridge_config: &TraitBridgeConfig) -> Vec<&'a MethodDef> {
trait_def
.methods
.iter()
.filter(|method| is_visitor_callback_method(method, bridge_config))
.collect()
}
fn is_visitor_callback_method(method: &MethodDef, bridge_config: &TraitBridgeConfig) -> bool {
if method.trait_source.is_some() {
return false;
}
let Some(result_type) = bridge_config.result_type.as_deref() else {
return false;
};
let Some(context_type) = bridge_config.context_type.as_deref() else {
return false;
};
type_ref_matches_name(&method.return_type, result_type)
&& method
.params
.iter()
.any(|param| type_ref_matches_name(¶m.ty, context_type))
}
fn type_ref_matches_name(ty: &TypeRef, name: &str) -> bool {
match ty {
TypeRef::Named(type_name) => type_name == name,
TypeRef::Optional(inner) => type_ref_matches_name(inner, name),
_ => false,
}
}