use super::json_args::build_json_arg;
use crate::codegen::generators::trait_bridge::{bridge_param_type as param_type, visitor_param_type};
use crate::core::ir::{ApiSurface, MethodDef, TypeDef, TypeRef};
pub(super) struct VisitorBridgeCtx<'a> {
pub(super) trait_type: &'a TypeDef,
pub(super) struct_name: &'a str,
pub(super) trait_path: &'a str,
pub(super) core_crate: &'a str,
pub(super) type_paths: &'a std::collections::HashMap<String, String>,
pub(super) bridge_cfg: &'a crate::core::config::TraitBridgeConfig,
pub(super) api: &'a ApiSurface,
}
pub(super) fn gen_visitor_bridge(out: &mut String, ctx: &VisitorBridgeCtx<'_>) -> anyhow::Result<()> {
let VisitorBridgeCtx {
trait_type,
struct_name,
trait_path,
core_crate,
type_paths,
bridge_cfg,
api,
} = ctx;
let result_metadata = crate::codegen::visitor_result::required_visitor_result_metadata(api, bridge_cfg)?;
let context_helper = crate::codegen::visitor_context::visitor_context_helper(
api,
bridge_cfg,
core_crate,
crate::codegen::visitor_context::VisitorContextBackend::Rustler,
)?;
let ctx_helper = minijinja::context! {
context_type_path => context_helper.type_path,
context_field_lines => context_helper.field_lines,
};
out.push_str(&crate::backends::rustler::template_env::render(
"visitor_bridge_helper.rs.jinja",
ctx_helper,
));
out.push_str(&crate::backends::rustler::template_env::render(
"visitor_bridge_globals.rs.jinja",
minijinja::context! {},
));
let ctx_struct = minijinja::context! {
struct_name => struct_name
};
out.push_str(&crate::backends::rustler::template_env::render(
"visitor_bridge_struct.rs.jinja",
ctx_struct,
));
let ctx_debug = minijinja::context! {
struct_name => struct_name
};
out.push_str(&crate::backends::rustler::template_env::render(
"visitor_bridge_debug.rs.jinja",
ctx_debug,
));
let ctx_constructors = minijinja::context! {
struct_name => struct_name
};
out.push_str(&crate::backends::rustler::template_env::render(
"visitor_bridge_constructors.rs.jinja",
ctx_constructors,
));
let ctx_send_wait = minijinja::context! {
struct_name => struct_name
};
out.push_str(&crate::backends::rustler::template_env::render(
"visitor_send_and_wait.rs.jinja",
ctx_send_wait,
));
out.push_str(&crate::backends::rustler::template_env::render(
"visitor_reply_nif.rs.jinja",
minijinja::context! {},
));
out.push_str(&crate::backends::rustler::template_env::render(
"trait_impl_header.jinja",
minijinja::context! {
trait_path => trait_path,
struct_name => struct_name,
},
));
for method in crate::codegen::generators::trait_bridge::visitor_callback_methods(trait_type, bridge_cfg) {
gen_visitor_method_async(out, method, type_paths, struct_name, bridge_cfg, &result_metadata);
}
out.push_str("}\n");
out.push('\n');
Ok(())
}
fn gen_visitor_method_async(
out: &mut String,
method: &MethodDef,
type_paths: &std::collections::HashMap<String, String>,
_struct_name: &str,
bridge_cfg: &crate::core::config::TraitBridgeConfig,
result_metadata: &crate::codegen::visitor_result::VisitorResultMetadata,
) {
let name = &method.name;
let mut sig_parts = vec!["&mut self".to_string()];
for p in &method.params {
let ty_str = visitor_param_type(&p.ty, p.is_ref, p.optional, type_paths);
sig_parts.push(format!("{}: {}", p.name, ty_str));
}
let sig = sig_parts.join(", ");
let ret_ty = match &method.return_type {
TypeRef::Named(n) => type_paths
.get(n.as_str())
.map(|p| p.replace('-', "_"))
.unwrap_or_else(|| n.clone()),
other => param_type(other, "", false, type_paths),
};
let handle_name = if let Some(suffix) = name.strip_prefix("visit_") {
format!("handle_{suffix}")
} else {
name.clone()
};
let args: Vec<minijinja::Value> = method
.params
.iter()
.map(|p| {
let json_expr = build_json_arg(p, bridge_cfg);
let key = p.name.strip_prefix('_').unwrap_or(&p.name).to_string();
minijinja::context! {
key => key,
expr => json_expr
}
})
.collect();
let ctx = minijinja::context! {
method_name => name,
sig => sig,
ret_ty => ret_ty,
default_result_expr => crate::codegen::visitor_result::default_result_expr(&ret_ty, result_metadata),
unknown_string_result_expr => crate::codegen::visitor_result::unknown_string_result_expr(
&ret_ty,
result_metadata,
"s",
),
unit_result_variants => crate::codegen::visitor_result::variant_contexts(&result_metadata.unit_variants),
payload_result_variants => crate::codegen::visitor_result::variant_contexts(
&result_metadata.string_payload_variants,
),
handle_name => handle_name,
args => args
};
out.push_str(&crate::backends::rustler::template_env::render(
"visitor_method.rs.jinja",
ctx,
));
}