use alef_core::ir::TypeRef;
use std::collections::HashSet;
pub(super) fn gen_exception_class(namespace: &str, class_name: &str) -> String {
use crate::template_env::render;
use minijinja::Value;
render(
"exception_class.jinja",
Value::from_serialize(serde_json::json!({
"namespace": namespace,
"class_name": class_name,
})),
)
}
pub(super) fn compute_handle_returned_types(api: &alef_core::ir::ApiSurface) -> HashSet<String> {
fn inner_named(ty: &alef_core::ir::TypeRef) -> Option<&str> {
match ty {
alef_core::ir::TypeRef::Named(n) => Some(n.as_str()),
alef_core::ir::TypeRef::Optional(inner) | alef_core::ir::TypeRef::Vec(inner) => inner_named(inner),
_ => None,
}
}
let mut type_def_map = std::collections::HashMap::new();
for typ in &api.types {
type_def_map.insert(typ.name.clone(), typ);
}
let mut handle_types = HashSet::new();
for func in &api.functions {
if let Some(name) = inner_named(&func.return_type) {
if let Some(type_def) = type_def_map.get(name) {
if !type_def.has_serde {
handle_types.insert(name.to_string());
}
}
}
}
for typ in &api.types {
for method in &typ.methods {
if let Some(name) = inner_named(&method.return_type) {
if let Some(type_def) = type_def_map.get(name) {
if !type_def.has_serde {
handle_types.insert(name.to_string());
}
}
}
}
}
handle_types
}
pub(super) fn emit_return_statement(out: &mut String, return_type: &TypeRef) {
emit_return_statement_indented(out, return_type, " ");
}
pub(super) fn emit_return_marshalling_indented(
out: &mut String,
return_type: &TypeRef,
indent: &str,
enum_names: &HashSet<String>,
true_opaque_types: &HashSet<String>,
handle_returned_types: &HashSet<String>,
) {
use super::{returns_bool_via_int, returns_json_object, returns_string};
use crate::template_env::render;
use crate::type_map::csharp_type;
use heck::ToPascalCase;
if *return_type == TypeRef::Unit {
return;
}
if returns_string(return_type) {
out.push_str(&render("return_string_utf8.jinja", minijinja::context! { indent }));
out.push_str(&render("free_native_string.jinja", minijinja::context! { indent }));
} else if returns_bool_via_int(return_type) {
out.push_str(&render("return_bool_from_int.jinja", minijinja::context! { indent }));
} else if let TypeRef::Named(type_name) = return_type {
let pascal = type_name.to_pascal_case();
if true_opaque_types.contains(type_name)
|| true_opaque_types.contains(&pascal)
|| handle_returned_types.contains(type_name)
|| handle_returned_types.contains(&pascal)
{
out.push_str(&render(
"return_opaque_ctor.jinja",
minijinja::context! { indent, pascal },
));
} else if !enum_names.contains(&pascal) {
let to_json_method = format!("{pascal}ToJson");
let free_method = format!("{pascal}Free");
let cs_ty = csharp_type(return_type);
out.push_str(&render(
"native_to_json_ptr.jinja",
minijinja::context! { indent, to_json_method },
));
out.push_str(&render(
"json_from_ptr.jinja",
minijinja::context! { indent, ptr_var => "jsonPtr" },
));
out.push_str(&render(
"free_string_ptr.jinja",
minijinja::context! { indent, ptr_var => "jsonPtr" },
));
out.push_str(&render(
"free_native_handle.jinja",
minijinja::context! { indent, free_method },
));
out.push_str(&render(
"deserialize_json.jinja",
minijinja::context! { indent, cs_type => cs_ty },
));
} else {
let cs_ty = csharp_type(return_type);
out.push_str(&render(
"json_from_ptr.jinja",
minijinja::context! { indent, ptr_var => "nativeResult" },
));
out.push_str(&render(
"free_string_ptr.jinja",
minijinja::context! { indent, ptr_var => "nativeResult" },
));
out.push_str(&render(
"deserialize_json.jinja",
minijinja::context! { indent, cs_type => cs_ty },
));
}
} else if returns_json_object(return_type) {
if let TypeRef::Optional(inner) = return_type {
if returns_string(inner) {
out.push_str(&render("return_ptr_as_string.jinja", minijinja::context! { indent }));
out.push_str(&render("free_native_string.jinja", minijinja::context! { indent }));
return;
}
if let TypeRef::Named(type_name) = inner.as_ref() {
let pascal = type_name.to_pascal_case();
if true_opaque_types.contains(type_name)
|| true_opaque_types.contains(&pascal)
|| handle_returned_types.contains(type_name)
|| handle_returned_types.contains(&pascal)
{
out.push_str(&render(
"return_opaque_ctor.jinja",
minijinja::context! { indent, pascal },
));
return;
}
let to_json_method = format!("{pascal}ToJson");
let free_method = format!("{pascal}Free");
let cs_ty = csharp_type(return_type);
out.push_str(&render(
"native_to_json_ptr.jinja",
minijinja::context! { indent, to_json_method },
));
out.push_str(&render(
"json_from_ptr.jinja",
minijinja::context! { indent, ptr_var => "jsonPtr" },
));
out.push_str(&render(
"free_string_ptr.jinja",
minijinja::context! { indent, ptr_var => "jsonPtr" },
));
out.push_str(&render(
"free_native_handle.jinja",
minijinja::context! { indent, free_method },
));
out.push_str(&render(
"deserialize_json.jinja",
minijinja::context! { indent, cs_type => cs_ty },
));
return;
}
}
let cs_ty = csharp_type(return_type);
out.push_str(&render(
"json_from_ptr.jinja",
minijinja::context! { indent, ptr_var => "nativeResult" },
));
out.push_str(&render(
"free_string_ptr.jinja",
minijinja::context! { indent, ptr_var => "nativeResult" },
));
out.push_str(&render(
"deserialize_json.jinja",
minijinja::context! { indent, cs_type => cs_ty },
));
} else {
out.push_str(&render("return_native_result.jinja", minijinja::context! { indent }));
}
}
pub(super) fn emit_return_statement_indented(out: &mut String, return_type: &TypeRef, indent: &str) {
if *return_type != TypeRef::Unit {
out.push_str(&crate::template_env::render(
"return_value.jinja",
minijinja::context! { indent },
));
}
}