Friday 26 February 2016

Call Rust from NodeJS via cross-platform C ABI

Rust language is quite elegant and looks like a decent replacement to C. There are already many useful packages in Crates available. It is quite good for developing libraries.

Let’s try to develop a Rust addon for NodeJS. It is possible to use node-ffi to call Rust from NodeJS, however FFI is very slow to init [results]. Node/V8 itself is written in C++ and it is possible to build custom C++ extensions and link the Rust library via the C ABI almost at no performance cost !

You can go directly to more complex example on github, if you can’t wait:
One critical moment to note: Rust and VC++ compilers should be of the same architecture as target NodeJS. Say if one using 32 bit NodeJS on windows one should use target i686-pc-windows-msvc, if 64bt Node then Rust should be configured with x86_64-pc-windows-msvc compile target. For linux x86_64-linux-gnu or i686-linux-gnu appropriately.

C++
#include <node.h>

using namespace v8;

extern "C" {
   extern int32_t add_in_rust(int32_t input, int32_t input);
}

void add_in_rust_wrapper(const FunctionCallbackInfo<Value>& args) {
   Isolate* isolate = Isolate::GetCurrent();
   HandleScope scope(isolate);
   int32_t value1 = args[0]->NumberValue();
   int32_t value2 = args[1]->NumberValue();
   args.GetReturnValue().Set(Number::New(isolate, add_in_rust(value1, value2)));
}

void init(Handle<Object> exports) {
   NODE_SET_METHOD(exports, "function_in_rust", add_in_rust_wrapper);
}

NODE_MODULE(addon, init)

Rust
#[no_mangle]
pub extern "C" fn fibonacci(v1: i32, v2: i32) -> i32 {
    v1 + v2
}
I used 32 bit int here, to simplify the example, however it is possible to accept and return `c_int` with crate libc, like that:
extern crate libc;
use libc::c_int;
//use `c_int` as platform int primitive, and ordinary `int` in the C++ addon.


Have a look at my examples set, to find something more useful than just an int:

https://github.com/andruhon/rust-in-node-examples , which generally contains following things:
  • int to int function
  • string to string function
  • numeric array to numeric array function
  • void to struct as an object
  • struct as object to bool
  • callbacks and mutable state

Other options:

https://github.com/rustbridge/neon/ - it is possible to do quite a lot with Neon, however it is more difficult than FFI because in Rust you have to be aware of underlying V8 types and perform manipulations with them. Neon also has platform compatibility issues and a bit overengineered on my opinion.

https://github.com/andruhon/runo-bridge - the command line tool: you feed Rust souce file with `no_mangle extern "C"` functions, or interface definition as a JSON and it will generate some C++ boilerplate code for addon. It just a prototype, which accepts/returns only `void`, `int`, `bool` and `*char`(C string) at a moment. I’ll keep improving it.


A few more articles on integrating Rust with NodeJS coming soon...