alef 0.34.1

Opinionated polyglot binding generator for Rust libraries
Documentation
let reply_id = TRAIT_REPLY_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let (tx, rx) = tokio::sync::oneshot::channel::<Result<String, String>>();
TRAIT_REPLY_CHANNELS.lock().unwrap().insert(reply_id, tx);

let pid = self.inner;

{%- for arg in native_args %}
let {{ arg.binding }} = {{ arg.owned_expr }};
{%- endfor %}

let method = "{{ method_name }}";

drop(tokio::task::spawn_blocking(move || {
    let mut env = rustler::OwnedEnv::new();
    let _ = env.send_and_clear(&pid, |env| {
        let {% if native_args %}mut {% endif %}args_map = rustler::Term::map_new(env);
{%- for arg in native_args %}
        args_map = args_map.map_put("{{ arg.key }}".encode(env), {{ arg.binding }}.encode(env)).expect("map_put");
{%- endfor %}
        (rustler::types::atom::Atom::from_str(env, "trait_call").unwrap(), method, args_map, reply_id).encode(env)
    });
}));

match rx.blocking_recv() {
{%- if has_error %}
    Ok(Ok(json)) => serde_json::from_str(&json).map_err(|_e| {{ error_deser }}),
    Ok(Err(msg)) => Err({{ error_msg }}),
    Err(_) => Err({{ error_closed }})
{%- else %}
    // This method's Rust signature is infallible, so a host failure cannot
    // propagate. Log each failure before substituting the default — a silent
    // default is indistinguishable from a real result to the caller.
    Ok(Ok(json)) => serde_json::from_str(&json).unwrap_or_else(|e| {
        eprintln!("[{{ wrapper }}] host '{{ method_name }}' returned an unparseable value; returning default: {e}");
        Default::default()
    }),
    // The host side already logs its own raises in detail, so keep this brief.
    Ok(Err(_msg)) => {
        eprintln!("[{{ wrapper }}] host '{{ method_name }}' raised (details in host log); returning default");
        Default::default()
    }
    Err(_) => {
        eprintln!("[{{ wrapper }}] reply channel for host '{{ method_name }}' closed before a reply arrived (host process exited or dropped the call); returning default");
        Default::default()
    }
{%- endif %}
}