use crate::backends::ffi::type_map::result_presence_companion_exists;
use crate::backends::zig::template_env::render;
use crate::codegen::c_consumer::result_presence_symbol;
use crate::core::ir::{ReceiverKind, TypeRef};
const PRESENT: &str = "1";
const FUNCTION_INDENT: &str = " ";
pub(super) const METHOD_INDENT: &str = " ";
fn indent_fragment(fragment: &str, extra: &str) -> String {
fragment
.lines()
.map(|line| format!("{extra}{line}\n"))
.collect::<String>()
}
pub(super) fn free_function_presence_gate(
func: &crate::core::ir::FunctionDef,
prefix: &str,
struct_names: &std::collections::HashSet<String>,
opaque_creator_map: &std::collections::HashMap<String, (String, String)>,
primary_c_call: &str,
error_type: Option<&str>,
) -> Option<String> {
if !result_presence_companion_exists(&func.return_type, None) {
return None;
}
let mut teardown = String::new();
for param in &func.params {
super::functions::emit_param_free(param, prefix, struct_names, opaque_creator_map, &mut teardown);
}
result_presence_gate(
&func.return_type,
None,
primary_c_call,
prefix,
FUNCTION_INDENT,
&indent_fragment(&teardown, FUNCTION_INDENT),
error_type,
)
}
pub(super) fn result_presence_gate(
return_type: &TypeRef,
receiver: Option<&ReceiverKind>,
primary_c_call: &str,
prefix: &str,
indent: &str,
cleanup: &str,
error_type: Option<&str>,
) -> Option<String> {
if !result_presence_companion_exists(return_type, receiver) {
return None;
}
let (callee, rest) = primary_c_call
.split_once('(')
.unwrap_or_else(|| panic!("a Zig C call expression must have an argument list: {primary_c_call}"));
let symbol = callee
.strip_prefix("c.")
.unwrap_or_else(|| panic!("a Zig C call expression must be `@cImport`-qualified: {primary_c_call}"));
let args = rest
.strip_suffix(')')
.unwrap_or_else(|| panic!("a Zig C call expression must close its argument list: {primary_c_call}"));
let failure_block = error_type.map_or_else(String::new, |error_type| {
render(
"result_presence_error_check.jinja",
minijinja::context! {
indent => format!("{indent} "),
prefix,
error_type,
},
)
});
Some(render(
"result_presence_gate.jinja",
minijinja::context! {
symbol => result_presence_symbol(symbol),
args,
present => PRESENT,
indent,
cleanup,
failure_block,
},
))
}
#[cfg(test)]
mod tests;