alef 0.84.2

Opinionated polyglot binding generator for Rust libraries
Documentation
        let __fut = {{ call_expr }};
        // ~keep 32 MiB: the runtime below is a *current-thread* runtime, so it spawns no
        // workers and `thread_stack_size` would govern nothing that matters here —
        // `block_on` drives the host callback future on this very thread. A thread from
        // the bare `std::thread::spawn` this replaces gets Rust's 2 MiB default, which a
        // deep callback future overflows, and a stack overflow aborts the process with
        // SIGBUS instead of raising a catchable panic. Matches the Rustler bridge, which
        // widens its own calling thread to the same 32 MiB for the same reason.
        const VISITOR_BLOCK_ON_STACK_SIZE_BYTES: usize = 32 * 1024 * 1024;
{% if has_error %}
        let {{ result_var }} = std::thread::Builder::new()
            .stack_size(VISITOR_BLOCK_ON_STACK_SIZE_BYTES)
            .spawn(move || {
                ::tokio::runtime::Builder::new_current_thread()
                    .build()
                    .expect("build alef visitor tokio runtime")
                    .block_on(__fut)
            })
            .expect("spawn alef visitor block_on thread")
            .join()
            .expect("thread panicked");
{% else %}
        let {{ result_var }} = match std::thread::Builder::new()
            .stack_size(VISITOR_BLOCK_ON_STACK_SIZE_BYTES)
            .spawn(move || {
                ::tokio::runtime::Builder::new_current_thread()
                    .build()
                    .expect("build alef visitor tokio runtime")
                    .block_on(__fut)
            })
            .expect("spawn alef visitor block_on thread")
            .join()
        {
            Ok(v) => v,
            Err(e) => {
                let msg = e
                    .downcast_ref::<&str>()
                    .map(|s| (*s).to_string())
                    .or_else(|| e.downcast_ref::<String>().cloned())
                    .unwrap_or_else(|| "non-string panic payload".to_string());
{% if resume_panic %}
                // Excluded core return types carry no Default guarantee, so a
                // substituted value is not an option here — log the failure,
                // then re-raise the original panic (previous behavior, now
                // observable).
                tracing::warn!(wrapper = "{{ wrapper }}", method = "{{ method_name }}", error = %msg, "host callback panicked");
                std::panic::resume_unwind(e);
{% else %}
                // This method's Rust signature is infallible, so a panic on the
                // callback thread cannot propagate. Log before substituting the
                // default — a silent default is indistinguishable from a real
                // result to the caller.
                tracing::warn!(wrapper = "{{ wrapper }}", method = "{{ method_name }}", error = %msg, "host callback panicked; returning default");
                return Default::default();
{% endif %}
            }
        };
{% endif %}