use super::super::cancellation;
use super::super::types::emit_type_doc;
use super::gen_param_to_c;
use crate::backends::go::c_symbols;
use crate::backends::go::type_map::{go_optional_type, go_type};
use crate::codegen::naming::{go_param_name, go_type_name, to_go_name};
use crate::core::ir::{MethodDef, TypeDef, TypeRef};
#[allow(clippy::too_many_arguments)]
pub(in crate::backends::go::gen_bindings) fn gen_streaming_method_wrapper(
typ: &TypeDef,
method: &MethodDef,
ffi_prefix: &str,
item_type: &str,
data_enum_names: &std::collections::HashSet<&str>,
opaque_names: &std::collections::HashSet<&str>,
_value_only_types: &std::collections::HashSet<String>,
enum_names: &std::collections::HashSet<String>,
ffi_param_enum_names: &std::collections::HashSet<String>,
) -> String {
let mut out = String::with_capacity(2048);
let method_go_name = to_go_name(&method.name);
let method_with_context_name = format!("{method_go_name}WithContext");
let receiver_name = if typ.is_opaque { "h" } else { "r" };
let go_receiver_type = go_type_name(&typ.name);
let item_go_type = go_type_name(item_type);
let stream_type_name = format!("{go_receiver_type}{method_go_name}Stream");
out.push_str(&crate::backends::go::template_env::render(
"streaming_stream_type.jinja",
minijinja::context! {
stream_type_name => &stream_type_name,
receiver_type => &go_receiver_type,
method_name => &method_go_name,
item_type => &item_go_type,
},
));
emit_type_doc(&mut out, &method_go_name, &method.doc, "is a streaming method.");
let item_is_sum_type = data_enum_names.contains(item_type);
let method_params: Vec<String> = method
.params
.iter()
.map(|p| {
let param_type: String = if p.optional {
go_optional_type(&p.ty).into_owned()
} else if let TypeRef::Named(name) = &p.ty {
if opaque_names.contains(name.as_str()) {
format!("*{}", go_type(&p.ty))
} else {
go_type(&p.ty).into_owned()
}
} else {
go_type(&p.ty).into_owned()
};
format!("{} {}", go_param_name(&p.name), param_type)
})
.collect();
let param_args = method
.params
.iter()
.map(|p| go_param_name(&p.name))
.collect::<Vec<_>>()
.join(", ");
out.push_str(&crate::backends::go::template_env::render(
"streaming_method_compat.jinja",
minijinja::context! {
receiver_name => receiver_name,
receiver_type => &go_receiver_type,
method_name => &method_go_name,
method_with_context_name => &method_with_context_name,
params => method_params.join(", "),
param_args => ¶m_args,
item_type => &item_go_type,
},
));
let mut context_params = vec!["ctx context.Context".to_string()];
context_params.extend(method_params);
out.push_str(&crate::backends::go::template_env::render(
"streaming_method_signature.jinja",
minijinja::context! {
receiver_name => receiver_name,
receiver_type => &go_receiver_type,
method_name => &method_with_context_name,
params => context_params.join(", "),
item_type => &item_go_type,
stream_type_name => &stream_type_name,
},
));
for param in &method.params {
out.push_str(&gen_param_to_c(
param,
"nil, ",
true,
ffi_prefix,
opaque_names,
enum_names,
ffi_param_enum_names,
));
}
let c_params: Vec<String> = method
.params
.iter()
.flat_map(|p| -> Vec<String> {
let c_name = go_param_name(&format!("c_{}", p.name));
if matches!(p.ty, TypeRef::Bytes) {
vec![c_name.clone(), format!("{}Len", c_name)]
} else {
vec![c_name]
}
})
.collect();
let fn_start = c_symbols::stream_adapter_symbol(ffi_prefix, &typ.name, &method.name, "start_cancellable");
let fn_next = c_symbols::stream_adapter_symbol(ffi_prefix, &typ.name, &method.name, "next");
let fn_free = c_symbols::stream_adapter_symbol(ffi_prefix, &typ.name, &method.name, "free");
let item_to_json_fn = c_symbols::method_symbol(ffi_prefix, item_type, "to_json");
let item_free_fn = c_symbols::method_symbol(ffi_prefix, item_type, "free");
let c_receiver = format!("{}.ptr", receiver_name);
let start_call = cancellation::with_token_arg(&if c_params.is_empty() {
format!("C.{}({})", fn_start, c_receiver)
} else {
format!("C.{}({}, {})", fn_start, c_receiver, c_params.join(", "))
});
out.push_str(&crate::backends::go::template_env::render(
"streaming_method_body.jinja",
minijinja::context! {
cancel_prelude => cancellation::prelude_with_stop_closure(ffi_prefix, "nil, "),
start_call => &start_call,
ffi_prefix => ffi_prefix,
free_string_fn => c_symbols::free_string_symbol(ffi_prefix),
method_name => &method.name,
fn_next => &fn_next,
fn_free => &fn_free,
item_to_json_fn => &item_to_json_fn,
item_free_fn => &item_free_fn,
item_type => &item_go_type,
item_is_sum_type => item_is_sum_type,
stream_type_name => &stream_type_name,
},
));
out
}