Expand description
enif-ffi — raw FFI bindings to the Erlang NIF API (erl_nif).
A thin, 1:1, all-unsafe binding to the enif_* C API exported by the
BEAM. It is the foundation a safe NIF library is built on; it adds no
abstractions of its own.
§Naming
Every C prefix is dropped — enif_ (functions), ERL_NIF_ (the term type,
macros, constants), and ErlNif (everything else) — because the whole API
lives under the enif_ffi:: namespace and the prefix would be pure
redundancy:
ERL_NIF_TERM→Term,ErlNifEnv→Env,ErlNifBinary→Binaryenif_make_atom→make_atom,enif_is_atom→is_atomERL_NIF_SELECT_READ→SelectFlags::READ
A bare name that would collide with a Rust keyword or a std prelude item
takes a trailing underscore: ErlNifOption → Option_, enif_self →
self_.
The public surface is flat: everything is re-exported to the crate root.
Prefer namespaced use (enif_ffi::Term, enif_ffi::make_atom) over a glob
import.
§Who this is for
Most NIF authors want a safe library on top of this — writing NIFs by hand
against a raw, all-unsafe table is deliberate, low-level work. Reach for
enif-ffi directly when you are building that safe layer, or when you want
the bare enif_* surface with no abstraction in the way.
§A minimal NIF
A consumer touches three things: the C-ABI functions (the BEAM calling
convention), the Entry that registers them and carries the load-time
metadata, and nif_init! to define the entry point. The same source
compiles on Unix and Windows.
use enif_ffi::*;
use std::ffi::c_int;
// add(A, B) -> A + B — decode two integers, return their sum.
unsafe extern "C" fn nif_add(env: *mut Env, argc: c_int, argv: *const Term) -> Term {
if argc != 2 {
return unsafe { make_badarg(env) };
}
let args = unsafe { std::slice::from_raw_parts(argv, 2) };
let (mut a, mut b): (c_int, c_int) = (0, 0);
if unsafe { get_int(env, args[0], &mut a) } == 0
|| unsafe { get_int(env, args[1], &mut b) } == 0
{
return unsafe { make_badarg(env) };
}
unsafe { make_int(env, a.wrapping_add(b)) }
}
// mk_tuple() -> {ok, 42} — build a 2-tuple of an atom and an integer.
unsafe extern "C" fn nif_mk_tuple(env: *mut Env, _argc: c_int, _argv: *const Term) -> Term {
let ok = unsafe { make_atom(env, c"ok".as_ptr()) };
let n = unsafe { make_int(env, 42) };
unsafe { make_tuple2(env, ok, n) }
}
// Build the library descriptor: the function table plus the version and name
// metadata the BEAM reads at load. Both the table and the `Entry` must outlive
// the call, so they are leaked.
fn build_entry() -> *const Entry {
let funcs = vec![
Func { name: c"add".as_ptr(), arity: 2, fptr: nif_add, flags: 0 },
Func { name: c"mk_tuple".as_ptr(), arity: 0, fptr: nif_mk_tuple, flags: 0 },
]
.leak();
Box::leak(Box::new(Entry {
major: MAJOR_VERSION,
minor: MINOR_VERSION,
name: c"example".as_ptr(),
num_of_funcs: funcs.len() as c_int,
funcs: funcs.as_mut_ptr(),
load: None,
reload: None,
upgrade: None,
unload: None,
vm_variant: VM_VARIANT.as_ptr(),
options: 1,
sizeof_resource_type_init: std::mem::size_of::<ResourceTypeInit>(),
min_erts: MIN_ERTS_VERSION.as_ptr(),
}))
}
// Generates the platform-correct `nif_init` symbol the BEAM calls at load.
enif_ffi::nif_init!(build_entry);On the Erlang side, once the module has loaded the library:
example:add(2, 3). %=> 5
example:mk_tuple(). %=> {ok, 42}smoke_test/ in the repository is the full, CI-exercised version of this:
built and loaded into real BEAMs across every supported NIF version.
§Version support
The floor is NIF 2.15 (OTP 22) — always compiled. Newer API is opt-in through an additive feature ladder, each rung pulling in the one below:
nif_2_16— OTP 24nif_2_17— OTP 26nif_2_18— OTP 29
Because the rungs chain, the enabled set is always a contiguous prefix, so
each version-gated item carries exactly one #[cfg]. Enabling a rung means
“I require at least this OTP”; the symbols it adds are resolved at load time
and a BEAM older than the target will fail the load rather than misbehave.
Item-level version annotations and the gating boundaries are derived from the
tagged erl_nif header history (the otp-enif snapshot repo).
§Platform
Unix and Windows are both supported; the binding mechanism is chosen at
compile time. On Unix the enif_* table is resolved with dlsym at load;
on Windows the BEAM passes a callback struct to nif_init, which is stored
instead. nif_init! generates the correctly-typed entry point for the
target, so a NIF’s source is identical on both.
§Verification
Correctness rests on two checks rather than exhaustive per-symbol tests:
the enif_* table layout is audited against the tagged erl_nif header
history (every field version-gated and order-matched), and a smoke NIF is
built and loaded into real BEAMs across NIF 2.15–2.18 on both Unix and
Windows in CI, proving the binding resolves and dispatches the table on
every supported version.
Macros§
- nif_
init - Define the NIF library’s entry point.
Structs§
- Binary
- A binary’s bytes, as a size and data pointer.
- Cond
- An opaque condition variable handle.
- Entry
- The library descriptor the BEAM reads at load.
- Env
- A NIF environment that owns terms.
- Func
- The descriptor for a single exported NIF.
- IOQueue
- An opaque I/O queue handle.
- IOVec
- A scatter/gather I/O vector.
- MapIterator
- A cursor for iterating a map’s entries.
- Monitor
- A process-monitor handle.
- Mutex
- An opaque mutex handle.
- Pid
- A local process identifier.
- Port
- A port identifier.
- RWLock
- An opaque read/write lock handle.
- Resource
Flags - Create-or-take-over flags for registering a resource type.
- Resource
Type - A handle to a registered resource type.
- Resource
Type Init - Callback table for resource type registration.
- Select
Flags - Mode flags for
select. Combine with|. - SysIO
Vec - A single base/length I/O segment; on Unix this is
struct iovec. - SysInfo
- A snapshot of BEAM runtime information.
- Thread
Opts - Options for creating a thread.
- Unique
Integer - Flags shaping the result of
make_unique_integer. Combine with|.
Enums§
- Char
Encoding - Encoding for reading and writing atom and string bytes.
- Hash
- The hash algorithm selector for
hash. - MapIterator
Entry - Starting position for a map iterator.
- Option_
- The key selecting which runtime option
set_optionsets. - Term
Type - The canonical term types returned by
term_type. - Time
Unit - The unit of a
Timevalue.
Constants§
- BIN2TERM_
SAFE - Safe decoding for
binary_to_term: reject encoded atoms that don’t already exist. - DIRTY_
JOB_ CPU_ BOUND - Run on a dirty CPU scheduler.
- DIRTY_
JOB_ IO_ BOUND - Run on a dirty I/O scheduler.
- IOQ_
NORMAL - Normal I/O queue mode.
- MAJOR_
VERSION - The major NIF API version this build targets.
- MINOR_
VERSION - MIN_
ERTS_ VERSION - SELECT_
ERROR_ CANCELLED - A pending error
selectwas cancelled. - SELECT_
FAILED selectfailed to add the event to the poll set.- SELECT_
INVALID_ EVENT selectwas given an invalid event object.- SELECT_
NOTSUP - The requested
selectmode is not supported for the event object. - SELECT_
READ_ CANCELLED - A pending read
selectwas cancelled. - SELECT_
STOP_ CALLED select’s stop callback ran on the calling thread.- SELECT_
STOP_ SCHEDULED select’s stop callback was scheduled to run later.- SELECT_
WRITE_ CANCELLED - A pending write
selectwas cancelled. - THR_
DIRTY_ CPU_ SCHEDULER - Dirty CPU scheduler thread.
- THR_
DIRTY_ IO_ SCHEDULER - Dirty I/O scheduler thread.
- THR_
NORMAL_ SCHEDULER - Normal BEAM scheduler thread.
- THR_
UNDEFINED - Not a scheduler thread.
- TIME_
ERROR - Sentinel returned by the time functions on error.
- VM_
VARIANT - The VM variant the library is built for.
Functions§
- alloc⚠
- Allocates a block of memory from the BEAM allocator.
- alloc_
binary ⚠ - Allocates a new, mutable binary.
- alloc_
env ⚠ - Allocates a process-independent environment.
- alloc_
resource ⚠ - Allocates a reference-counted resource object.
- binary_
to_ ⚠term - Decodes a term from the external term format.
- clear_
env ⚠ - Clears a process-independent environment for reuse.
- compare⚠
- Orders two terms by Erlang term order.
- compare_
monitors ⚠ - Orders two monitor identifiers.
- compare_
pids ⚠ - Orders two pids by Erlang term order.
- cond_
broadcast ⚠ - Wakes all threads waiting on a condition variable.
- cond_
create ⚠ - Creates a condition variable.
- cond_
destroy ⚠ - Destroys a condition variable.
- cond_
name ⚠ - Returns a condition variable’s name.
- cond_
signal ⚠ - Wakes one thread waiting on a condition variable.
- cond_
wait ⚠ - Waits on a condition variable.
- consume_
timeslice ⚠ - Reports CPU time consumed and asks whether the NIF should yield.
- convert_
time_ ⚠unit - Converts a time value between units.
- cpu_
time ⚠ - Returns the current CPU time as a timestamp.
- demonitor_
process ⚠ - Cancels a process monitor held by a resource.
- dlopen⚠
- Loads a shared library.
- dlsym⚠
- Resolves a symbol in a shared library.
- dynamic_
resource_ ⚠call - Calls into a resource type defined by another module.
- equal_
tids ⚠ - Compares two thread identifiers.
- free⚠
- Frees memory from the BEAM allocator.
- free_
env ⚠ - Frees a process-independent environment.
- free_
iovec ⚠ - Frees an iovec from
inspect_iovec. - get_
atom ⚠ - Copies an atom’s name into a C buffer.
- get_
atom_ ⚠cache_ index - Returns an atom’s distribution cache index.
- get_
atom_ ⚠length - Reads the byte length of an atom’s name.
- get_
double ⚠ - Decodes a floating-point value from a term.
- get_int⚠
- Decodes a fixed-width signed integer from a term.
- get_
int64 ⚠ - Decodes a 64-bit signed integer from a term.
- get_
list_ ⚠cell - Splits a non-empty list into its head and tail.
- get_
list_ ⚠length - Reads the length of a proper list.
- get_
local_ ⚠pid - Extracts a node-local pid from a term.
- get_
local_ ⚠port - Extracts a node-local port from a term.
- get_
long ⚠ - Decodes a long integer from a term.
- get_
map_ ⚠size - Reads the number of pairs in a map.
- get_
map_ ⚠value - Looks up a key in a map.
- get_
resource ⚠ - Unwraps a resource object from a term.
- get_
string ⚠ - Copies an Erlang string into a C buffer.
- get_
string_ ⚠length - Measures the length of an Erlang string.
- get_
tuple ⚠ - Borrows the elements of a tuple.
- get_
uint ⚠ - Decodes an unsigned integer from a term.
- get_
uint64 ⚠ - Decodes a 64-bit unsigned integer from a term.
- get_
ulong ⚠ - Decodes an unsigned long integer from a term.
- getenv⚠
- Reads an OS environment variable.
- has_
pending_ ⚠exception - Tests whether the environment has a pending exception.
- hash⚠
- Hashes a term.
- init_
resource_ ⚠type - Registers a resource type, including a dyncall callback.
- inspect_
binary ⚠ - Inspects the contents of a binary term.
- inspect_
iolist_ ⚠as_ binary - Flattens an iolist into a contiguous binary.
- inspect_
iovec ⚠ - Converts a list of binaries into an iovec.
- ioq_
create ⚠ - Creates an I/O queue.
- ioq_deq⚠
- Removes bytes from the front of an I/O queue.
- ioq_
destroy ⚠ - Destroys an I/O queue.
- ioq_
enq_ ⚠binary - Appends a binary to an I/O queue.
- ioq_
enqv ⚠ - Appends an iovec to an I/O queue.
- ioq_
peek ⚠ - Borrows the queued data as an array of iovecs.
- ioq_
peek_ ⚠head - Borrows the first binary in an I/O queue.
- ioq_
size ⚠ - Returns the number of bytes queued.
- is_atom⚠
- Tests whether a term is an atom.
- is_
binary ⚠ - Tests whether a term is a binary.
- is_
current_ ⚠process_ alive - Tests whether the calling process is still alive.
- is_
empty_ ⚠list - Tests whether a term is the empty list.
- is_
exception ⚠ - Tests whether a term is a pending exception.
- is_fun⚠
- Tests whether a term is a fun.
- is_
identical ⚠ - Tests two terms for exact equality.
- is_list⚠
- Tests whether a term is a list.
- is_map⚠
- Tests whether a term is a map.
- is_
number ⚠ - Tests whether a term is a number.
- is_pid⚠
- Tests whether a term is a pid.
- is_
pid_ ⚠undefined - Tests whether a pid value is the undefined marker.
- is_port⚠
- Tests whether a term is a port.
- is_
port_ ⚠alive - Tests whether a port is alive.
- is_
process_ ⚠alive - Tests whether a process is alive.
- is_ref⚠
- Tests whether a term is a reference.
- is_
tuple ⚠ - Tests whether a term is a tuple.
- keep_
resource ⚠ - Adds a reference to a resource object.
- make_
atom ⚠ - Builds an atom from a Latin-1 C string.
- make_
atom_ ⚠len - Builds an atom from a length-counted Latin-1 string.
- make_
badarg ⚠ - Raises a
badargexception when the NIF returns. - make_
binary ⚠ - Builds a binary term from a mutable binary.
- make_
copy ⚠ - Deep-copies a term into another environment.
- make_
double ⚠ - Builds an Erlang float from a
double. - make_
existing_ ⚠atom - Looks up an already-existing atom by name.
- make_
existing_ ⚠atom_ len - Looks up an existing atom by a length-counted name.
- make_
int ⚠ - Builds an Erlang integer from a 32-bit signed value.
- make_
int64 ⚠ - Builds an Erlang integer from a signed 64-bit value.
- make_
list1 ⚠ - Builds a 1-element list.
- make_
list2 ⚠ - Builds a 2-element list.
- make_
list3 ⚠ - Builds a 3-element list.
- make_
list4 ⚠ - Builds a 4-element list.
- make_
list5 ⚠ - Builds a 5-element list.
- make_
list6 ⚠ - Builds a 6-element list.
- make_
list7 ⚠ - Builds a 7-element list.
- make_
list8 ⚠ - Builds an 8-element list.
- make_
list9 ⚠ - Builds a 9-element list.
- make_
list_ ⚠cell - Prepends an element to a list.
- make_
list_ ⚠from_ array - Builds a proper list from an array of terms.
- make_
long ⚠ - Builds an Erlang integer from a long value.
- make_
map_ ⚠from_ arrays - Builds a map from parallel key and value arrays.
- make_
map_ ⚠put - Returns a map with a key inserted or updated.
- make_
map_ ⚠remove - Returns a map with a key removed.
- make_
map_ ⚠update - Returns a map with an existing key’s value replaced.
- make_
monitor_ ⚠term - Builds a term identifying a monitor.
- make_
new_ ⚠atom - Creates an atom from a Latin-1 or UTF-8 C string.
- make_
new_ ⚠atom_ len - Creates an atom from a length-counted string.
- make_
new_ ⚠binary - Allocates a binary term and returns a writable pointer to its bytes.
- make_
new_ ⚠map - Creates an empty map.
- make_
pid ⚠ - Builds a pid term, or the atom
undefined. - make_
ref ⚠ - Creates a fresh, unique reference.
- make_
resource ⚠ - Wraps a resource object in an opaque term.
- make_
resource_ ⚠binary - Builds a binary term backed by a resource’s memory.
- make_
reverse_ ⚠list - Reverses a proper list.
- make_
string ⚠ - Builds a string as a list of character codepoints.
- make_
string_ ⚠len - Builds a string from a length-counted C string.
- make_
sub_ ⚠binary - Builds a sub-binary referencing part of another binary.
- make_
tuple1 ⚠ - Builds a 1-tuple.
- make_
tuple2 ⚠ - Builds a 2-tuple.
- make_
tuple3 ⚠ - Builds a 3-tuple.
- make_
tuple4 ⚠ - Builds a 4-tuple.
- make_
tuple5 ⚠ - Builds a 5-tuple.
- make_
tuple6 ⚠ - Builds a 6-tuple.
- make_
tuple7 ⚠ - Builds a 7-tuple.
- make_
tuple8 ⚠ - Builds an 8-tuple.
- make_
tuple9 ⚠ - Builds a 9-tuple.
- make_
tuple_ ⚠from_ array - Builds a tuple from an array of terms.
- make_
uint ⚠ - Builds an Erlang integer from an unsigned int.
- make_
uint64 ⚠ - Builds an Erlang integer from an unsigned 64-bit value.
- make_
ulong ⚠ - Builds an Erlang integer from an unsigned long value.
- make_
unique_ ⚠integer - Returns a unique integer.
- map_
iterator_ ⚠create - Creates an iterator over a map.
- map_
iterator_ ⚠destroy - Destroys a map iterator.
- map_
iterator_ ⚠get_ pair - Reads the key and value at the current position.
- map_
iterator_ ⚠is_ head - Tests whether an iterator is before the first entry.
- map_
iterator_ ⚠is_ tail - Tests whether an iterator is past the last entry.
- map_
iterator_ ⚠next - Advances an iterator to the next entry.
- map_
iterator_ ⚠prev - Moves an iterator to the previous entry.
- max_
atom_ ⚠cache_ index - Returns the largest possible atom cache index.
- monitor_
process ⚠ - Monitors a process on behalf of a resource.
- monotonic_
time ⚠ - Returns the current Erlang monotonic time.
- mutex_
create ⚠ - Creates a mutex.
- mutex_
destroy ⚠ - Destroys a mutex.
- mutex_
lock ⚠ - Locks a mutex, blocking until it is free.
- mutex_
name ⚠ - Returns a mutex’s name.
- mutex_
trylock ⚠ - Tries to lock a mutex without blocking.
- mutex_
unlock ⚠ - Unlocks a mutex.
- now_
time ⚠ - Returns an
erlang:now/0timestamp. - open_
resource_ ⚠type - Registers a resource type for the calling module.
- open_
resource_ ⚠type_ x - Registers a resource type with select and monitor callbacks.
- port_
command ⚠ - Sends a command to a port, asynchronously.
- priv_
data ⚠ - The library’s private data pointer.
- raise_
exception ⚠ - Raises an
errorexception with a given reason on return. - realloc⚠
- Resizes a block from the BEAM allocator.
- realloc_
binary ⚠ - Resizes a mutable binary.
- release_
binary ⚠ - Releases a mutable binary.
- release_
resource ⚠ - Drops one reference to a resource object.
- rwlock_
create ⚠ - Creates a read/write lock.
- rwlock_
destroy ⚠ - Destroys a read/write lock.
- rwlock_
name ⚠ - Returns a read/write lock’s name.
- rwlock_
rlock ⚠ - Takes a read lock, blocking until available.
- rwlock_
runlock ⚠ - Releases a read lock.
- rwlock_
rwlock ⚠ - Takes the write lock, blocking until exclusive.
- rwlock_
rwunlock ⚠ - Releases the write lock.
- rwlock_
tryrlock ⚠ - Tries to take a read lock without blocking.
- rwlock_
tryrwlock ⚠ - Tries to take the write lock without blocking.
- schedule_
nif ⚠ - Reschedules a NIF call onto a regular or dirty scheduler.
- select⚠
- Schedules or cancels asynchronous readiness notification for an OS event.
- select_
error ⚠ - Selects an event for error conditions, with a custom message.
- select_
read ⚠ - Selects an event for read readiness, with a custom message.
- select_
write ⚠ - Selects an event for write readiness, with a custom message.
- select_
x ⚠ - Selects on an OS event with an explicit notification message.
- self_⚠
- Records the calling process as a pid.
- send⚠
- Sends a message to a process.
- set_
option_ ⚠delay_ halt - Requests that runtime halt wait for this library’s NIF calls.
- set_
option_ ⚠on_ halt - Installs a callback run when the runtime halts.
- set_
option_ ⚠on_ unload_ thread - Installs a per-scheduler callback run when the library unloads.
- set_
pid_ ⚠undefined - Marks a pid value as undefined.
- sizeof_
resource ⚠ - Returns the byte size of a resource object.
- system_
info ⚠ - Fills in a system-information struct.
- term_
size ⚠ - Returns the heap size a term occupies.
- term_
to_ ⚠binary - Encodes a term to the external term format.
- term_
type ⚠ - Classifies a term by its top-level type.
- thread_
create ⚠ - Spawns a new BEAM-managed thread.
- thread_
exit ⚠ - Terminates the calling thread.
- thread_
join ⚠ - Waits for a thread to finish and collects its result.
- thread_
name ⚠ - Returns a thread’s name.
- thread_
opts_ ⚠create - Allocates a thread-options block.
- thread_
opts_ ⚠destroy - Frees a thread-options block.
- thread_
self ⚠ - Returns the calling thread’s identifier.
- thread_
type ⚠ - Returns the type of the calling thread.
- time_
offset ⚠ - Returns the offset from monotonic time to system time.
- tsd_get⚠
- Reads the calling thread’s value for a key.
- tsd_
key_ ⚠create - Creates a thread-specific data key.
- tsd_
key_ ⚠destroy - Destroys a thread-specific data key.
- tsd_set⚠
- Stores the calling thread’s value for a key.
- whereis_
pid ⚠ - Looks up a registered process by name.
- whereis_
port ⚠ - Looks up a registered port by name.