1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
/*! Low level Rust bindings to the [Erlang NIF API](http://www.erlang.org/doc/man/erl_nif.html). # 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: ``` #[macro_use] extern crate erlang_nif_sys; use erlang_nif_sys::*; # fn main(){} //0 fn my_nif(env: *mut ErlNifEnv, argc: c_int, args: *const ERL_NIF_TERM) -> ERL_NIF_TERM { // ... # unsafe{enif_make_badarg(env)} } ``` # NIF Module Initialization ## For the Impatient ``` #[macro_use] extern crate erlang_nif_sys; use erlang_nif_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} ); # fn main(){} //1 # fn my_load(env: *mut ErlNifEnv, priv_data: *mut *mut c_void, load_info: ERL_NIF_TERM)-> c_int { 0 } # fn my_nif_fun1(_: *mut ErlNifEnv,_: c_int,args: *const ERL_NIF_TERM) -> ERL_NIF_TERM {unsafe{*args}} # fn my_dirty_fun2(_: *mut ErlNifEnv,_: c_int,args: *const ERL_NIF_TERM) -> ERL_NIF_TERM {unsafe{*args}} ``` ## Details The `erlang_nif-sys` analog of [`ERL_NIF_INIT()`](http://www.erlang.org/doc/man/erl_nif_init.html) 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 implentation 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](http://www.erlang.org/doc/man/erl_nif.html#dirty_nifs) in the Erlang docs. The `options` are the NIF module intialization functions [`load`](http://www.erlang.org/doc/man/erl_nif.html#load), [`reload`](http://www.erlang.org/doc/man/erl_nif.html#reload), [`upgrade`](http://www.erlang.org/doc/man/erl_nif.html#upgrade), and [`unload`](http://www.erlang.org/doc/man/erl_nif.html#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: ``` #[macro_use] extern crate erlang_nif_sys; use erlang_nif_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) {} # fn main(){} //2 ``` # 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. ``` extern crate erlang_nif_sys; use erlang_nif_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) } } } # fn main(){} //3 ``` */ // Don't throw warnings on NIF naming conventions #![allow(non_camel_case_types)] #[cfg(windows)] extern crate unreachable; #[macro_use] mod initmacro; pub mod erlang_nif_sys_api; pub use erlang_nif_sys_api::*;