Enum NapiThreadsafeFunctionReleaseMode

Source
#[repr(u32)]
pub enum NapiThreadsafeFunctionReleaseMode { Release = 0, Abort = 1, }
Expand description

§Nodex - Nodejs eXtension 🥳

Yet another crate to create native nodejs addons :)

This crate aims to make creating native nodejs addons very easy and comfortable.

click here: uuhan/nodex@dev to see the most recent developments.

§Platform Support

  • linux
  • macos
  • windows (>=0.2.1)

§Changelog

releases

§Usage

[lib]
crate-type = ["cdylib"]

[dependencies.nodex-api]
version = "0.2.3"
features = ["v8"]

The default napi version is set to v1, you can use other version with your need.

We have v1,v2,v3,…v8 versions.

Currently, nodex just reexports nodex-api:

[lib]
crate-type = ["cdylib"]

[dependencies.nodex]
version = "0.2.3"
features = ["v8"]

§Napi Level

§v1

  • NapiValueT::wrap::<T, Finalizer>() - Wraps a native instance, call finalizer when value is garbage-collected.
  • NapiValueT::remove_wrap::<T>() - Remove the wrapped native instance. The finalizer will not be called if the wrapped instance is removed.
  • NapiValueT::unwrap::<T>() - Access the wrapped instance.
  • NapiValueT::gc::<Finalizer>() - Hook fired when value is gabage-collected.

§v3

  • NapiEnv::add_cleanup_hook() - Do the cleanup when nodejs environment exits.

§v4

  • NapiThreadsafeFunction::<Data, const N: usize> - Thread safe function.

§v5

  • NapiValueT::finalizer() - Adds a napi_finalize callback which will be called when the JavaScript object is ready for gc.

§v6

  • NapiEnv::set_instance_data::<Data, Finalizer> - Set data to current agent.
  • NapiENv::get_instance_data::<Data> - Get Option<&mut Data> from current agent.

§v8

  • NapiEnv::add_async_cleanup_hook() - Do the cleanup when nodejs environment exits, asynchronous.

§Examples

§Init Module

simply define your module by:

use nodex::prelude::*;
nodex::napi_module!(init);
fn init(env: NapiEnv, exports: JsObject) -> NapiResult<()> {
    Ok(())
}

§Version Guard

make sure the node api version is large or equal than your compiled addon’s.

use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    nodex::napi_guard!(env.napi_version()?);
    Ok(())
}

§Nodejs Version & Napi Version

get the runtime version:

use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    let node_version = env.node_version()?;
    let napi_version = env.napi_version()?;
    Ok(())
}

§Define Js Variable

use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    // String & Symbol
    let label: JsSymbol = env.symbol()?;
    let name: JsString = env.string("")?;

    // Object
    let mut obj: JsObject = env.object()?;
    obj.set_property(name, env.null()?)?;

    // Function
    let func: JsFunction = env.func(move |this, (a1, a2, a3): (JsValue, JsValue, JsValue)| {
        let env = this.env();
        a1.as_function()?.call(this, ())?;
        a1.as_function()?.call(this, env.string("I am from rust world.")?)
    })?;

    let func: JsFunction = env.func(move |this, a1: JsFunction| {
        let env = this.env();
        a1.call(this, env.string("I am from rust world.")?)
    })?;

    let class: JsClass = env.class("myclass", |mut this, a1: JsNumber| {
        this.set_named_property("a1", a1)?;
        Ok(this)
    }, &[])?;

    // Error
    let error: JsError = JsError::error(env, "error", Some("code"))?;

    Ok(())
}

§Napi handle scope

use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    // napi handle scope
    let _scope: NapiHandleScope = env.handle_scope()?;
    let _escapable_scope: NapiEscapableHandleScope = env.escapable_handle_scope()?;
    Ok(())
}

§Napi cleanup hook

§sync
use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    env.add_cleanup_hook(|| {
        println!("clean hook fired");
        Ok(())
    })?;

    let hook_to_remove = env.add_cleanup_hook(|| {
        println!("clean hook fired");
        Ok(())
    })?;

    hook_to_remove.remove()?;
    Ok(())
}
§aync
use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    match env.add_async_cleanup_hook(|hook| {
        // DO SOME CLEANUP
        // NB: should call remove after done
        hook.remove()
    })? {
        Some(hook) => {
            // NB: also the hook can be removed before it is fired.
            hook.remove()?;
        }
        None => {}
    }

    Ok(())
}

§Set Property Descriptor

use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    let mut obj: JsObject = env.object()?;
    obj.define_properties(&[DescriptorValueBuilder::new()
        .with_utf8name("myvalue")
        .with_value(env.string("myvalue")?)
        .build()?])?;

    obj.define_properties(&[DescriptorMethodBuilder::new()
        .with_utf8name("mymethod")
        .with_method(move |this, ()| this.env().double(200.))
        .build()?])?;

    obj.define_properties(&[DescriptorAccessorBuilder::new()
        .with_utf8name("myaccessor")
        .with_getter(|this| this.env().double(100.))
        .with_setter(|_this: JsObject, n: JsNumber| {
            println!("setter: {}", n.get_value_int32()?);
            Ok(())
        })
        .build()?])?;

    Ok(())
}

