COOKIES! This blog uses cookies!
I am completely out of control of cookies here, otherwise I would have disabled them (it is controlled by the platform).
If you don't like cookies and being tracked please leave this blog immediately.

Showing posts with label Rust. Show all posts
Showing posts with label Rust. Show all posts

Tuesday, 26 April 2016

Call Rust from NodeJS via cross-platform C ABI with RuNo bridge

The RuNo bridge is a command line tool which generates C++ code for NodeJS addon from Rust code or from JSON definition (with JSON definition it should work with any C ABI compatible library, of course when implemented functionality is enough).

I've implemeted this tool after my last research on calling Rust from Node JS.

The parser of RuNo bridge does not do magical deep analysis of code, it just detects the following signatures in your code:

#[no_mangle]

pub extern "C" fn ...


it does not require any C++ knowledge from developer if you use primitives mentioned above and your Rust ABI interface complies with simple requirements:

  • All your ABI functoins should be listed in one Rust file;
  • Your library should use crate libc;
  • Each ABI function should be preceeded with #[no_mangle];
  • Each ABI function should be prefixed with pub extern "C";
  • ABI Functions should only take params of c_int,c_float,c_double or *c_char (as a C string with EOF);
  • ABI Functions should return either one of c_int,c_float,c_double or *c_char (as a C string with EOF)
It is tested on Windows, Mac OS and Ubuntu, however it has some limitations developer should know:


The package itself does not need Rust or C++ with node-gyp, it just emits a C++ source file.

However in order to build the source code, rust and C++ compiler should be compatible with NodeJS version installed. It is particularly important on Windows, where Rust target should be MSVC not GNU. For example, if one using 32 bit NodeJS on Windows this one should use target i686-pc-windows-msvc, if 64 bit Node then Rust should be configured with x86_64-pc-windows-msvc compile target. The same about C++: Everything is mostrly smooth on platforms with GCC, and a bit painful with MS Visual C++, please refer to node-gyp installation instructions for details.

You can find simple usage examples on the github: https://github.com/andruhon/runo-bridge-example

I will appreciate any comments or contribution.

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...