3 unstable releases

0.2.1 Oct 15, 2020
0.2.0 Apr 24, 2020
0.1.0 Feb 4, 2020
Download history 5/week @ 2020-07-07 6/week @ 2020-07-14 3/week @ 2020-07-21 4/week @ 2020-07-28 4/week @ 2020-08-04 12/week @ 2020-08-11 8/week @ 2020-08-18 9/week @ 2020-08-25 19/week @ 2020-09-01 6/week @ 2020-09-08 3/week @ 2020-09-15 15/week @ 2020-09-22 83/week @ 2020-09-29 78/week @ 2020-10-06 21/week @ 2020-10-13 8/week @ 2020-10-20

83 downloads per month
Used in node-bindgen

Apache-2.0

7KB
106 lines

node-bindgen

Easy way to write native Node.js module using idiomatic Rust

Features

  • Easy: Just write idiomatic Rust code, node-bindgen take care of generating Node.js FFI wrapper codes.
  • Safe: Node.js arguments are checked automatically based on Rust types.
  • Async: Support Async Rust. Async codes are translated into Node.js promises.
  • Class: Rust struct can be access using Node.js classes.
  • Stream: Implement Node.js stream using Rust
  • N-API: Use Node.js N-API which means you don't have to recompile your module.

Compatibility with Node.js version

This project uses v5 of Node N-API. Please see following compatibility matrix.

Following OS are supported:

  • Linux
  • MacOs
  • Windows

Why node-bindgen?

Writing native node-js requires lots of boiler plate code. Node-bindgen generates external "C" glue code from rust code including native module registration. This make it writing node-js module easy and fun.

Node-bi

Getting started

CLI Installation

Install nj-cli command line which will be used to generate native library.

cargo install nj-cli

This is one time step.

Configuring Cargo.toml

Add two dependencies to your projects' Cargo.toml.

Add node-bindgen as a regular dependency (as below):

[dependencies]
node-bindgen = { version = "2.1.1" }

Then add node-bindgen's procedure macro to your build-dependencies as below:

[build-dependencies]
node-bindgen = { version = "2.1.1", features = ["build"] }

Then update crate type to cdylib to generate node.js compatible native module:

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

Example

A simple functional example which add two integers. Noticed that you don't need to worry about JS conversion.


use node_bindgen::derive::node_bindgen;

/// add two integer
#[node_bindgen]
fn sum(first: i32, second: i32) -> i32 {        
    first + second
}

Building native library

To build node.js library, using nj-cli to build:

nj-cli build

This will generate Node.js module in "./dist" folder.

Using in Node.js

Then in the Node.js, rust function can invoked as normal node.js function:

$ node
Welcome to Node.js v14.0.0.
Type ".help" for more information.
> let addon = require('./dist');
undefined
> addon.sum(2,3)
5
> 

Features

Function name or method can be renamed instead of default mapping

#[node_bindgen(name="multiply")]
fn mul(first: i32,second: i32) -> i32 {        
    first * second 
}

Rust function mul is re-mapped as multiply

Optional argument

Argument can be skipped if it is marked as optional

#[node_bindgen]
fn sum(first: i32, second: Option<i32>) -> i32 {        
    first + second.unwrap_or(0)
}

Then sum can be invoked as sum(10) or sum(10,20)

Callback

JS callback are mapped as Rust closure

#[node_bindgen]
fn hello<F: Fn(String)>(first: f64, second: F) {

    let msg = format!("argument is: {}", first);

    second(msg);
}

from node:

let addon = require('./dist');

addon.hello(2,function(msg){
  assert.equal(msg,"argument is: 2");
  console.log(msg);  // print out argument is 2
});

Callback are supported in Async rust as well.

Support for Async Rust

Async rust function is mapped to Node.js promise.


use std::time::Duration;
use flv_future_aio::time::sleep;
use node_bindgen::derive::node_bindgen;


#[node_bindgen]
async fn hello(arg: f64) -> f64 {
    println!("sleeping");
    sleep(Duration::from_secs(1)).await;
    println!("woke and adding 10.0");
    arg + 10.0
}
let addon = require('./dist');

addon.hello(5).then((val) => {
  console.log("future value is %s",val);
});

JavaScript class

JavaScript class is supported.


struct MyClass {
    val: f64,
}


#[node_bindgen]
impl MyClass {

    #[node_bindgen(constructor)]
    fn new(val: f64) -> Self {
        Self { val }
    }

    #[node_bindgen]
    fn plus_one(&self) -> f64 {
        self.val + 1.0
    }

    #[node_bindgen(getter)]
    fn value(&self) -> f64 {
        self.val
    }
}
let addon = require('./dist');
const assert = require('assert');

let obj = new addon.MyObject(10);
assert.equal(obj.value,10,"verify value works");
assert.equal(obj.plusOne(),11);

There are more features in the examples folder

Contributing

If you'd like to contribute to the project, please read our Contributing guide.

License

This project is licensed under the Apache license.

Dependencies

~0–3MB
~73K SLoC