use super::generator::RustlerBridgeGenerator;
use super::json_args::build_json_arg;
use crate::codegen::generators::trait_bridge::{TraitBridgeGenerator, TraitBridgeSpec};
use crate::core::ir::{MethodDef, TypeRef};
impl TraitBridgeGenerator for RustlerBridgeGenerator {
fn foreign_object_type(&self) -> &str {
"rustler::LocalPid"
}
fn bridge_imports(&self) -> Vec<String> {
vec!["async_trait::async_trait".to_string()]
}
fn gen_sync_method_body(&self, method: &MethodDef, spec: &TraitBridgeSpec) -> String {
let has_error = method.error_type.is_some();
let clone_params: Vec<minijinja::Value> = method
.params
.iter()
.filter(|p| {
match &p.ty {
TypeRef::String => !p.is_ref, TypeRef::Bytes => false, TypeRef::Named(_) => p.is_ref, _ => false,
}
})
.map(|p| {
minijinja::context! {
name => p.name.clone()
}
})
.collect();
let params: Vec<minijinja::Value> = method
.params
.iter()
.map(|p| {
let json_expr = build_json_arg(p, spec.bridge_config);
minijinja::context! {
name => p.name.clone(),
json_expr => json_expr
}
})
.collect();
let error_deser = spec
.error_constructor
.replace("{msg}", "format!(\"Failed to deserialize response: {}\", _e)");
let error_msg = spec.error_constructor.replace("{msg}", "msg");
let error_closed = spec
.error_constructor
.replace("{msg}", "\"Channel closed before reply received\".to_string()");
let ctx = minijinja::context! {
clone_params => clone_params,
params => params,
method_name => method.name,
has_error => has_error,
error_deser => error_deser,
error_msg => error_msg,
error_closed => error_closed
};
crate::backends::rustler::template_env::render("sync_method_body.rs.jinja", ctx)
}
fn gen_async_method_body(&self, method: &MethodDef, spec: &TraitBridgeSpec) -> String {
let has_error = method.error_type.is_some();
let param_clones: Vec<minijinja::Value> = method
.params
.iter()
.filter(|p| {
match &p.ty {
TypeRef::String => !p.is_ref, TypeRef::Bytes => false, TypeRef::Named(_) => p.is_ref, _ => false,
}
})
.map(|p| {
minijinja::context! {
name => p.name.clone()
}
})
.collect();
let args_json: Vec<minijinja::Value> = method
.params
.iter()
.map(|p| {
let expr = build_json_arg(p, spec.bridge_config);
minijinja::context! {
name => p.name.clone(),
expr => expr
}
})
.collect();
let error_deser = spec
.error_constructor
.replace("{msg}", "format!(\"Failed to deserialize response: {}\", _e)");
let error_msg = spec.error_constructor.replace("{msg}", "msg");
let error_closed = spec
.error_constructor
.replace("{msg}", "\"Channel closed before reply received\".to_string()");
let ctx = minijinja::context! {
param_clones => param_clones,
args_json => args_json,
method_name => method.name,
has_error => has_error,
error_deser => error_deser,
error_msg => error_msg,
error_closed => error_closed
};
crate::backends::rustler::template_env::render("trait_async_method_body.rs.jinja", ctx)
}
fn gen_constructor(&self, spec: &TraitBridgeSpec) -> String {
let wrapper = spec.wrapper_name();
let ctx = minijinja::context! {
wrapper_name => wrapper
};
crate::backends::rustler::template_env::render("trait_constructor.rs.jinja", ctx)
}
fn gen_unregistration_fn(&self, spec: &TraitBridgeSpec) -> String {
let Some(unregister_fn) = spec.bridge_config.unregister_fn.as_deref() else {
return String::new();
};
let host_path = crate::codegen::generators::trait_bridge::host_function_path(spec, unregister_fn);
let ctx = minijinja::context! {
unregister_fn => unregister_fn,
host_path => host_path
};
crate::backends::rustler::template_env::render("trait_unregistration_fn.rs.jinja", ctx)
}
fn gen_clear_fn(&self, spec: &TraitBridgeSpec) -> String {
let Some(clear_fn) = spec.bridge_config.clear_fn.as_deref() else {
return String::new();
};
let host_path = crate::codegen::generators::trait_bridge::host_function_path(spec, clear_fn);
let ctx = minijinja::context! {
clear_fn => clear_fn,
host_path => host_path
};
crate::backends::rustler::template_env::render("trait_clear_fn.rs.jinja", ctx)
}
fn gen_registration_fn(&self, spec: &TraitBridgeSpec) -> String {
let Some(register_fn) = spec.bridge_config.register_fn.as_deref() else {
return String::new();
};
let Some(registry_getter) = spec.bridge_config.registry_getter.as_deref() else {
return String::new();
};
let wrapper = spec.wrapper_name();
let trait_path = spec.trait_path();
let extra_args = spec.bridge_config.register_extra_args.as_deref().unwrap_or_default();
let ctx = minijinja::context! {
register_fn => register_fn,
wrapper_name => wrapper,
trait_path => trait_path,
registry_getter => registry_getter,
extra_args => extra_args
};
crate::backends::rustler::template_env::render("trait_registration_fn.rs.jinja", ctx)
}
}
impl RustlerBridgeGenerator {
pub fn gen_support_nifs(&self) -> String {
let ctx = minijinja::context! {};
crate::backends::rustler::template_env::render("trait_support_nifs.rs.jinja", ctx)
}
}