alef 0.34.11

Opinionated polyglot binding generator for Rust libraries
Documentation
use crate::core::ir::{FunctionDef, ParamDef, TypeRef};
use std::collections::BTreeSet;

use super::types::kotlin_type_with_string_imports;
use crate::backends::kotlin::gen_bindings::helpers::emit_cleaned_kdoc;
use crate::backends::kotlin::gen_bindings::shared::to_lower_camel;

pub(crate) fn emit_function(
    f: &FunctionDef,
    out: &mut String,
    imports: &mut BTreeSet<String>,
    _java_package: &str,
    client_type_names: &std::collections::HashSet<&str>,
) {
    emit_cleaned_kdoc(out, &f.doc, "    ");
    let params: Vec<String> = f.params.iter().map(|p| format_param_with_imports(p, imports)).collect();
    let return_ty = kotlin_type_with_string_imports(&f.return_type, false, imports);
    let async_kw = if f.is_async { "suspend " } else { "" };
    let func_name_camel = to_lower_camel(&f.name);
    let call_args = f
        .params
        .iter()
        .map(|p| to_lower_camel(&p.name))
        .collect::<Vec<_>>()
        .join(", ");

    let returns_client_type = match &f.return_type {
        TypeRef::Named(n) => client_type_names.contains(n.as_str()),
        _ => false,
    };

    out.push_str(&crate::backends::kotlin::template_env::render(
        "function_signature.jinja",
        minijinja::context! {
            async_kw => async_kw,
            name => func_name_camel,
            params => params.join(", "),
            return_type => return_ty,
        },
    ));
    out.push('\n');

    let optional_suffix = if matches!(f.return_type, TypeRef::Optional(_)) && !returns_client_type {
        ".orElse(null)"
    } else {
        ""
    };

    if f.is_async {
        if returns_client_type {
            let wrapper = return_ty.trim_end_matches('?');
            out.push_str(&crate::backends::kotlin::template_env::render(
                "async_bridge_client_return.jinja",
                minijinja::context! {
                    wrapper => wrapper,
                    name => func_name_camel,
                    args => call_args,
                },
            ));
        } else {
            out.push_str(&crate::backends::kotlin::template_env::render(
                "async_bridge_return.jinja",
                minijinja::context! {
                    name => func_name_camel,
                    args => call_args,
                    optional_suffix => optional_suffix,
                },
            ));
        }
    } else if matches!(f.return_type, TypeRef::Unit) {
        out.push_str(&crate::backends::kotlin::template_env::render(
            "bridge_call_unit.jinja",
            minijinja::context! {
                name => func_name_camel,
                args => call_args,
            },
        ));
        out.push('\n');
    } else if returns_client_type {
        let wrapper = return_ty.trim_end_matches('?');
        out.push_str(&crate::backends::kotlin::template_env::render(
            "bridge_client_return.jinja",
            minijinja::context! {
                wrapper => wrapper,
                name => func_name_camel,
                args => call_args,
            },
        ));
    } else {
        out.push_str(&crate::backends::kotlin::template_env::render(
            "bridge_return.jinja",
            minijinja::context! {
                name => func_name_camel,
                args => call_args,
                optional_suffix => optional_suffix,
            },
        ));
    }
    out.push_str("    }\n");
}

pub(crate) fn format_param_with_imports(p: &ParamDef, imports: &mut BTreeSet<String>) -> String {
    let ty_str = kotlin_type_with_string_imports(&p.ty, p.optional, imports);
    let default = if p.optional { " = null" } else { "" };
    format!("{}: {}{}", to_lower_camel(&p.name), ty_str, default)
}