§Create An Async Work

use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    // without shared state
    env.async_work(
        "my-test-async-task",
        (),
        move |_| {
            // you can do the hard work in the thread-pool context.
            // NB: js work is not allowed here.
            println!("execute async task");
        },
        move |_, status, _| {
            // you can do some js work in this context
            println!("[{}] complete async task", status);
            Ok(())
        },
    )?
    .queue()?;

    Ok(())
}

§gabage-collected hook

for napi less than 5, implement by napi_wrap, otherwise by napi_add_finalizer.

use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    let mut obj = env.object()?;
    obj.gc(move |_| {
        println!("obj garbage-collected");
        Ok(())
    });

    Ok(())
}

§Wrap native instance

use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    let mut obj = env.object()?;
    obj.wrap([1usize; 2], move |_, wrapped| {
        Ok(())
    })?;
    obj.unwrap::<[usize; 2]>()?; // access the wrapped instance
    obj.remove_wrap::<[usize; 2]>()?; // the finalizer will not be called
    Ok(())
}

§Thread safe function

require: napi >= 4

use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
    let tsfn = NapiThreadsafeFunction::<_, 0>::new(
        env,
        "tsfn-task",
        env.func(|this, a1: JsString| {
            println!("callback result: {}", a1.get()?);
            this.env().undefined()
        })?,
        // finalizer
        move |_| Ok(()),
        // js-callback
        move |f, data: String| {
            f.call(env.object()?, env.string(&data)?)?;
            Ok(())
        },
    )?;

    std::thread::spawn(move || {
        tsfn.non_blocking("hello, world - 1".into()).unwrap();
        tsfn.non_blocking("hello, world - 2".into()).unwrap();
        tsfn.release().unwrap();
    });
    Ok(())
}

§Promise for some heavy work

use nodex::prelude::*;
fn test(env: NapiEnv) -> NapiResult<()> {
let promise: JsPromise<JsString, JsError> = env.promise(
    move |result| {
        for i in 1..=3 {
            std::thread::sleep(std::time::Duration::from_secs(1));
            println!("[{}] Doing...", i);
        }

        *result = true;
    },
    move |promise, _, result| {
        let env = promise.env();
        if result {
            promise.resolve(env.string("the promise is resolved.")?)?;
        } else {
            promise.reject(env.error("the promise is rejected.")?)?;
        }
        Ok(())
    },
)?;
Ok(())
}
// the `promise.value()` can return to js world as a Promise

§Run script

use nodex::prelude::*;
fn script(env: NapiEnv) -> NapiResult<()> {
    let func: Function<JsUndefined> = env.run_script(
        r#"
            function hello() {
                console.log(this);
            }

            hello
        "#,
    )?;

    func.call(env.global()?.object(), ())?;
    Ok(())
}

§More

examples/demo

Run:

bash demo.sh

§How to participate in

§Code of conduct

cat >> .git/hooks/pre-push << EOF
#!/bin/sh

cargo fmt || exit
cargo clippy -- -D warnings || exit
EOF

chmod +x .git/hooks/pre-push

§TODO

  • ergonomical api design.
  • export the codebase from crates world, make it easy to call rust function from js world.
    • sweet syntax, like: #[nodex::function] fn foo()
  • import the huge codebase from npm world, make it easy to call js function from rust side.
    • sweet syntax, like: let lodash = nodex::import!(lodash);
  • nodejs async runtime to drive rust async code
    • async runtime for async rust
    • macros like: #[nodex::rt] async fn main(), so you can use nodejs to run any rust async-code.
      • node –require=main.node
      • rust code introspection with nodejs repl
  • cargo-nodex cargo subcommand to make ease of create nodejs addons, e.g. auto generate ts typings.
    • cargo nodex build
    • cargo nodex typings
    • cargo nodex package

§License

Licensed under either of

  • Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
  • MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option. napi_threadsafe_function_release_mode

Variants§

§

Release = 0

§

Abort = 1

Trait Implementations§

Source§

impl Clone for NapiThreadsafeFunctionReleaseMode

Source§

fn clone(&self) -> NapiThreadsafeFunctionReleaseMode

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for NapiThreadsafeFunctionReleaseMode

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl PartialEq for NapiThreadsafeFunctionReleaseMode

Source§

fn eq(&self, other: &NapiThreadsafeFunctionReleaseMode) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Copy for NapiThreadsafeFunctionReleaseMode

Source§

impl Eq for NapiThreadsafeFunctionReleaseMode

Source§

impl StructuralPartialEq for NapiThreadsafeFunctionReleaseMode

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.