alef 0.25.37

Opinionated polyglot binding generator for Rust libraries
Documentation
#[allow(unused_imports)]
use napi::bindgen_prelude::{JsObjectValue, ToNapiValue, Unknown, Object};
#[allow(unused_imports)]
use napi::JsValue;

fn nodecontext_to_js_object<'e>(
    env: &'e napi::Env,
    ctx: &{{ context_type_path }},
) -> napi::Result<napi::bindgen_prelude::Object<'e>> {
    let mut obj = napi::bindgen_prelude::Object::new(env)?;
{{ context_field_lines }}
    Ok(obj)
}

pub struct {{ struct_name }} {
    env: napi::sys::napi_env,
    obj_ref: Option<napi::bindgen_prelude::ObjectRef<false>>,
}

impl std::fmt::Debug for {{ struct_name }} {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{{ struct_name }}")
    }
}

impl {{ struct_name }} {
    pub fn new(js_obj: napi::bindgen_prelude::Object<'_>) -> napi::Result<Self> {
        // SAFETY: Object<'_> is laid out as 3 pointer-sized words: [napi_env, napi_value, is_ref].
        // We extract the raw napi_env pointer so we can reconstruct an Env inside visitor
        // callbacks. The pointer is stable for the lifetime of the Node process.
        let env = unsafe {
            let raw: [*mut std::ffi::c_void; 3] = std::mem::transmute_copy(&js_obj);
            raw[0] as napi::sys::napi_env
        };
        // Create a persistent napi reference so the JS object survives across the
        // synchronous convert() call, regardless of HandleScope movement.
        let obj_ref = js_obj.create_ref::<false>()?;
        Ok(Self { env, obj_ref: Some(obj_ref) })
    }
}

impl Drop for {{ struct_name }} {
    fn drop(&mut self) {
        // Release the persistent reference so the JS object can be GC'd. unref takes
        // ownership; the Option lets us move out from &mut self in drop.
        if let Some(obj_ref) = self.obj_ref.take() {
            // self.env was captured from the napi_env that owns obj_ref.
            let env = napi::Env::from_raw(self.env);
            let _ = obj_ref.unref(&env);
        }
    }
}

// SAFETY: The visitor bridge stores an napi_ref (via ObjectRef), which is valid across
// threads as long as all napi:: operations using it happen on the original event loop
// thread where the reference was created. The Arc<Mutex<>> wrapper around the bridge
// ensures synchronous, single-threaded access during the convert() call.
unsafe impl Send for {{ struct_name }} {}
// SAFETY: see Send impl above.
unsafe impl Sync for {{ struct_name }} {}

impl {{ trait_path }} for {{ struct_name }} {
{{ method_impls }}
}