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.
[x] linux
[x] macos
[x] windows (>=0.1.6)
```toml [lib] crate-type = ["cdylib"]
[dependencies.nodex-api] version = "0.2.0" 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:
```toml [lib] crate-type = ["cdylib"]
[dependencies.nodex] version = "0.2.0" features = ["v8"] ```
simply define your module by:
rust
use nodex::prelude::*;
nodex::napi_module!(init);
fn init(env: NapiEnv, exports: JsObject) -> NapiResult<()> {
Ok(())
}
make sure the node api version is large or equal than your compiled addon's.
rust
use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
nodex::napi_guard!(env.napi_version()?);
Ok(())
}
get the runtime version:
rust
use nodex::prelude::*;
fn env(env: NapiEnv) -> NapiResult<()> {
let node_version = env.node_version()?;
let napi_version = env.napi_version()?;
Ok(())
}
```rust 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(())
} ```
rust
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(())
}
```rust use nodex::prelude::*; fn env(env: NapiEnv) -> NapiResult<()> { env.addcleanuphook(|| { println!("clean hook fired"); Ok(()) })?;
let hook_to_remove = env.add_cleanup_hook(|| {
println!("clean hook fired");
Ok(())
})?;
hook_to_remove.remove()?;
Ok(())
} ```
```rust use nodex::prelude::*; fn env(env: NapiEnv) -> NapiResult<()> { match env.addasynccleanup_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(())
} ```
```rust use nodex::prelude::*; fn env(env: NapiEnv) -> NapiResult<()> { let mut obj: JsObject = env.object()?; obj.defineproperties(&[DescriptorValueBuilder::new() .withutf8name("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(())
} ```
```rust use nodex::prelude::*; fn env(env: NapiEnv) -> NapiResult<()> { // without shared state env.asyncwork( "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(())
} ```
for napi less than 5, implement by napiwrap, otherwise by napiadd_finalizer.
```rust use nodex::prelude::*; fn env(env: NapiEnv) -> NapiResult<()> { let mut obj = env.object()?; obj.gc(move |_| { println!("obj garbage-collected"); Ok(()) });
Ok(())
} ```
rust
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(())
}
require: napi >= 4
```rust 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(())
} ```
```rust
use nodex::prelude::*;
fn test(env: NapiEnv) -> NapiResult<()> {
let promise: JsPromise
*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
```
```rust
use nodex::prelude::*;
fn script(env: NapiEnv) -> NapiResult<()> {
let func: Function
hello
"#,
)?;
func.call(env.global()?.cast(), ())?;
Ok(())
} ```
Run:
bash
bash demo.sh
```bash cat >> .git/hooks/pre-push << EOF
cargo fmt || exit cargo clippy -- -D warnings || exit EOF
chmod +x .git/hooks/pre-push ```
Licensed under either of
at your option.