use crate::backends::swift::gen_rust_crate::trait_bridge::SwiftBridgeGenerator;
use crate::codegen::generators::trait_bridge::{TraitBridgeGenerator as _, TraitBridgeSpec};
use crate::core::config::TraitBridgeConfig;
use crate::core::ir::{ApiSurface, TypeDef};
use super::has_plugin_super;
use super::method_impls::{emit_inbound_method_impl, error_type_path, result_type};
pub(crate) fn emit_inbound_wrapper(
trait_def: &TypeDef,
bridge_config: &TraitBridgeConfig,
api: &ApiSurface,
source_crate: &str,
type_paths: &std::collections::HashMap<String, String>,
error_type: &str,
error_constructor: &str,
) -> String {
let trait_name = &trait_def.name;
let trait_snake = heck::AsSnakeCase(trait_name.as_str()).to_string();
let box_name = format!("Swift{trait_name}Box");
let wrapper_name = format!("Swift{trait_name}Wrapper");
let trait_path = if trait_def.rust_path.is_empty() {
format!("{source_crate}::{trait_name}")
} else {
trait_def.rust_path.replace('-', "_")
};
let emit_plugin = has_plugin_super(bridge_config);
let plugin_path = if emit_plugin {
resolve_plugin_supertrait_path(api, bridge_config)
} else {
None
};
let mut out = String::new();
if emit_plugin {
out.push_str(&crate::backends::swift::template_env::render(
"inbound_wrapper_struct.rs.jinja",
minijinja::context! {
trait_name => trait_name,
wrapper_name => &wrapper_name,
box_name => &box_name,
},
));
} else {
out.push_str(&crate::backends::swift::template_env::render(
"inbound_plain_wrapper_struct.rs.jinja",
minijinja::context! {
trait_name => trait_name,
wrapper_name => &wrapper_name,
box_name => &box_name,
},
));
if trait_def
.super_traits
.iter()
.any(|s| s == "Debug" || s.ends_with("::Debug"))
{
out.push_str(&crate::backends::swift::template_env::render(
"inbound_plain_wrapper_debug.rs.jinja",
minijinja::context! {
wrapper_name => &wrapper_name,
},
));
}
}
if emit_plugin {
if let Some(plugin_path) = plugin_path.as_deref() {
out.push_str(&crate::backends::swift::template_env::render(
"inbound_plugin_impl.rs.jinja",
minijinja::context! {
plugin_path => plugin_path,
wrapper_name => &wrapper_name,
result_type => result_type(source_crate, error_type, "()"),
},
));
} else {
out.push_str(&crate::backends::swift::template_env::render(
"inbound_plugin_path_compile_error.rs.jinja",
minijinja::context! {
trait_name => trait_name,
},
));
}
}
let _ = trait_snake;
let has_async = trait_def.methods.iter().any(|m| m.is_async);
out.push_str(&crate::backends::swift::template_env::render(
"inbound_trait_impl_open.rs.jinja",
minijinja::context! {
has_async => has_async,
trait_path => &trait_path,
wrapper_name => &wrapper_name,
},
));
let lifetime_type_names: std::collections::HashSet<String> = api
.types
.iter()
.filter(|t| t.has_lifetime_params)
.map(|t| t.name.clone())
.collect();
for method in &trait_def.methods {
emit_inbound_method_impl(
&mut out,
method,
&trait_snake,
source_crate,
type_paths,
error_type,
emit_plugin,
&lifetime_type_names,
);
}
out.push_str("}\n\n");
if let Some(register_fn) = bridge_config.register_fn.as_deref() {
if let Some(registry_getter) = bridge_config.registry_getter.as_deref() {
let extra_args = bridge_config
.register_extra_args
.as_deref()
.map(|a| format!(", {a}"))
.unwrap_or_default();
out.push_str(&crate::backends::swift::template_env::render(
"inbound_register_fn.rs.jinja",
minijinja::context! {
trait_name => trait_name,
register_fn => register_fn,
box_name => &box_name,
trait_path => &trait_path,
wrapper_name => &wrapper_name,
registry_getter => registry_getter,
extra_args => &extra_args,
},
));
}
}
let spec = build_bridge_spec(
bridge_config,
trait_def,
source_crate,
type_paths,
error_type,
error_constructor,
);
let generator = SwiftBridgeGenerator;
let unregister_code = generator.gen_unregistration_fn(&spec);
if !unregister_code.is_empty() {
out.push_str(&unregister_code);
out.push('\n');
}
let clear_code = generator.gen_clear_fn(&spec);
if !clear_code.is_empty() {
out.push_str(&clear_code);
out.push('\n');
}
out
}
fn resolve_plugin_supertrait_path(api: &ApiSurface, bridge_config: &TraitBridgeConfig) -> Option<String> {
let super_trait = bridge_config.super_trait.as_deref()?;
if super_trait.contains("::") {
return Some(super_trait.replace('-', "_"));
}
api.types
.iter()
.find(|t| t.is_trait && t.name == super_trait && !t.rust_path.is_empty())
.map(|t| t.rust_path.replace('-', "_"))
}
fn build_bridge_spec<'a>(
bridge_config: &'a TraitBridgeConfig,
trait_def: &'a TypeDef,
source_crate: &'a str,
type_paths: &std::collections::HashMap<String, String>,
error_type: &str,
error_constructor: &str,
) -> TraitBridgeSpec<'a> {
TraitBridgeSpec {
trait_def,
bridge_config,
core_import: source_crate,
wrapper_prefix: "Swift",
type_paths: type_paths.clone(),
lifetime_type_names: std::collections::HashSet::new(),
error_type: error_type.to_string(),
error_constructor: error_constructor.to_string(),
}
}
pub(crate) fn emit_plugin_error_helper(source_crate: &str, error_type: &str, error_constructor: &str) -> String {
let error_type_path = error_type_path(source_crate, error_type);
let plugin_error_constructor = error_constructor.replace("{msg}", "message");
crate::backends::swift::template_env::render(
"plugin_error_helper.rs.jinja",
minijinja::context! {
error_type_path => &error_type_path,
plugin_error_constructor => &plugin_error_constructor,
},
)
}