Expand description

Low level Rust bindings to the Erlang NIF API.

NIF Crate

A NIF module is built by creating a new crate that uses erlang_nif-sys as a dependency. (more)

NIF Functions

All NIF functions must have the following signature:

use rustler_sys::*;
fn my_nif(env: *mut ErlNifEnv,
          argc: c_int,
          args: *const ERL_NIF_TERM) -> ERL_NIF_TERM {
    // ...
}

NIF Module Initialization

For the Impatient

use rustler_sys::*;

nif_init!("my_nif_module",[
        ("my_nif_fun1", 1, my_nif_fun1),
        ("my_dirty_fun2", 1, my_dirty_fun2, ERL_NIF_DIRTY_JOB_CPU_BOUND)
    ],
    {load: my_load}
);

Details

The erlang_nif-sys analog of ERL_NIF_INIT() is nif_init! which has the following form:

nif_init!(module_name, [nif_funcs], {options})

module_name must be a string literal, for example "mynifmodule".

nif_funcs declares all the exported NIF functions for this module. Each entry is declared as

(name, arity, function, flags)

name is a string literal indicating the name of the function as seen from Erlang code. arity is an integer indicating how many parameter this function takes as seen from Erlang code. function is the Rust implementation of the NIF and must be of the form Fn(env: *mut ErlNifEnv, argc: c_int, args: *const ERL_NIF_TERM) -> ERL_NIF_TERM. This is usually a plain Rust function, but closures are permitted. flags is optional and allows you to specify if this NIF is to run on a dirty scheduler. See dirty NIFs in the Erlang docs.

The options are the NIF module initialization functions load, reload, upgrade, and unload. Each is optional and is specified in struct-init style if present. If no options are needed, the curly braces may be elided. Stub implementation of all these functions looks something like:

use rustler_sys::*;

nif_init!("mymod", [], {load: load, reload: reload, upgrade: upgrade, unload: unload});

fn load(env: *mut ErlNifEnv,
        priv_data: *mut *mut c_void,
        load_info: ERL_NIF_TERM)-> c_int { 0 }

fn reload(env: *mut ErlNifEnv,
          priv_data: *mut *mut c_void,
          load_info: ERL_NIF_TERM) -> c_int { 0 }

fn upgrade(env: *mut ErlNifEnv,
           priv_data: *mut *mut c_void,
           old_priv_data: *mut *mut c_void,
                      load_info: ERL_NIF_TERM) -> c_int { 0 }

fn unload(env: *mut ErlNifEnv,
          priv_data: *mut c_void) {}

Invoking NIF API

As with any Rust FFI call, NIF API calls must be wrapped in unsafe blocks. Below is an example of invoking NIF APIs along with an approach for dealing with the the args parameter.

use rustler_sys::*;
use std::mem;

fn native_add(env: *mut ErlNifEnv,
              argc: c_int,
              args: *const ERL_NIF_TERM) -> ERL_NIF_TERM {
    unsafe {
        let mut a: c_int = mem::uninitialized();
        let mut b: c_int = mem::uninitialized();
        if argc == 2 &&
           0 != enif_get_int(env, *args, &mut a) &&
           0 != enif_get_int(env, *args.offset(1), &mut b) {
            enif_make_int(env, a+b)
         }
         else {
            enif_make_badarg(env)
         }
    }
}

Re-exports

pub use crate::rustler_sys_api::*;

Modules

Macros

See enif_fprintf in the Erlang docs.

See enif_make_list in the Erlang docs.

See enif_make_tuple in the Erlang docs.

See enif_snprintf in the Erlang docs.

Create ErlNifFunc structure. Use inside nif_init!. (Deprecated)

Implement exported module init function needed by the Erlang runtime.

Platform specific NIF module initialization.

Wrapper to deliver NIF args as Rust slice.