use crate::backends::ffi::type_map::result_presence_companion_exists;
use crate::codegen::c_consumer;
use crate::codegen::naming::go_param_name;
use crate::core::ir::{ApiSurface, ParamDef, ReceiverKind, TypeRef};
const CTX_PARAM: &str = "ctx";
const BODY_LOCALS: [&str; 4] = [CTX_PARAM, "cancelToken", "cancelDone", "cancelStopped"];
const TOKEN_ARG: &str = "cancelToken";
pub(super) fn is_cancellable(
is_async: bool,
can_return_error: bool,
return_type: &TypeRef,
receiver: Option<&ReceiverKind>,
params: &[ParamDef],
) -> bool {
is_async
&& can_return_error
&& !result_presence_companion_exists(return_type, receiver)
&& !params
.iter()
.any(|param| BODY_LOCALS.contains(&go_param_name(¶m.name).as_str()))
}
pub(super) fn with_ctx_param(params: &str) -> String {
if params.is_empty() {
format!("{CTX_PARAM} context.Context")
} else {
format!("{CTX_PARAM} context.Context, {params}")
}
}
pub(super) fn forwarded_args(param_names: &[String]) -> String {
std::iter::once("context.Background()".to_string())
.chain(param_names.iter().cloned())
.collect::<Vec<_>>()
.join(", ")
}
pub(super) fn prelude(ffi_prefix: &str, err_return_prefix: &str) -> String {
render_prelude(ffi_prefix, err_return_prefix, true)
}
pub(super) fn prelude_with_stop_closure(ffi_prefix: &str, err_return_prefix: &str) -> String {
render_prelude(ffi_prefix, err_return_prefix, false)
}
fn render_prelude(ffi_prefix: &str, err_return_prefix: &str, defer_cleanup: bool) -> String {
crate::backends::go::template_env::render(
"ctx_cancel_prelude.jinja",
minijinja::context! {
defer_cleanup => defer_cleanup,
err_return_prefix => err_return_prefix,
new_fn => c_consumer::cancel_token_new_symbol(ffi_prefix),
cancel_fn => c_consumer::cancel_token_cancel_symbol(ffi_prefix),
free_fn => c_consumer::cancel_token_free_symbol(ffi_prefix),
},
)
}
pub(super) fn with_token_arg(c_call: &str) -> String {
let open_call = c_call
.strip_suffix(')')
.unwrap_or_else(|| panic!("a cgo call expression ends with `)`: {c_call}"));
if open_call.ends_with('(') {
format!("{open_call}{TOKEN_ARG})")
} else {
format!("{open_call}, {TOKEN_ARG})")
}
}
pub(super) fn cancellable_symbol(primary_symbol: &str) -> String {
c_consumer::cancellable_symbol(primary_symbol)
}
pub(super) fn last_error_call(with_context: bool) -> &'static str {
if with_context {
"lastErrorContext(ctx)"
} else {
"lastError()"
}
}
pub(super) fn gen_last_error_context_helper(ffi_prefix: &str) -> String {
crate::backends::go::template_env::render(
"last_error_context_helper.jinja",
minijinja::context! {
last_error_code_fn => crate::backends::go::c_symbols::last_error_code_symbol(ffi_prefix),
cancelled_code => ApiSurface::FFI_ERROR_CODE_CANCELLED,
},
)
}
#[cfg(test)]
mod tests;