Skip to main content

Crate enif_ffi

Crate enif_ffi 

Source
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_TERMTerm, ErlNifEnvEnv, ErlNifBinaryBinary
  • enif_make_atommake_atom, enif_is_atomis_atom
  • ERL_NIF_SELECT_READSelectFlags::READ

A bare name that would collide with a Rust keyword or a std prelude item takes a trailing underscore: ErlNifOptionOption_, enif_selfself_.

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 24
  • nif_2_17 — OTP 26
  • nif_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.
ResourceFlags
Create-or-take-over flags for registering a resource type.
ResourceType
A handle to a registered resource type.
ResourceTypeInit
Callback table for resource type registration.
SelectFlags
Mode flags for select. Combine with |.
SysIOVec
A single base/length I/O segment; on Unix this is struct iovec.
SysInfo
A snapshot of BEAM runtime information.
ThreadOpts
Options for creating a thread.
UniqueInteger
Flags shaping the result of make_unique_integer. Combine with |.

Enums§

CharEncoding
Encoding for reading and writing atom and string bytes.
Hash
The hash algorithm selector for hash.
MapIteratorEntry
Starting position for a map iterator.
Option_
The key selecting which runtime option set_option sets.
TermType
The canonical term types returned by term_type.
TimeUnit
The unit of a Time value.

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 select was cancelled.
SELECT_FAILED
select failed to add the event to the poll set.
SELECT_INVALID_EVENT
select was given an invalid event object.
SELECT_NOTSUP
The requested select mode is not supported for the event object.
SELECT_READ_CANCELLED
A pending read select was 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 select was 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 badarg exception 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/0 timestamp.
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 error exception 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.

Type Aliases§

Event
An OS event handle for use with select.
IOQueueOpts
Creation mode for an I/O queue.
TSDKey
A thread-specific data key.
Term
Any Erlang term, as an opaque tagged word.
Tid
A thread identifier.
Time
A time value in BEAM time units.