enif_ffi/api.rs
1//! The `enif_*` wrapper functions — the public API of the crate.
2//!
3//! Each is a thin, `#[inline]`, all-`unsafe` forwarder to the corresponding
4//! pointer in the resolved [`api`] table, with the `enif_` prefix dropped.
5//! [`init`](crate::init) must have run first.
6//!
7//! Functions added after the 2.15 floor are gated behind their rung. The C
8//! macros that have no exported symbol (`make_tupleN`, `make_listN`,
9//! `select_read`/`write`/`error`, `make_pid`, `compare_pids`, the per-option
10//! `set_option_*`) are reimplemented here in terms of the real functions they
11//! expand to.
12//!
13//! The variadic `printf` family (`enif_fprintf`/`snprintf`/`vfprintf`/
14//! `vsnprintf`) is intentionally not wrapped — Rust cannot forward C varargs or
15//! a `va_list` — though their slots are kept in the table for ABI order.
16
17#![allow(clippy::missing_safety_doc)]
18
19use std::ffi::{c_char, c_int, c_long, c_uint, c_ulong, c_void};
20
21use crate::ffi::api;
22use crate::types::*;
23
24// ===========================================================================
25// NIF 0.1 / 1.0 — core term, binary, integer, atom, list/tuple
26// ===========================================================================
27
28/// The library's private data pointer.
29///
30/// Returns the pointer last stored through the `*priv_data` out-parameter of the
31/// module's `load` or `upgrade` callback, or null if none was set. The same
32/// pointer is shared by every NIF call into the library.
33///
34/// [`enif_priv_data`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_priv_data) — NIF 1.0 — OTP R13B04
35#[inline]
36pub unsafe fn priv_data(env: *mut Env) -> *mut c_void {
37 unsafe { (api().priv_data)(env) }
38}
39
40/// Allocates a block of memory from the BEAM allocator.
41///
42/// Returns a pointer to at least `size` bytes, or null on failure. The block is
43/// owned by the caller and is not garbage-collected; release it with [`free`].
44///
45/// [`enif_alloc`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_alloc) — NIF 0.1 — OTP R13B03
46#[inline]
47pub unsafe fn alloc(size: usize) -> *mut c_void {
48 unsafe { (api().alloc)(size) }
49}
50
51/// Frees memory from the BEAM allocator.
52///
53/// Releases a block previously returned by [`alloc`] or [`realloc`]. Passing a
54/// pointer not obtained from those, or freeing the same block twice, is
55/// undefined behavior.
56///
57/// [`enif_free`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_free) — NIF 0.1 — OTP R13B03
58#[inline]
59pub unsafe fn free(ptr: *mut c_void) {
60 unsafe { (api().free)(ptr) }
61}
62
63/// Tests whether a term is an atom.
64///
65/// Returns a non-zero value if `term` is an atom, `0` otherwise.
66///
67/// [`enif_is_atom`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_atom) — NIF 1.0 — OTP R13B04
68#[inline]
69pub unsafe fn is_atom(env: *mut Env, term: Term) -> c_int {
70 unsafe { (api().is_atom)(env, term) }
71}
72
73/// Tests whether a term is a binary.
74///
75/// Returns a non-zero value if `term` is a binary, `0` otherwise.
76///
77/// [`enif_is_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_binary) — NIF 0.1 — OTP R13B03
78#[inline]
79pub unsafe fn is_binary(env: *mut Env, term: Term) -> c_int {
80 unsafe { (api().is_binary)(env, term) }
81}
82
83/// Tests whether a term is a reference.
84///
85/// Returns a non-zero value if `term` is a reference — as made by [`make_ref`]
86/// or `erlang:make_ref/0` — and `0` otherwise.
87///
88/// [`enif_is_ref`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_ref) — NIF 1.0 — OTP R13B04
89#[inline]
90pub unsafe fn is_ref(env: *mut Env, term: Term) -> c_int {
91 unsafe { (api().is_ref)(env, term) }
92}
93
94/// Inspects the contents of a binary term.
95///
96/// On success fills `bin` with the byte count and a read-only data pointer for
97/// `bin_term` and returns a non-zero value; returns `0` if `bin_term` is not a
98/// binary. The data is valid for the rest of the NIF call and needs no release
99/// unless it is later grown into an owned binary with [`realloc_binary`].
100///
101/// [`enif_inspect_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_inspect_binary) — NIF 0.1 — OTP R13B03
102#[inline]
103pub unsafe fn inspect_binary(env: *mut Env, bin_term: Term, bin: *mut Binary) -> c_int {
104 unsafe { (api().inspect_binary)(env, bin_term, bin) }
105}
106
107/// Allocates a new, mutable binary.
108///
109/// Allocates `size` bytes and initializes `bin` to refer to them, returning a
110/// non-zero value on success or `0` on failure. The binary is owned by the
111/// caller until it is handed to a term with [`make_binary`] or discarded with
112/// [`release_binary`].
113///
114/// [`enif_alloc_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_alloc_binary) — NIF 0.1 — OTP R13B03
115#[inline]
116pub unsafe fn alloc_binary(size: usize, bin: *mut Binary) -> c_int {
117 unsafe { (api().alloc_binary)(size, bin) }
118}
119
120/// Resizes a mutable binary.
121///
122/// Changes `bin` to `size` bytes, preserving the existing data up to the smaller
123/// of the two lengths. If `bin` currently refers to read-only data it is left
124/// untouched and a fresh mutable copy is assigned in its place. Returns a
125/// non-zero value on success or `0` on failure.
126///
127/// [`enif_realloc_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_realloc_binary) — NIF 1.0 — OTP R13B04
128#[inline]
129pub unsafe fn realloc_binary(bin: *mut Binary, size: usize) -> c_int {
130 unsafe { (api().realloc_binary)(bin, size) }
131}
132
133/// Releases a mutable binary.
134///
135/// Frees a binary previously initialized by [`alloc_binary`] or
136/// [`realloc_binary`] that has not been transferred to a term with
137/// [`make_binary`]. Do not release a binary obtained from [`inspect_binary`].
138///
139/// [`enif_release_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_release_binary) — NIF 0.1 — OTP R13B03
140#[inline]
141pub unsafe fn release_binary(bin: *mut Binary) {
142 unsafe { (api().release_binary)(bin) }
143}
144
145/// Decodes a fixed-width signed integer from a term.
146///
147/// If `term` is an integer that fits in a C `int`, writes it through `ip` and
148/// returns a non-zero value; otherwise leaves `*ip` untouched and returns `0`
149/// (a float, a non-integer, or a bignum that overflows the range).
150///
151/// [`enif_get_int`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_int) — NIF 0.1 — OTP R13B03
152#[inline]
153pub unsafe fn get_int(env: *mut Env, term: Term, ip: *mut c_int) -> c_int {
154 unsafe { (api().get_int)(env, term, ip) }
155}
156
157/// Decodes an unsigned long integer from a term.
158///
159/// If `term` is a non-negative integer that fits in a C `unsigned long`, writes
160/// it through `ip` and returns a non-zero value; otherwise leaves `*ip`
161/// untouched and returns `0`.
162///
163/// [`enif_get_ulong`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_ulong) — NIF 0.1 — OTP R13B03
164#[inline]
165pub unsafe fn get_ulong(env: *mut Env, term: Term, ip: *mut c_ulong) -> c_int {
166 unsafe { (api().get_ulong)(env, term, ip) }
167}
168
169/// Decodes a floating-point value from a term.
170///
171/// If `term` is a float, writes it through `dp` and returns a non-zero value;
172/// otherwise leaves `*dp` untouched and returns `0`. Integer terms are not
173/// accepted.
174///
175/// [`enif_get_double`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_double) — NIF 1.0 — OTP R13B04
176#[inline]
177pub unsafe fn get_double(env: *mut Env, term: Term, dp: *mut f64) -> c_int {
178 unsafe { (api().get_double)(env, term, dp) }
179}
180
181/// Splits a non-empty list into its head and tail.
182///
183/// If `list` is a non-empty list, writes its first element through `head` and
184/// the remainder through `tail` and returns a non-zero value; returns `0` for
185/// the empty list or a non-list term.
186///
187/// [`enif_get_list_cell`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_list_cell) — NIF 0.1 — OTP R13B03
188#[inline]
189pub unsafe fn get_list_cell(env: *mut Env, list: Term, head: *mut Term, tail: *mut Term) -> c_int {
190 unsafe { (api().get_list_cell)(env, list, head, tail) }
191}
192
193/// Borrows the elements of a tuple.
194///
195/// If `term` is a tuple, sets `array` to a read-only pointer to its elements and
196/// `arity` to their count, returning a non-zero value; returns `0` otherwise.
197/// Element N is `(*array)[N-1]`, and the array is valid for the rest of the NIF
198/// call.
199///
200/// [`enif_get_tuple`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_tuple) — NIF 1.0 — OTP R13B04
201#[inline]
202pub unsafe fn get_tuple(
203 env: *mut Env,
204 term: Term,
205 arity: *mut c_int,
206 array: *mut *const Term,
207) -> c_int {
208 unsafe { (api().get_tuple)(env, term, arity, array) }
209}
210
211/// Tests two terms for exact equality.
212///
213/// Returns a non-zero value if `lhs` and `rhs` are identical, matching the
214/// Erlang `=:=` operator — so the integer `1` and the float `1.0` are *not*
215/// identical.
216///
217/// [`enif_is_identical`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_identical) — NIF 1.0 — OTP R13B04
218#[inline]
219pub unsafe fn is_identical(lhs: Term, rhs: Term) -> c_int {
220 unsafe { (api().is_identical)(lhs, rhs) }
221}
222
223/// Orders two terms by Erlang term order.
224///
225/// Returns a negative, zero, or positive value according to whether `lhs` sorts
226/// before, equal to, or after `rhs` under the standard term order — the
227/// `<`/`=<`/`>`/`>=` and arithmetic `==` operators, not `=:=`.
228///
229/// [`enif_compare`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_compare) — NIF 1.0 — OTP R13B04
230#[inline]
231pub unsafe fn compare(lhs: Term, rhs: Term) -> c_int {
232 unsafe { (api().compare)(lhs, rhs) }
233}
234
235/// Builds a binary term from a mutable binary.
236///
237/// Transfers ownership of `bin`'s data into a new binary term and returns it.
238/// After the call `bin` is read-only for the rest of the NIF call and must not
239/// be passed to [`release_binary`].
240///
241/// [`enif_make_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_binary) — NIF 0.1 — OTP R13B03
242#[inline]
243pub unsafe fn make_binary(env: *mut Env, bin: *mut Binary) -> Term {
244 unsafe { (api().make_binary)(env, bin) }
245}
246
247/// Raises a `badarg` exception when the NIF returns.
248///
249/// Associates a pending `badarg` with `env`; once invoked, the runtime raises
250/// `badarg` on return regardless of the term the NIF actually returns. The
251/// returned term is a convenience for returning directly. For arbitrary
252/// exception terms see [`raise_exception`].
253///
254/// [`enif_make_badarg`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_badarg) — NIF 0.1 — OTP R13B03
255#[inline]
256pub unsafe fn make_badarg(env: *mut Env) -> Term {
257 unsafe { (api().make_badarg)(env) }
258}
259
260/// Builds an Erlang integer from a 32-bit signed value.
261///
262/// Constructs the integer term in `env`; always succeeds. For values outside the
263/// `c_int` range use [`make_int64`] or [`make_uint64`].
264///
265/// [`enif_make_int`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_int) — NIF 0.1 — OTP R13B03
266#[inline]
267pub unsafe fn make_int(env: *mut Env, i: c_int) -> Term {
268 unsafe { (api().make_int)(env, i) }
269}
270
271/// Builds an Erlang integer from an unsigned long value.
272///
273/// Constructs the integer term in `env`; always succeeds.
274///
275/// [`enif_make_ulong`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_ulong) — NIF 0.1 — OTP R13B03
276#[inline]
277pub unsafe fn make_ulong(env: *mut Env, i: c_ulong) -> Term {
278 unsafe { (api().make_ulong)(env, i) }
279}
280
281/// Builds an Erlang float from a `double`.
282///
283/// Constructs the float term in `env`. If the value is infinite or NaN — which
284/// Erlang floats cannot represent — a `badarg` is raised on return, as if via
285/// [`make_badarg`].
286///
287/// [`enif_make_double`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_double) — NIF 1.0 — OTP R13B04
288#[inline]
289pub unsafe fn make_double(env: *mut Env, d: f64) -> Term {
290 unsafe { (api().make_double)(env, d) }
291}
292
293/// Builds an atom from a Latin-1 C string.
294///
295/// Creates, or reuses, the atom named by the NUL-terminated `name`, interpreted
296/// as ISO Latin-1. A name longer than the 255-character atom limit raises
297/// `badarg` on return. For a length-counted name see [`make_atom_len`].
298///
299/// [`enif_make_atom`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_atom) — NIF 0.1 — OTP R13B03
300#[inline]
301pub unsafe fn make_atom(env: *mut Env, name: *const c_char) -> Term {
302 unsafe { (api().make_atom)(env, name) }
303}
304
305/// Looks up an already-existing atom by name.
306///
307/// If an atom named by the NUL-terminated `name`, in the given [`CharEncoding`],
308/// already exists, writes it through `atom` and returns a non-zero value; returns
309/// `0` without creating one otherwise. Useful to avoid growing the atom table
310/// from untrusted input.
311///
312/// [`enif_make_existing_atom`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_existing_atom) — NIF 1.0 — OTP R13B04
313#[inline]
314pub unsafe fn make_existing_atom(
315 env: *mut Env,
316 name: *const c_char,
317 atom: *mut Term,
318 encoding: CharEncoding,
319) -> c_int {
320 unsafe { (api().make_existing_atom)(env, name, atom, encoding) }
321}
322
323/// Prepends an element to a list.
324///
325/// Builds the cons cell `[head | tail]` in `env` and returns it. `tail` need not
326/// be a proper list.
327///
328/// [`enif_make_list_cell`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list_cell) — NIF 0.1 — OTP R13B03
329#[inline]
330pub unsafe fn make_list_cell(env: *mut Env, head: Term, tail: Term) -> Term {
331 unsafe { (api().make_list_cell)(env, head, tail) }
332}
333
334/// Builds a string as a list of character codepoints.
335///
336/// Creates the Erlang string for the NUL-terminated `string`, in the given
337/// [`CharEncoding`], and returns it as a list of integer codepoints.
338///
339/// [`enif_make_string`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_string) — NIF 0.1 — OTP R13B03
340#[inline]
341pub unsafe fn make_string(env: *mut Env, string: *const c_char, encoding: CharEncoding) -> Term {
342 unsafe { (api().make_string)(env, string, encoding) }
343}
344
345/// Creates a fresh, unique reference.
346///
347/// Returns a new reference term bound to `env`, equivalent to
348/// `erlang:make_ref/0`.
349///
350/// [`enif_make_ref`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_ref) — NIF 1.0 — OTP R13B04
351#[inline]
352pub unsafe fn make_ref(env: *mut Env) -> Term {
353 unsafe { (api().make_ref)(env) }
354}
355
356// ===========================================================================
357// NIF 1.0 — thread primitives
358// ===========================================================================
359
360/// Creates a mutex.
361///
362/// Returns a new mutex, or null on failure. `name` is an identifying string used
363/// in lock checking and debugging. Behaves like the driver's
364/// [`erl_drv_mutex_create`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_mutex_create).
365///
366/// [`enif_mutex_create`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_mutex_create) — NIF 1.0 — OTP R13B04
367#[inline]
368pub unsafe fn mutex_create(name: *mut c_char) -> *mut Mutex {
369 unsafe { (api().mutex_create)(name) }
370}
371
372/// Destroys a mutex.
373///
374/// Frees a mutex created by [`mutex_create`]; it must be unlocked. Like
375/// [`erl_drv_mutex_destroy`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_mutex_destroy).
376///
377/// [`enif_mutex_destroy`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_mutex_destroy) — NIF 1.0 — OTP R13B04
378#[inline]
379pub unsafe fn mutex_destroy(mtx: *mut Mutex) {
380 unsafe { (api().mutex_destroy)(mtx) }
381}
382
383/// Tries to lock a mutex without blocking.
384///
385/// Locks `mtx` and returns `0` if it is free; returns `EBUSY` without blocking if
386/// it is already held. Like
387/// [`erl_drv_mutex_trylock`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_mutex_trylock).
388///
389/// [`enif_mutex_trylock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_mutex_trylock) — NIF 1.0 — OTP R13B04
390#[inline]
391pub unsafe fn mutex_trylock(mtx: *mut Mutex) -> c_int {
392 unsafe { (api().mutex_trylock)(mtx) }
393}
394
395/// Locks a mutex, blocking until it is free.
396///
397/// Re-locking a mutex already held by the calling thread is undefined behavior.
398/// Like [`erl_drv_mutex_lock`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_mutex_lock).
399///
400/// [`enif_mutex_lock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_mutex_lock) — NIF 1.0 — OTP R13B04
401#[inline]
402pub unsafe fn mutex_lock(mtx: *mut Mutex) {
403 unsafe { (api().mutex_lock)(mtx) }
404}
405
406/// Unlocks a mutex.
407///
408/// Releases `mtx`, which must be held by the calling thread. Like
409/// [`erl_drv_mutex_unlock`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_mutex_unlock).
410///
411/// [`enif_mutex_unlock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_mutex_unlock) — NIF 1.0 — OTP R13B04
412#[inline]
413pub unsafe fn mutex_unlock(mtx: *mut Mutex) {
414 unsafe { (api().mutex_unlock)(mtx) }
415}
416
417/// Creates a condition variable.
418///
419/// Returns a new condition variable, or null on failure. `name` identifies it for
420/// debugging. Like
421/// [`erl_drv_cond_create`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_cond_create).
422///
423/// [`enif_cond_create`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_cond_create) — NIF 1.0 — OTP R13B04
424#[inline]
425pub unsafe fn cond_create(name: *mut c_char) -> *mut Cond {
426 unsafe { (api().cond_create)(name) }
427}
428
429/// Destroys a condition variable.
430///
431/// Frees a condition variable created by [`cond_create`]. Like
432/// [`erl_drv_cond_destroy`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_cond_destroy).
433///
434/// [`enif_cond_destroy`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_cond_destroy) — NIF 1.0 — OTP R13B04
435#[inline]
436pub unsafe fn cond_destroy(cnd: *mut Cond) {
437 unsafe { (api().cond_destroy)(cnd) }
438}
439
440/// Wakes one thread waiting on a condition variable.
441///
442/// Like [`erl_drv_cond_signal`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_cond_signal).
443///
444/// [`enif_cond_signal`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_cond_signal) — NIF 1.0 — OTP R13B04
445#[inline]
446pub unsafe fn cond_signal(cnd: *mut Cond) {
447 unsafe { (api().cond_signal)(cnd) }
448}
449
450/// Wakes all threads waiting on a condition variable.
451///
452/// Like [`erl_drv_cond_broadcast`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_cond_broadcast).
453///
454/// [`enif_cond_broadcast`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_cond_broadcast) — NIF 1.0 — OTP R13B04
455#[inline]
456pub unsafe fn cond_broadcast(cnd: *mut Cond) {
457 unsafe { (api().cond_broadcast)(cnd) }
458}
459
460/// Waits on a condition variable.
461///
462/// Atomically releases `mtx` and blocks until `cnd` is signaled, then re-acquires
463/// `mtx` before returning. Call it in a loop that re-checks the predicate, since
464/// spurious wakeups are possible. Like
465/// [`erl_drv_cond_wait`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_cond_wait).
466///
467/// [`enif_cond_wait`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_cond_wait) — NIF 1.0 — OTP R13B04
468#[inline]
469pub unsafe fn cond_wait(cnd: *mut Cond, mtx: *mut Mutex) {
470 unsafe { (api().cond_wait)(cnd, mtx) }
471}
472
473/// Creates a read/write lock.
474///
475/// Returns a new rwlock, or null on failure. `name` identifies it for debugging.
476/// Like [`erl_drv_rwlock_create`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_rwlock_create).
477///
478/// [`enif_rwlock_create`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_rwlock_create) — NIF 1.0 — OTP R13B04
479#[inline]
480pub unsafe fn rwlock_create(name: *mut c_char) -> *mut RWLock {
481 unsafe { (api().rwlock_create)(name) }
482}
483
484/// Destroys a read/write lock.
485///
486/// Frees an rwlock created by [`rwlock_create`]; it must be unlocked. Like
487/// [`erl_drv_rwlock_destroy`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_rwlock_destroy).
488///
489/// [`enif_rwlock_destroy`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_rwlock_destroy) — NIF 1.0 — OTP R13B04
490#[inline]
491pub unsafe fn rwlock_destroy(rwlck: *mut RWLock) {
492 unsafe { (api().rwlock_destroy)(rwlck) }
493}
494
495/// Tries to take a read lock without blocking.
496///
497/// Acquires `rwlck` for reading and returns `0` if possible; otherwise returns
498/// `EBUSY` without blocking. Like
499/// [`erl_drv_rwlock_tryrlock`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_rwlock_tryrlock).
500///
501/// [`enif_rwlock_tryrlock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_rwlock_tryrlock) — NIF 1.0 — OTP R13B04
502#[inline]
503pub unsafe fn rwlock_tryrlock(rwlck: *mut RWLock) -> c_int {
504 unsafe { (api().rwlock_tryrlock)(rwlck) }
505}
506
507/// Takes a read lock, blocking until available.
508///
509/// Several readers may hold the lock at once, but never alongside a writer. Like
510/// [`erl_drv_rwlock_rlock`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_rwlock_rlock).
511///
512/// [`enif_rwlock_rlock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_rwlock_rlock) — NIF 1.0 — OTP R13B04
513#[inline]
514pub unsafe fn rwlock_rlock(rwlck: *mut RWLock) {
515 unsafe { (api().rwlock_rlock)(rwlck) }
516}
517
518/// Releases a read lock.
519///
520/// Like [`erl_drv_rwlock_runlock`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_rwlock_runlock).
521///
522/// [`enif_rwlock_runlock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_rwlock_runlock) — NIF 1.0 — OTP R13B04
523#[inline]
524pub unsafe fn rwlock_runlock(rwlck: *mut RWLock) {
525 unsafe { (api().rwlock_runlock)(rwlck) }
526}
527
528/// Tries to take the write lock without blocking.
529///
530/// Acquires `rwlck` exclusively and returns `0` if possible; otherwise returns
531/// `EBUSY` without blocking. Like
532/// [`erl_drv_rwlock_tryrwlock`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_rwlock_tryrwlock).
533///
534/// [`enif_rwlock_tryrwlock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_rwlock_tryrwlock) — NIF 1.0 — OTP R13B04
535#[inline]
536pub unsafe fn rwlock_tryrwlock(rwlck: *mut RWLock) -> c_int {
537 unsafe { (api().rwlock_tryrwlock)(rwlck) }
538}
539
540/// Takes the write lock, blocking until exclusive.
541///
542/// Excludes all other readers and writers for the duration. Like
543/// [`erl_drv_rwlock_rwlock`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_rwlock_rwlock).
544///
545/// [`enif_rwlock_rwlock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_rwlock_rwlock) — NIF 1.0 — OTP R13B04
546#[inline]
547pub unsafe fn rwlock_rwlock(rwlck: *mut RWLock) {
548 unsafe { (api().rwlock_rwlock)(rwlck) }
549}
550
551/// Releases the write lock.
552///
553/// Like [`erl_drv_rwlock_rwunlock`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_rwlock_rwunlock).
554///
555/// [`enif_rwlock_rwunlock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_rwlock_rwunlock) — NIF 1.0 — OTP R13B04
556#[inline]
557pub unsafe fn rwlock_rwunlock(rwlck: *mut RWLock) {
558 unsafe { (api().rwlock_rwunlock)(rwlck) }
559}
560
561/// Creates a thread-specific data key.
562///
563/// Allocates a key through which each thread can store its own pointer, writing
564/// it through `key` and returning `0` on success. `name` identifies it for
565/// debugging. Like
566/// [`erl_drv_tsd_key_create`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_tsd_key_create).
567///
568/// [`enif_tsd_key_create`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_tsd_key_create) — NIF 1.0 — OTP R13B04
569#[inline]
570pub unsafe fn tsd_key_create(name: *mut c_char, key: *mut TSDKey) -> c_int {
571 unsafe { (api().tsd_key_create)(name, key) }
572}
573
574/// Destroys a thread-specific data key.
575///
576/// Frees a key created by [`tsd_key_create`]; every thread must first have reset
577/// its value for the key to null. Like
578/// [`erl_drv_tsd_key_destroy`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_tsd_key_destroy).
579///
580/// [`enif_tsd_key_destroy`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_tsd_key_destroy) — NIF 1.0 — OTP R13B04
581#[inline]
582pub unsafe fn tsd_key_destroy(key: TSDKey) {
583 unsafe { (api().tsd_key_destroy)(key) }
584}
585
586/// Stores the calling thread's value for a key.
587///
588/// Associates `data` with `key` for the current thread only. Like
589/// [`erl_drv_tsd_set`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_tsd_set).
590///
591/// [`enif_tsd_set`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_tsd_set) — NIF 1.0 — OTP R13B04
592#[inline]
593pub unsafe fn tsd_set(key: TSDKey, data: *mut c_void) {
594 unsafe { (api().tsd_set)(key, data) }
595}
596
597/// Reads the calling thread's value for a key.
598///
599/// Returns the pointer last stored for `key` by the current thread, or null if it
600/// has set none. Like
601/// [`erl_drv_tsd_get`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_tsd_get).
602///
603/// [`enif_tsd_get`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_tsd_get) — NIF 1.0 — OTP R13B04
604#[inline]
605pub unsafe fn tsd_get(key: TSDKey) -> *mut c_void {
606 unsafe { (api().tsd_get)(key) }
607}
608
609/// Allocates a thread-options block.
610///
611/// Returns options to pass to [`thread_create`], or null on failure. `name`
612/// identifies it for debugging. Like
613/// [`erl_drv_thread_opts_create`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_thread_opts_create).
614///
615/// [`enif_thread_opts_create`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_thread_opts_create) — NIF 1.0 — OTP R13B04
616#[inline]
617pub unsafe fn thread_opts_create(name: *mut c_char) -> *mut ThreadOpts {
618 unsafe { (api().thread_opts_create)(name) }
619}
620
621/// Frees a thread-options block.
622///
623/// Releases options created by [`thread_opts_create`]. Like
624/// [`erl_drv_thread_opts_destroy`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_thread_opts_destroy).
625///
626/// [`enif_thread_opts_destroy`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_thread_opts_destroy) — NIF 1.0 — OTP R13B04
627#[inline]
628pub unsafe fn thread_opts_destroy(opts: *mut ThreadOpts) {
629 unsafe { (api().thread_opts_destroy)(opts) }
630}
631
632/// Spawns a new BEAM-managed thread.
633///
634/// Starts a thread running `func(args)`, writing its id through `tid` and
635/// returning `0` on success. `opts` may be null for defaults. Every created
636/// thread must eventually be reaped with [`thread_join`]. Like
637/// [`erl_drv_thread_create`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_thread_create).
638///
639/// [`enif_thread_create`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_thread_create) — NIF 1.0 — OTP R13B04
640#[inline]
641pub unsafe fn thread_create(
642 name: *mut c_char,
643 tid: *mut Tid,
644 func: Option<unsafe extern "C" fn(*mut c_void) -> *mut c_void>,
645 args: *mut c_void,
646 opts: *mut ThreadOpts,
647) -> c_int {
648 unsafe { (api().thread_create)(name, tid, func, args, opts) }
649}
650
651/// Returns the calling thread's identifier.
652///
653/// Like [`erl_drv_thread_self`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_thread_self).
654///
655/// [`enif_thread_self`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_thread_self) — NIF 1.0 — OTP R13B04
656#[inline]
657pub unsafe fn thread_self() -> Tid {
658 unsafe { (api().thread_self)() }
659}
660
661/// Compares two thread identifiers.
662///
663/// Returns a non-zero value if `tid1` and `tid2` refer to the same thread. Like
664/// [`erl_drv_equal_tids`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_equal_tids).
665///
666/// [`enif_equal_tids`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_equal_tids) — NIF 1.0 — OTP R13B04
667#[inline]
668pub unsafe fn equal_tids(tid1: Tid, tid2: Tid) -> c_int {
669 unsafe { (api().equal_tids)(tid1, tid2) }
670}
671
672/// Terminates the calling thread.
673///
674/// Ends the current thread with result `resp`, which a joiner receives through
675/// [`thread_join`]. Valid only on threads started by [`thread_create`]. Like
676/// [`erl_drv_thread_exit`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_thread_exit).
677///
678/// [`enif_thread_exit`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_thread_exit) — NIF 1.0 — OTP R13B04
679#[inline]
680pub unsafe fn thread_exit(resp: *mut c_void) {
681 unsafe { (api().thread_exit)(resp) }
682}
683
684/// Waits for a thread to finish and collects its result.
685///
686/// Blocks until thread `tid` exits, writing its result through `respp` (when
687/// non-null) and returning `0`. Like
688/// [`erl_drv_thread_join`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_thread_join).
689///
690/// [`enif_thread_join`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_thread_join) — NIF 1.0 — OTP R13B04
691#[inline]
692pub unsafe fn thread_join(tid: Tid, respp: *mut *mut c_void) -> c_int {
693 unsafe { (api().thread_join)(tid, respp) }
694}
695
696// ===========================================================================
697// NIF 1.0 / 2.0 — more core, resources, strings, env, send
698// ===========================================================================
699
700/// Resizes a block from the BEAM allocator.
701///
702/// Grows or shrinks the block at `ptr` (from [`alloc`]) to `size` bytes,
703/// preserving contents up to the smaller size, and returns the possibly-moved
704/// pointer or null on failure. On failure the original block is left valid.
705///
706/// [`enif_realloc`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_realloc) — NIF 1.0 — OTP R13B04
707#[inline]
708pub unsafe fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void {
709 unsafe { (api().realloc)(ptr, size) }
710}
711
712/// Fills in a system-information struct.
713///
714/// Writes BEAM runtime details — ERTS and OTP versions, scheduler counts, SMP
715/// and dirty-scheduler support — into the [`SysInfo`] at `sys_info_ptr`, which
716/// must be `size` bytes. Mirrors the driver's
717/// [`driver_system_info`](https://www.erlang.org/doc/apps/erts/erl_driver.html#driver_system_info).
718///
719/// [`enif_system_info`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_system_info) — NIF 1.0 — OTP R13B04
720#[inline]
721pub unsafe fn system_info(sys_info_ptr: *mut SysInfo, size: usize) {
722 unsafe { (api().system_info)(sys_info_ptr, size) }
723}
724
725/// Flattens an iolist into a contiguous binary.
726///
727/// Initializes `bin` with a single contiguous buffer holding the bytes of the
728/// iolist `term`, returning a non-zero value on success or `0` if `term` is not
729/// an iolist. As with [`inspect_binary`], the data is transient and needs no
730/// release unless later grown with [`realloc_binary`].
731///
732/// [`enif_inspect_iolist_as_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_inspect_iolist_as_binary) — NIF 1.0 — OTP R13B04
733#[inline]
734pub unsafe fn inspect_iolist_as_binary(env: *mut Env, term: Term, bin: *mut Binary) -> c_int {
735 unsafe { (api().inspect_iolist_as_binary)(env, term, bin) }
736}
737
738/// Builds a sub-binary referencing part of another binary.
739///
740/// Returns a binary term covering `size` bytes of `bin_term` starting at the
741/// zero-based byte offset `pos`. `bin_term` must be a binary or bitstring and
742/// `pos + size` must lie within it. No bytes are copied.
743///
744/// [`enif_make_sub_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_sub_binary) — NIF 1.0 — OTP R13B04
745#[inline]
746pub unsafe fn make_sub_binary(env: *mut Env, bin_term: Term, pos: usize, size: usize) -> Term {
747 unsafe { (api().make_sub_binary)(env, bin_term, pos, size) }
748}
749
750/// Copies an Erlang string into a C buffer.
751///
752/// Writes the characters of the string `list`, in the given [`CharEncoding`], as
753/// a NUL-terminated string into `buf` (capacity `size`). Returns the number of
754/// bytes written including the NUL; a negative value whose magnitude is the
755/// buffer size if the string was truncated; or `0` if `list` is not a string.
756///
757/// [`enif_get_string`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_string) — NIF 1.0 — OTP R13B04
758#[inline]
759pub unsafe fn get_string(
760 env: *mut Env,
761 list: Term,
762 buf: *mut c_char,
763 size: c_uint,
764 encoding: CharEncoding,
765) -> c_int {
766 unsafe { (api().get_string)(env, list, buf, size, encoding) }
767}
768
769/// Copies an atom's name into a C buffer.
770///
771/// Writes the name of the atom `term`, in the given [`CharEncoding`], as a
772/// NUL-terminated string into `buf` (capacity `size`). Returns the number of
773/// bytes written including the NUL, or `0` if `term` is not an atom or the name
774/// does not fit.
775///
776/// [`enif_get_atom`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_atom) — NIF 1.0 — OTP R13B04
777#[inline]
778pub unsafe fn get_atom(
779 env: *mut Env,
780 term: Term,
781 buf: *mut c_char,
782 size: c_uint,
783 encoding: CharEncoding,
784) -> c_int {
785 unsafe { (api().get_atom)(env, term, buf, size, encoding) }
786}
787
788/// Tests whether a term is a fun.
789///
790/// Returns a non-zero value if `term` is a fun, `0` otherwise.
791///
792/// [`enif_is_fun`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_fun) — NIF 1.0 — OTP R13B04
793#[inline]
794pub unsafe fn is_fun(env: *mut Env, term: Term) -> c_int {
795 unsafe { (api().is_fun)(env, term) }
796}
797
798/// Tests whether a term is a pid.
799///
800/// Returns a non-zero value if `term` is a pid, `0` otherwise.
801///
802/// [`enif_is_pid`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_pid) — NIF 1.0 — OTP R13B04
803#[inline]
804pub unsafe fn is_pid(env: *mut Env, term: Term) -> c_int {
805 unsafe { (api().is_pid)(env, term) }
806}
807
808/// Tests whether a term is a port.
809///
810/// Returns a non-zero value if `term` is a port, `0` otherwise.
811///
812/// [`enif_is_port`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_port) — NIF 1.0 — OTP R13B04
813#[inline]
814pub unsafe fn is_port(env: *mut Env, term: Term) -> c_int {
815 unsafe { (api().is_port)(env, term) }
816}
817
818/// Decodes an unsigned integer from a term.
819///
820/// If `term` is a non-negative integer that fits in a C `unsigned int`, writes it
821/// through `ip` and returns a non-zero value; otherwise leaves `*ip` untouched
822/// and returns `0`.
823///
824/// [`enif_get_uint`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_uint) — NIF 1.0 — OTP R13B04
825#[inline]
826pub unsafe fn get_uint(env: *mut Env, term: Term, ip: *mut c_uint) -> c_int {
827 unsafe { (api().get_uint)(env, term, ip) }
828}
829
830/// Decodes a long integer from a term.
831///
832/// If `term` is an integer that fits in a C `long`, writes it through `ip` and
833/// returns a non-zero value; otherwise leaves `*ip` untouched and returns `0`.
834///
835/// [`enif_get_long`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_long) — NIF 1.0 — OTP R13B04
836#[inline]
837pub unsafe fn get_long(env: *mut Env, term: Term, ip: *mut c_long) -> c_int {
838 unsafe { (api().get_long)(env, term, ip) }
839}
840
841/// Builds an Erlang integer from an unsigned int.
842///
843/// Constructs the integer term in `env`; always succeeds.
844///
845/// [`enif_make_uint`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_uint) — NIF 1.0 — OTP R13B04
846#[inline]
847pub unsafe fn make_uint(env: *mut Env, i: c_uint) -> Term {
848 unsafe { (api().make_uint)(env, i) }
849}
850
851/// Builds an Erlang integer from a long value.
852///
853/// Constructs the integer term in `env`; always succeeds.
854///
855/// [`enif_make_long`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_long) — NIF 1.0 — OTP R13B04
856#[inline]
857pub unsafe fn make_long(env: *mut Env, i: c_long) -> Term {
858 unsafe { (api().make_long)(env, i) }
859}
860
861/// Builds a tuple from an array of terms.
862///
863/// Returns a tuple whose elements are the `cnt` terms at `arr`, in order.
864///
865/// [`enif_make_tuple_from_array`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_tuple_from_array) — NIF 1.0 — OTP R13B04
866#[inline]
867pub unsafe fn make_tuple_from_array(env: *mut Env, arr: *const Term, cnt: c_uint) -> Term {
868 unsafe { (api().make_tuple_from_array)(env, arr, cnt) }
869}
870
871/// Builds a proper list from an array of terms.
872///
873/// Returns the list whose elements are the `cnt` terms at `arr`, in order; an
874/// empty array yields the empty list.
875///
876/// [`enif_make_list_from_array`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list_from_array) — NIF 1.0 — OTP R13B04
877#[inline]
878pub unsafe fn make_list_from_array(env: *mut Env, arr: *const Term, cnt: c_uint) -> Term {
879 unsafe { (api().make_list_from_array)(env, arr, cnt) }
880}
881
882/// Tests whether a term is the empty list.
883///
884/// Returns a non-zero value if `term` is `[]`, `0` otherwise.
885///
886/// [`enif_is_empty_list`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_empty_list) — NIF 1.0 — OTP R13B04
887#[inline]
888pub unsafe fn is_empty_list(env: *mut Env, term: Term) -> c_int {
889 unsafe { (api().is_empty_list)(env, term) }
890}
891
892/// Registers a resource type for the calling module.
893///
894/// Creates — or during a code upgrade takes over — the resource type named
895/// `name` with destructor `dtor`, returning an opaque [`ResourceType`] handle or
896/// null on failure. `flags` selects [`ResourceFlags::CREATE`] and/or
897/// [`ResourceFlags::TAKEOVER`], and the operation actually performed is written
898/// through `tried`. `module_str` is reserved and must be null. Callable only
899/// from the module's `load` or `upgrade` callback; for stop/down/dyncall
900/// callbacks use [`open_resource_type_x`].
901///
902/// [`enif_open_resource_type`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_open_resource_type) — NIF 1.0 — OTP R13B04
903#[inline]
904pub unsafe fn open_resource_type(
905 env: *mut Env,
906 module_str: *const c_char,
907 name: *const c_char,
908 dtor: Option<unsafe extern "C" fn(*mut Env, *mut c_void)>,
909 flags: ResourceFlags,
910 tried: *mut ResourceFlags,
911) -> *mut ResourceType {
912 unsafe { (api().open_resource_type)(env, module_str, name, dtor, flags, tried) }
913}
914
915/// Allocates a reference-counted resource object.
916///
917/// Allocates `size` bytes of a resource of type `type_` (from
918/// [`open_resource_type`]) and returns a pointer with reference count 1. Publish
919/// it to Erlang with [`make_resource`] and drop your own reference with
920/// [`release_resource`]; the destructor runs once the count reaches zero.
921///
922/// [`enif_alloc_resource`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_alloc_resource) — NIF 1.0 — OTP R13B04
923#[inline]
924pub unsafe fn alloc_resource(type_: *mut ResourceType, size: usize) -> *mut c_void {
925 unsafe { (api().alloc_resource)(type_, size) }
926}
927
928/// Drops one reference to a resource object.
929///
930/// Decrements the reference count of `obj` (from [`alloc_resource`]); when it
931/// reaches zero the type's destructor runs and the memory is freed. Terms made
932/// with [`make_resource`] hold their own references, so this need not free
933/// immediately.
934///
935/// [`enif_release_resource`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_release_resource) — NIF 1.0 — OTP R13B04
936#[inline]
937pub unsafe fn release_resource(obj: *mut c_void) {
938 unsafe { (api().release_resource)(obj) }
939}
940
941/// Wraps a resource object in an opaque term.
942///
943/// Returns a term referring to `obj` (from [`alloc_resource`]). Ownership is not
944/// transferred: you still hold your own reference and must [`release_resource`]
945/// it. The term keeps `obj` alive independently of that reference.
946///
947/// [`enif_make_resource`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_resource) — NIF 1.0 — OTP R13B04
948#[inline]
949pub unsafe fn make_resource(env: *mut Env, obj: *mut c_void) -> Term {
950 unsafe { (api().make_resource)(env, obj) }
951}
952
953/// Unwraps a resource object from a term.
954///
955/// If `term` is a resource of type `type_`, writes its object pointer through
956/// `objp` and returns a non-zero value; returns `0` otherwise. The pointer is
957/// borrowed — valid while the term (or any other reference) keeps the object
958/// alive — not a new reference.
959///
960/// [`enif_get_resource`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_resource) — NIF 1.0 — OTP R13B04
961#[inline]
962pub unsafe fn get_resource(
963 env: *mut Env,
964 term: Term,
965 type_: *mut ResourceType,
966 objp: *mut *mut c_void,
967) -> c_int {
968 unsafe { (api().get_resource)(env, term, type_, objp) }
969}
970
971/// Returns the byte size of a resource object.
972///
973/// Reports the `size` that `obj` was allocated with by [`alloc_resource`].
974///
975/// [`enif_sizeof_resource`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_sizeof_resource) — NIF 1.0 — OTP R13B04
976#[inline]
977pub unsafe fn sizeof_resource(obj: *mut c_void) -> usize {
978 unsafe { (api().sizeof_resource)(obj) }
979}
980
981/// Allocates a binary term and returns a writable pointer to its bytes.
982///
983/// Creates a binary of `size` bytes, writes the owning term through `termp`, and
984/// returns a pointer to its data. The bytes are mutable only until the calling
985/// NIF returns. A convenience combining [`alloc_binary`] and [`make_binary`].
986///
987/// [`enif_make_new_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_new_binary) — NIF 2.0 — OTP R14A
988#[inline]
989pub unsafe fn make_new_binary(env: *mut Env, size: usize, termp: *mut Term) -> *mut u8 {
990 unsafe { (api().make_new_binary)(env, size, termp) }
991}
992
993/// Tests whether a term is a list.
994///
995/// Returns a non-zero value if `term` is a list — including the empty list — and
996/// `0` otherwise.
997///
998/// [`enif_is_list`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_list) — NIF 2.0 — OTP R14A
999#[inline]
1000pub unsafe fn is_list(env: *mut Env, term: Term) -> c_int {
1001 unsafe { (api().is_list)(env, term) }
1002}
1003
1004/// Tests whether a term is a tuple.
1005///
1006/// Returns a non-zero value if `term` is a tuple, `0` otherwise.
1007///
1008/// [`enif_is_tuple`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_tuple) — NIF 2.0 — OTP R14A
1009#[inline]
1010pub unsafe fn is_tuple(env: *mut Env, term: Term) -> c_int {
1011 unsafe { (api().is_tuple)(env, term) }
1012}
1013
1014/// Reads the byte length of an atom's name.
1015///
1016/// Writes through `len` the number of bytes in the atom `term`'s name in the
1017/// given [`CharEncoding`], excluding any terminating NUL, and returns a non-zero
1018/// value; returns `0` if `term` is not an atom.
1019///
1020/// [`enif_get_atom_length`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_atom_length) — NIF 2.0 — OTP R14A
1021#[inline]
1022pub unsafe fn get_atom_length(
1023 env: *mut Env,
1024 term: Term,
1025 len: *mut c_uint,
1026 encoding: CharEncoding,
1027) -> c_int {
1028 unsafe { (api().get_atom_length)(env, term, len, encoding) }
1029}
1030
1031/// Reads the length of a proper list.
1032///
1033/// If `term` is a proper list, writes its element count through `len` and returns
1034/// a non-zero value; returns `0` for an improper or non-list term.
1035///
1036/// [`enif_get_list_length`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_list_length) — NIF 2.0 — OTP R14A
1037#[inline]
1038pub unsafe fn get_list_length(env: *mut Env, term: Term, len: *mut c_uint) -> c_int {
1039 unsafe { (api().get_list_length)(env, term, len) }
1040}
1041
1042/// Builds an atom from a length-counted Latin-1 string.
1043///
1044/// Like [`make_atom`], but reads exactly `len` bytes of `name` as ISO Latin-1, so
1045/// embedded NUL bytes are ordinary characters. A name over the 255-character
1046/// atom limit raises `badarg` on return.
1047///
1048/// [`enif_make_atom_len`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_atom_len) — NIF 2.0 — OTP R14A
1049#[inline]
1050pub unsafe fn make_atom_len(env: *mut Env, name: *const c_char, len: usize) -> Term {
1051 unsafe { (api().make_atom_len)(env, name, len) }
1052}
1053
1054/// Looks up an existing atom by a length-counted name.
1055///
1056/// Like [`make_existing_atom`], but reads exactly `len` bytes of `name`, so
1057/// embedded NUL bytes are ordinary characters. Writes the atom through `atom` and
1058/// returns a non-zero value only if it already exists.
1059///
1060/// [`enif_make_existing_atom_len`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_existing_atom_len) — NIF 2.0 — OTP R14A
1061#[inline]
1062pub unsafe fn make_existing_atom_len(
1063 env: *mut Env,
1064 name: *const c_char,
1065 len: usize,
1066 atom: *mut Term,
1067 encoding: CharEncoding,
1068) -> c_int {
1069 unsafe { (api().make_existing_atom_len)(env, name, len, atom, encoding) }
1070}
1071
1072/// Builds a string from a length-counted C string.
1073///
1074/// Like [`make_string`], but reads exactly `len` bytes of `string`, so embedded
1075/// NUL bytes become ordinary characters in the resulting list.
1076///
1077/// [`enif_make_string_len`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_string_len) — NIF 2.0 — OTP R14A
1078#[inline]
1079pub unsafe fn make_string_len(
1080 env: *mut Env,
1081 string: *const c_char,
1082 len: usize,
1083 encoding: CharEncoding,
1084) -> Term {
1085 unsafe { (api().make_string_len)(env, string, len, encoding) }
1086}
1087
1088/// Allocates a process-independent environment.
1089///
1090/// Returns a fresh [`Env`] not tied to any process, for holding terms across NIF
1091/// calls — for example a message to send later. Free it with [`free_env`].
1092///
1093/// [`enif_alloc_env`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_alloc_env) — NIF 2.0 — OTP R14A
1094#[inline]
1095pub unsafe fn alloc_env() -> *mut Env {
1096 unsafe { (api().alloc_env)() }
1097}
1098
1099/// Frees a process-independent environment.
1100///
1101/// Releases an environment from [`alloc_env`] along with every term created in
1102/// it. Never call it on a NIF call environment.
1103///
1104/// [`enif_free_env`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_free_env) — NIF 2.0 — OTP R14A
1105#[inline]
1106pub unsafe fn free_env(env: *mut Env) {
1107 unsafe { (api().free_env)(env) }
1108}
1109
1110/// Clears a process-independent environment for reuse.
1111///
1112/// Frees all terms in an environment from [`alloc_env`] and resets it to empty,
1113/// avoiding a [`free_env`]/[`alloc_env`] cycle.
1114///
1115/// [`enif_clear_env`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_clear_env) — NIF 2.0 — OTP R14A
1116#[inline]
1117pub unsafe fn clear_env(env: *mut Env) {
1118 unsafe { (api().clear_env)(env) }
1119}
1120
1121/// Sends a message to a process.
1122///
1123/// Delivers `msg` to the process `to_pid`, returning a non-zero value if the
1124/// process was alive. `msg` must live in `msg_env`: pass an environment from
1125/// [`alloc_env`] (which the send consumes and clears), or null to send a copy of
1126/// a term rooted in `caller_env`. `caller_env` is the calling NIF's environment,
1127/// or null when sending from a thread that is not running a NIF.
1128///
1129/// [`enif_send`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_send) — NIF 2.0 — OTP R14A
1130#[inline]
1131pub unsafe fn send(
1132 caller_env: *mut Env,
1133 to_pid: *const Pid,
1134 msg_env: *mut Env,
1135 msg: Term,
1136) -> c_int {
1137 unsafe { (api().send)(caller_env, to_pid, msg_env, msg) }
1138}
1139
1140/// Deep-copies a term into another environment.
1141///
1142/// Returns a copy of `src_term` allocated in `dst_env`, so it can outlive
1143/// `src_term`'s original environment.
1144///
1145/// [`enif_make_copy`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_copy) — NIF 2.0 — OTP R14A
1146#[inline]
1147pub unsafe fn make_copy(dst_env: *mut Env, src_term: Term) -> Term {
1148 unsafe { (api().make_copy)(dst_env, src_term) }
1149}
1150
1151/// Records the calling process as a pid.
1152///
1153/// Writes the calling process's pid through `pid` and returns that same pointer.
1154/// `caller_env` must be a NIF call environment.
1155///
1156/// [`enif_self`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_self) — NIF 2.0 — OTP R14A
1157#[inline]
1158pub unsafe fn self_(caller_env: *mut Env, pid: *mut Pid) -> *mut Pid {
1159 unsafe { (api().self_)(caller_env, pid) }
1160}
1161
1162/// Extracts a node-local pid from a term.
1163///
1164/// If `term` is the pid of a process on the local node, writes it through `pid`
1165/// and returns a non-zero value; returns `0` otherwise.
1166///
1167/// [`enif_get_local_pid`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_local_pid) — NIF 2.0 — OTP R14A
1168#[inline]
1169pub unsafe fn get_local_pid(env: *mut Env, term: Term, pid: *mut Pid) -> c_int {
1170 unsafe { (api().get_local_pid)(env, term, pid) }
1171}
1172
1173/// Adds a reference to a resource object.
1174///
1175/// Increments the reference count of `obj` (from [`alloc_resource`]); balance
1176/// each call with [`release_resource`] before the object can be destructed.
1177///
1178/// [`enif_keep_resource`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_keep_resource) — NIF 2.0 — OTP R14A
1179#[inline]
1180pub unsafe fn keep_resource(obj: *mut c_void) {
1181 unsafe { (api().keep_resource)(obj) }
1182}
1183
1184/// Builds a binary term backed by a resource's memory.
1185///
1186/// Returns a binary of `size` bytes at `data` whose lifetime is managed by the
1187/// resource `obj` (from [`alloc_resource`]) rather than copied. The resource is
1188/// kept alive while the binary exists — a way to expose bytes owned by a resource
1189/// without copying them.
1190///
1191/// [`enif_make_resource_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_resource_binary) — NIF 2.0 — OTP R14A
1192#[inline]
1193pub unsafe fn make_resource_binary(
1194 env: *mut Env,
1195 obj: *mut c_void,
1196 data: *const c_void,
1197 size: usize,
1198) -> Term {
1199 unsafe { (api().make_resource_binary)(env, obj, data, size) }
1200}
1201
1202/// Decodes a 64-bit signed integer from a term.
1203///
1204/// If `term` is an integer that fits in a signed 64-bit value, writes it through
1205/// `ip` and returns a non-zero value; otherwise leaves `*ip` untouched and
1206/// returns `0`.
1207///
1208/// [`enif_get_int64`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_int64) — NIF 2.0 — OTP R14B
1209#[inline]
1210pub unsafe fn get_int64(env: *mut Env, term: Term, ip: *mut i64) -> c_int {
1211 unsafe { (api().get_int64)(env, term, ip) }
1212}
1213
1214/// Decodes a 64-bit unsigned integer from a term.
1215///
1216/// If `term` is a non-negative integer that fits in an unsigned 64-bit value,
1217/// writes it through `ip` and returns a non-zero value; otherwise leaves `*ip`
1218/// untouched and returns `0`.
1219///
1220/// [`enif_get_uint64`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_uint64) — NIF 2.0 — OTP R14B
1221#[inline]
1222pub unsafe fn get_uint64(env: *mut Env, term: Term, ip: *mut u64) -> c_int {
1223 unsafe { (api().get_uint64)(env, term, ip) }
1224}
1225
1226/// Builds an Erlang integer from a signed 64-bit value.
1227///
1228/// Constructs the integer term in `env`; always succeeds.
1229///
1230/// [`enif_make_int64`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_int64) — NIF 2.0 — OTP R14B
1231#[inline]
1232pub unsafe fn make_int64(env: *mut Env, i: i64) -> Term {
1233 unsafe { (api().make_int64)(env, i) }
1234}
1235
1236/// Builds an Erlang integer from an unsigned 64-bit value.
1237///
1238/// Constructs the integer term in `env`; always succeeds.
1239///
1240/// [`enif_make_uint64`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_uint64) — NIF 2.0 — OTP R14B
1241#[inline]
1242pub unsafe fn make_uint64(env: *mut Env, i: u64) -> Term {
1243 unsafe { (api().make_uint64)(env, i) }
1244}
1245
1246// ===========================================================================
1247// NIF 2.2 – 2.4
1248// ===========================================================================
1249
1250/// Tests whether a term is a pending exception.
1251///
1252/// Returns a non-zero value if `term` is an exception term — such as the value
1253/// returned by [`make_badarg`] or [`raise_exception`] — and `0` otherwise.
1254///
1255/// [`enif_is_exception`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_exception) — NIF 2.2 — OTP R14B03
1256#[inline]
1257pub unsafe fn is_exception(env: *mut Env, term: Term) -> c_int {
1258 unsafe { (api().is_exception)(env, term) }
1259}
1260
1261/// Reverses a proper list.
1262///
1263/// If `list_in` is a proper list, writes its reversal through `list_out` and
1264/// returns a non-zero value; returns `0` if `list_in` is not a proper list.
1265///
1266/// [`enif_make_reverse_list`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_reverse_list) — NIF 2.3 — OTP R15A
1267#[inline]
1268pub unsafe fn make_reverse_list(env: *mut Env, list_in: Term, list_out: *mut Term) -> c_int {
1269 unsafe { (api().make_reverse_list)(env, list_in, list_out) }
1270}
1271
1272/// Tests whether a term is a number.
1273///
1274/// Returns a non-zero value if `term` is an integer or a float, `0` otherwise.
1275///
1276/// [`enif_is_number`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_number) — NIF 2.3 — OTP R15A
1277#[inline]
1278pub unsafe fn is_number(env: *mut Env, term: Term) -> c_int {
1279 unsafe { (api().is_number)(env, term) }
1280}
1281
1282/// Loads a shared library.
1283///
1284/// Opens the shared object at path `lib` and returns a handle, or null on
1285/// failure. On failure `err_handler(err_arg, msg)` is invoked with a description
1286/// if it is non-null. Resolve symbols in the result with [`dlsym`].
1287///
1288/// [`enif_dlopen`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_dlopen) — NIF 2.4 — OTP R16B
1289#[inline]
1290pub unsafe fn dlopen(
1291 lib: *const c_char,
1292 err_handler: Option<unsafe extern "C" fn(*mut c_void, *const c_char)>,
1293 err_arg: *mut c_void,
1294) -> *mut c_void {
1295 unsafe { (api().dlopen)(lib, err_handler, err_arg) }
1296}
1297
1298/// Resolves a symbol in a shared library.
1299///
1300/// Looks up `symbol` in the library `handle` (from [`dlopen`]) and returns its
1301/// address, or null if not found — in which case `err_handler(err_arg, msg)` is
1302/// invoked with a description if it is non-null.
1303///
1304/// [`enif_dlsym`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_dlsym) — NIF 2.4 — OTP R16B
1305#[inline]
1306pub unsafe fn dlsym(
1307 handle: *mut c_void,
1308 symbol: *const c_char,
1309 err_handler: Option<unsafe extern "C" fn(*mut c_void, *const c_char)>,
1310 err_arg: *mut c_void,
1311) -> *mut c_void {
1312 unsafe { (api().dlsym)(handle, symbol, err_handler, err_arg) }
1313}
1314
1315/// Reports CPU time consumed and asks whether the NIF should yield.
1316///
1317/// Tells the scheduler that the current NIF has used `percent` (1–100) of a
1318/// timeslice since the previous call, or since the NIF began. Returns a non-zero
1319/// value once the accumulated time reaches a full slice — a hint that a
1320/// long-running NIF should return soon or reschedule with [`schedule_nif`] to
1321/// avoid blocking its scheduler.
1322///
1323/// [`enif_consume_timeslice`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_consume_timeslice) — NIF 2.4 — OTP R16B
1324#[inline]
1325pub unsafe fn consume_timeslice(env: *mut Env, percent: c_int) -> c_int {
1326 unsafe { (api().consume_timeslice)(env, percent) }
1327}
1328
1329// ===========================================================================
1330// NIF 2.6 — maps
1331// ===========================================================================
1332
1333/// Tests whether a term is a map.
1334///
1335/// Returns a non-zero value if `term` is a map, `0` otherwise.
1336///
1337/// [`enif_is_map`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_map) — NIF 2.6 — OTP 17
1338#[inline]
1339pub unsafe fn is_map(env: *mut Env, term: Term) -> c_int {
1340 unsafe { (api().is_map)(env, term) }
1341}
1342
1343/// Reads the number of pairs in a map.
1344///
1345/// If `term` is a map, writes its key/value count through `size` and returns a
1346/// non-zero value; returns `0` otherwise.
1347///
1348/// [`enif_get_map_size`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_map_size) — NIF 2.6 — OTP 17
1349#[inline]
1350pub unsafe fn get_map_size(env: *mut Env, term: Term, size: *mut usize) -> c_int {
1351 unsafe { (api().get_map_size)(env, term, size) }
1352}
1353
1354/// Creates an empty map.
1355///
1356/// Returns the map `#{}` in `env`.
1357///
1358/// [`enif_make_new_map`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_new_map) — NIF 2.6 — OTP 17
1359#[inline]
1360pub unsafe fn make_new_map(env: *mut Env) -> Term {
1361 unsafe { (api().make_new_map)(env) }
1362}
1363
1364/// Returns a map with a key inserted or updated.
1365///
1366/// Copies `map_in` with `key` associated to `value`, writing the result through
1367/// `map_out` and returning a non-zero value; returns `0` if `map_in` is not a
1368/// map. Any existing value for `key` is replaced.
1369///
1370/// [`enif_make_map_put`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_map_put) — NIF 2.6 — OTP 17
1371#[inline]
1372pub unsafe fn make_map_put(
1373 env: *mut Env,
1374 map_in: Term,
1375 key: Term,
1376 value: Term,
1377 map_out: *mut Term,
1378) -> c_int {
1379 unsafe { (api().make_map_put)(env, map_in, key, value, map_out) }
1380}
1381
1382/// Looks up a key in a map.
1383///
1384/// If `map` is a map containing `key`, writes the associated value through
1385/// `value` and returns a non-zero value; returns `0` if the key is absent or
1386/// `map` is not a map.
1387///
1388/// [`enif_get_map_value`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_map_value) — NIF 2.6 — OTP 17
1389#[inline]
1390pub unsafe fn get_map_value(env: *mut Env, map: Term, key: Term, value: *mut Term) -> c_int {
1391 unsafe { (api().get_map_value)(env, map, key, value) }
1392}
1393
1394/// Returns a map with an existing key's value replaced.
1395///
1396/// Copies `map_in` with `key` re-associated to `new_value`, writing the result
1397/// through `map_out` and returning a non-zero value. `key` must already be
1398/// present; returns `0` if it is absent or `map_in` is not a map.
1399///
1400/// [`enif_make_map_update`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_map_update) — NIF 2.6 — OTP 17
1401#[inline]
1402pub unsafe fn make_map_update(
1403 env: *mut Env,
1404 map_in: Term,
1405 key: Term,
1406 new_value: Term,
1407 map_out: *mut Term,
1408) -> c_int {
1409 unsafe { (api().make_map_update)(env, map_in, key, new_value, map_out) }
1410}
1411
1412/// Returns a map with a key removed.
1413///
1414/// Copies `map_in` without `key`, writing the result through `map_out` and
1415/// returning a non-zero value; if `key` is absent, `map_out` is set to `map_in`
1416/// unchanged. Returns `0` if `map_in` is not a map.
1417///
1418/// [`enif_make_map_remove`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_map_remove) — NIF 2.6 — OTP 17
1419#[inline]
1420pub unsafe fn make_map_remove(env: *mut Env, map_in: Term, key: Term, map_out: *mut Term) -> c_int {
1421 unsafe { (api().make_map_remove)(env, map_in, key, map_out) }
1422}
1423
1424/// Creates an iterator over a map.
1425///
1426/// Initializes `iter` to traverse `map` starting from [`MapIteratorEntry`]
1427/// `entry` (first or last), returning a non-zero value; returns `0` if `map` is
1428/// not a map. Destroy it with [`map_iterator_destroy`]. Iteration order is
1429/// unspecified but consistent for a given map.
1430///
1431/// [`enif_map_iterator_create`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_map_iterator_create) — NIF 2.6 — OTP 17
1432#[inline]
1433pub unsafe fn map_iterator_create(
1434 env: *mut Env,
1435 map: Term,
1436 iter: *mut MapIterator,
1437 entry: MapIteratorEntry,
1438) -> c_int {
1439 unsafe { (api().map_iterator_create)(env, map, iter, entry) }
1440}
1441
1442/// Destroys a map iterator.
1443///
1444/// Releases an iterator initialized by [`map_iterator_create`].
1445///
1446/// [`enif_map_iterator_destroy`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_map_iterator_destroy) — NIF 2.6 — OTP 17
1447#[inline]
1448pub unsafe fn map_iterator_destroy(env: *mut Env, iter: *mut MapIterator) {
1449 unsafe { (api().map_iterator_destroy)(env, iter) }
1450}
1451
1452/// Tests whether an iterator is before the first entry.
1453///
1454/// Returns a non-zero value if `iter` sits at the head sentinel — before the
1455/// first entry — and `0` otherwise.
1456///
1457/// [`enif_map_iterator_is_head`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_map_iterator_is_head) — NIF 2.6 — OTP 17
1458#[inline]
1459pub unsafe fn map_iterator_is_head(env: *mut Env, iter: *mut MapIterator) -> c_int {
1460 unsafe { (api().map_iterator_is_head)(env, iter) }
1461}
1462
1463/// Tests whether an iterator is past the last entry.
1464///
1465/// Returns a non-zero value if `iter` sits at the tail sentinel — after the last
1466/// entry — and `0` otherwise; iteration is exhausted once this holds.
1467///
1468/// [`enif_map_iterator_is_tail`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_map_iterator_is_tail) — NIF 2.6 — OTP 17
1469#[inline]
1470pub unsafe fn map_iterator_is_tail(env: *mut Env, iter: *mut MapIterator) -> c_int {
1471 unsafe { (api().map_iterator_is_tail)(env, iter) }
1472}
1473
1474/// Advances an iterator to the next entry.
1475///
1476/// Moves `iter` forward one entry, returning a non-zero value if it then points
1477/// at a valid entry, or `0` once it reaches the tail sentinel.
1478///
1479/// [`enif_map_iterator_next`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_map_iterator_next) — NIF 2.6 — OTP 17
1480#[inline]
1481pub unsafe fn map_iterator_next(env: *mut Env, iter: *mut MapIterator) -> c_int {
1482 unsafe { (api().map_iterator_next)(env, iter) }
1483}
1484
1485/// Moves an iterator to the previous entry.
1486///
1487/// Moves `iter` back one entry, returning a non-zero value if it then points at a
1488/// valid entry, or `0` once it reaches the head sentinel.
1489///
1490/// [`enif_map_iterator_prev`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_map_iterator_prev) — NIF 2.6 — OTP 17
1491#[inline]
1492pub unsafe fn map_iterator_prev(env: *mut Env, iter: *mut MapIterator) -> c_int {
1493 unsafe { (api().map_iterator_prev)(env, iter) }
1494}
1495
1496/// Reads the key and value at the current position.
1497///
1498/// If `iter` points at a valid entry, writes its key through `key` and value
1499/// through `value` and returns a non-zero value; returns `0` at a head or tail
1500/// sentinel.
1501///
1502/// [`enif_map_iterator_get_pair`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_map_iterator_get_pair) — NIF 2.6 — OTP 17
1503#[inline]
1504pub unsafe fn map_iterator_get_pair(
1505 env: *mut Env,
1506 iter: *mut MapIterator,
1507 key: *mut Term,
1508 value: *mut Term,
1509) -> c_int {
1510 unsafe { (api().map_iterator_get_pair)(env, iter, key, value) }
1511}
1512
1513// ===========================================================================
1514// NIF 2.7 – 2.11
1515// ===========================================================================
1516
1517/// Reschedules a NIF call onto a regular or dirty scheduler.
1518///
1519/// Arranges for `fp(env, argc, argv)` to run as a fresh NIF call and returns its
1520/// eventual result, which the current NIF must return directly. Used to split
1521/// long work into chunks or to move a dirty job onto a dirty scheduler.
1522/// `fun_name` names the rescheduled function, and `flags` is `0` for a regular
1523/// call or [`DIRTY_JOB_CPU_BOUND`] / [`DIRTY_JOB_IO_BOUND`] for a dirty one.
1524///
1525/// [`enif_schedule_nif`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_schedule_nif) — NIF 2.7 — OTP 17.3
1526#[inline]
1527pub unsafe fn schedule_nif(
1528 caller_env: *mut Env,
1529 fun_name: *const c_char,
1530 flags: c_int,
1531 fp: unsafe extern "C" fn(*mut Env, c_int, *const Term) -> Term,
1532 argc: c_int,
1533 argv: *const Term,
1534) -> Term {
1535 unsafe { (api().schedule_nif)(caller_env, fun_name, flags, fp, argc, argv) }
1536}
1537
1538/// Tests whether the environment has a pending exception.
1539///
1540/// Returns a non-zero value if a [`make_badarg`] or [`raise_exception`] is
1541/// pending on `env`. When `reason` is non-null and an exception is pending, its
1542/// reason term is written through it.
1543///
1544/// [`enif_has_pending_exception`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_has_pending_exception) — NIF 2.8 — OTP 18
1545#[inline]
1546pub unsafe fn has_pending_exception(env: *mut Env, reason: *mut Term) -> c_int {
1547 unsafe { (api().has_pending_exception)(env, reason) }
1548}
1549
1550/// Raises an `error` exception with a given reason on return.
1551///
1552/// Associates a pending `error:reason` exception with `env`; once invoked, the
1553/// runtime raises it when the NIF returns, regardless of the term the NIF
1554/// returns. The returned term is a convenience for returning directly. For the
1555/// common `badarg` case use [`make_badarg`].
1556///
1557/// [`enif_raise_exception`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_raise_exception) — NIF 2.8 — OTP 18
1558#[inline]
1559pub unsafe fn raise_exception(env: *mut Env, reason: Term) -> Term {
1560 unsafe { (api().raise_exception)(env, reason) }
1561}
1562
1563/// Reads an OS environment variable.
1564///
1565/// Copies the value of the environment variable `key` into `value` (capacity
1566/// `*value_size`), updates `*value_size` to the length, and returns `0` on
1567/// success, a positive value if it does not fit, or a negative value if unset.
1568/// Like [`erl_drv_getenv`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_getenv).
1569///
1570/// [`enif_getenv`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_getenv) — NIF 2.9 — OTP 18.2
1571#[inline]
1572pub unsafe fn getenv(key: *const c_char, value: *mut c_char, value_size: *mut usize) -> c_int {
1573 unsafe { (api().getenv)(key, value, value_size) }
1574}
1575
1576/// Returns the current Erlang monotonic time.
1577///
1578/// Reports monotonic time in the given [`TimeUnit`]. The value never decreases
1579/// but is often negative, and is meaningful only relative to other monotonic
1580/// readings.
1581///
1582/// [`enif_monotonic_time`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_monotonic_time) — NIF 2.10 — OTP 18.3
1583#[inline]
1584pub unsafe fn monotonic_time(time_unit: TimeUnit) -> Time {
1585 unsafe { (api().monotonic_time)(time_unit) }
1586}
1587
1588/// Returns the offset from monotonic time to system time.
1589///
1590/// Reports, in the given [`TimeUnit`], the amount to add to an Erlang monotonic
1591/// time to obtain the corresponding Erlang system time.
1592///
1593/// [`enif_time_offset`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_time_offset) — NIF 2.10 — OTP 18.3
1594#[inline]
1595pub unsafe fn time_offset(time_unit: TimeUnit) -> Time {
1596 unsafe { (api().time_offset)(time_unit) }
1597}
1598
1599/// Converts a time value between units.
1600///
1601/// Returns `val`, interpreted in [`TimeUnit`] `from`, expressed in [`TimeUnit`]
1602/// `to`, rounded toward negative infinity.
1603///
1604/// [`enif_convert_time_unit`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_convert_time_unit) — NIF 2.10 — OTP 18.3
1605#[inline]
1606pub unsafe fn convert_time_unit(val: Time, from: TimeUnit, to: TimeUnit) -> Time {
1607 unsafe { (api().convert_time_unit)(val, from, to) }
1608}
1609
1610/// Returns an `erlang:now/0` timestamp.
1611///
1612/// Returns a `{MegaSecs, Secs, MicroSecs}` tuple as `erlang:now/0` would.
1613/// Like that function, it is superseded by [`monotonic_time`] and time offsets.
1614///
1615/// [`enif_now_time`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_now_time) — NIF 2.11 — OTP 19
1616#[inline]
1617pub unsafe fn now_time(env: *mut Env) -> Term {
1618 unsafe { (api().now_time)(env) }
1619}
1620
1621/// Returns the current CPU time as a timestamp.
1622///
1623/// Returns the time the current logical CPU has spent executing since an
1624/// arbitrary past point, in the `{MegaSecs, Secs, MicroSecs}` format of
1625/// `erlang:timestamp/0`. Not available on all platforms.
1626///
1627/// [`enif_cpu_time`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_cpu_time) — NIF 2.11 — OTP 19
1628#[inline]
1629pub unsafe fn cpu_time(env: *mut Env) -> Term {
1630 unsafe { (api().cpu_time)(env) }
1631}
1632
1633/// Returns a unique integer.
1634///
1635/// Returns an integer unique for the given `properties`
1636/// ([`UniqueInteger::POSITIVE`] and/or [`UniqueInteger::MONOTONIC`]), matching
1637/// `erlang:unique_integer/1`.
1638///
1639/// [`enif_make_unique_integer`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_unique_integer) — NIF 2.11 — OTP 19
1640#[inline]
1641pub unsafe fn make_unique_integer(env: *mut Env, properties: UniqueInteger) -> Term {
1642 unsafe { (api().make_unique_integer)(env, properties) }
1643}
1644
1645/// Tests whether the calling process is still alive.
1646///
1647/// Returns a non-zero value if the process that scheduled the current NIF call is
1648/// still alive, `0` otherwise. Valid only on a NIF call environment.
1649///
1650/// [`enif_is_current_process_alive`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_current_process_alive) — NIF 2.11 — OTP 19
1651#[inline]
1652pub unsafe fn is_current_process_alive(env: *mut Env) -> c_int {
1653 unsafe { (api().is_current_process_alive)(env) }
1654}
1655
1656/// Tests whether a process is alive.
1657///
1658/// Returns a non-zero value if the process `pid` is alive, `0` otherwise.
1659///
1660/// [`enif_is_process_alive`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_process_alive) — NIF 2.11 — OTP 19
1661#[inline]
1662pub unsafe fn is_process_alive(env: *mut Env, pid: *const Pid) -> c_int {
1663 unsafe { (api().is_process_alive)(env, pid) }
1664}
1665
1666/// Tests whether a port is alive.
1667///
1668/// Returns a non-zero value if the port `port_id` is alive, `0` otherwise.
1669///
1670/// [`enif_is_port_alive`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_port_alive) — NIF 2.11 — OTP 19
1671#[inline]
1672pub unsafe fn is_port_alive(env: *mut Env, port_id: *const Port) -> c_int {
1673 unsafe { (api().is_port_alive)(env, port_id) }
1674}
1675
1676/// Extracts a node-local port from a term.
1677///
1678/// If `term` is a port on the local node, writes it through `port_id` and returns
1679/// a non-zero value; returns `0` otherwise.
1680///
1681/// [`enif_get_local_port`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_local_port) — NIF 2.11 — OTP 19
1682#[inline]
1683pub unsafe fn get_local_port(env: *mut Env, term: Term, port_id: *mut Port) -> c_int {
1684 unsafe { (api().get_local_port)(env, term, port_id) }
1685}
1686
1687/// Encodes a term to the external term format.
1688///
1689/// Allocates a binary (via [`alloc_binary`]) into `bin` holding the
1690/// external-format encoding of `term`, returning a non-zero value on success.
1691/// The caller owns `bin` and must hand it to a term or [`release_binary`] it.
1692///
1693/// [`enif_term_to_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_term_to_binary) — NIF 2.11 — OTP 19
1694#[inline]
1695pub unsafe fn term_to_binary(env: *mut Env, term: Term, bin: *mut Binary) -> c_int {
1696 unsafe { (api().term_to_binary)(env, term, bin) }
1697}
1698
1699/// Decodes a term from the external term format.
1700///
1701/// Decodes up to `size` bytes at `data`, writing the term through `term` and
1702/// returning the number of bytes consumed, or `0` on error. `opts` may be
1703/// [`BIN2TERM_SAFE`] to reject input that would create new atoms or other
1704/// resources.
1705///
1706/// [`enif_binary_to_term`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_binary_to_term) — NIF 2.11 — OTP 19
1707#[inline]
1708pub unsafe fn binary_to_term(
1709 env: *mut Env,
1710 data: *const u8,
1711 size: usize,
1712 term: *mut Term,
1713 opts: c_uint,
1714) -> usize {
1715 unsafe { (api().binary_to_term)(env, data, size, term, opts) }
1716}
1717
1718/// Sends a command to a port, asynchronously.
1719///
1720/// Like `erlang:port_command/2` but always fully asynchronous: delivers `msg` to
1721/// `to_port`, returning a non-zero value on success. `msg` lives in `msg_env` —
1722/// an [`alloc_env`] environment, which the call consumes and clears — or null to
1723/// copy a term rooted in the caller's `env`.
1724///
1725/// [`enif_port_command`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_port_command) — NIF 2.11 — OTP 19
1726#[inline]
1727pub unsafe fn port_command(
1728 env: *mut Env,
1729 to_port: *const Port,
1730 msg_env: *mut Env,
1731 msg: Term,
1732) -> c_int {
1733 unsafe { (api().port_command)(env, to_port, msg_env, msg) }
1734}
1735
1736/// Returns the type of the calling thread.
1737///
1738/// Returns one of [`THR_UNDEFINED`], [`THR_NORMAL_SCHEDULER`],
1739/// [`THR_DIRTY_CPU_SCHEDULER`], or [`THR_DIRTY_IO_SCHEDULER`] for the current
1740/// thread.
1741///
1742/// [`enif_thread_type`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_thread_type) — NIF 2.11 — OTP 19
1743#[inline]
1744pub unsafe fn thread_type() -> c_int {
1745 unsafe { (api().thread_type)() }
1746}
1747
1748// ===========================================================================
1749// NIF 2.12 — select, monitors, hash, whereis
1750// ===========================================================================
1751
1752/// Schedules or cancels asynchronous readiness notification for an OS event.
1753///
1754/// Asks the runtime to message `pid` (or the calling process, if `pid` is null)
1755/// when `event` becomes ready in the requested `mode` — [`SelectFlags::READ`]
1756/// and/or [`SelectFlags::WRITE`], or [`SelectFlags::STOP`] /
1757/// [`SelectFlags::CANCEL`] to tear a selection down. `obj` is the resource that
1758/// owns the event; its stop callback (from [`ResourceTypeInit`]) runs once the
1759/// event is safe to close. `ref_` is the term carried in the default `{select,
1760/// …}` message, or — with [`SelectFlags::CUSTOM_MSG`] — the whole message to
1761/// send. Returns a non-negative bitmask of `SELECT_*` result bits (see
1762/// [`SELECT_STOP_CALLED`]) on success, or a negative value on error.
1763///
1764/// [`enif_select`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_select) — NIF 2.12 — OTP 20
1765#[inline]
1766pub unsafe fn select(
1767 env: *mut Env,
1768 event: Event,
1769 mode: SelectFlags,
1770 obj: *mut c_void,
1771 pid: *const Pid,
1772 ref_: Term,
1773) -> c_int {
1774 unsafe { (api().select)(env, event, mode, obj, pid, ref_) }
1775}
1776
1777/// Registers a resource type with select and monitor callbacks.
1778///
1779/// Like [`open_resource_type`], but takes a [`ResourceTypeInit`] callback table,
1780/// so the type can also carry the stop, down, and dyncall callbacks used with
1781/// [`select`] and [`monitor_process`]. Returns the [`ResourceType`] handle or
1782/// null; callable only from the module's `load` or `upgrade` callback.
1783///
1784/// [`enif_open_resource_type_x`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_open_resource_type_x) — NIF 2.12 — OTP 20
1785#[inline]
1786pub unsafe fn open_resource_type_x(
1787 env: *mut Env,
1788 name: *const c_char,
1789 init: *const ResourceTypeInit,
1790 flags: ResourceFlags,
1791 tried: *mut ResourceFlags,
1792) -> *mut ResourceType {
1793 unsafe { (api().open_resource_type_x)(env, name, init, flags, tried) }
1794}
1795
1796/// Monitors a process on behalf of a resource.
1797///
1798/// Starts monitoring `target_pid` from the resource `obj`; when that process
1799/// dies, the resource type's `down` callback runs. Writes the monitor identifier
1800/// through `mon` and returns `0` on success, a positive value if the process is
1801/// already dead or `target_pid` is undefined, or a negative value if the resource
1802/// type has no `down` callback. Cancel with [`demonitor_process`].
1803///
1804/// [`enif_monitor_process`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_monitor_process) — NIF 2.12 — OTP 20
1805#[inline]
1806pub unsafe fn monitor_process(
1807 caller_env: *mut Env,
1808 obj: *mut c_void,
1809 target_pid: *const Pid,
1810 mon: *mut Monitor,
1811) -> c_int {
1812 unsafe { (api().monitor_process)(caller_env, obj, target_pid, mon) }
1813}
1814
1815/// Cancels a process monitor held by a resource.
1816///
1817/// Cancels the monitor `mon` held by resource `obj` (from [`monitor_process`]),
1818/// returning `0` if it was still active or a non-zero value if it had already
1819/// fired or been removed.
1820///
1821/// [`enif_demonitor_process`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_demonitor_process) — NIF 2.12 — OTP 20
1822#[inline]
1823pub unsafe fn demonitor_process(
1824 caller_env: *mut Env,
1825 obj: *mut c_void,
1826 mon: *const Monitor,
1827) -> c_int {
1828 unsafe { (api().demonitor_process)(caller_env, obj, mon) }
1829}
1830
1831/// Orders two monitor identifiers.
1832///
1833/// Returns a negative, zero, or positive value giving a total order over
1834/// `monitor1` and `monitor2`, suitable for keeping monitors in an ordered
1835/// structure. They compare equal only if they identify the same monitor.
1836///
1837/// [`enif_compare_monitors`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_compare_monitors) — NIF 2.12 — OTP 20
1838#[inline]
1839pub unsafe fn compare_monitors(monitor1: *const Monitor, monitor2: *const Monitor) -> c_int {
1840 unsafe { (api().compare_monitors)(monitor1, monitor2) }
1841}
1842
1843/// Hashes a term.
1844///
1845/// Returns a 64-bit hash of `term` using algorithm [`Hash`](crate::Hash) `type_`.
1846/// `salt` perturbs [`Hash::InternalHash`]; [`Hash::Phash2`] ignores it and
1847/// returns a 27-bit value matching `erlang:phash2/1`.
1848///
1849/// [`enif_hash`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_hash) — NIF 2.12 — OTP 20
1850#[inline]
1851pub unsafe fn hash(type_: Hash, term: Term, salt: u64) -> u64 {
1852 unsafe { (api().hash)(type_, term, salt) }
1853}
1854
1855/// Looks up a registered process by name.
1856///
1857/// If the atom `name` is a registered local process, writes its pid through `pid`
1858/// and returns a non-zero value; returns `0` otherwise. `caller_env` may be null
1859/// when called from a thread that is not running a NIF.
1860///
1861/// [`enif_whereis_pid`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_whereis_pid) — NIF 2.12 — OTP 20
1862#[inline]
1863pub unsafe fn whereis_pid(caller_env: *mut Env, name: Term, pid: *mut Pid) -> c_int {
1864 unsafe { (api().whereis_pid)(caller_env, name, pid) }
1865}
1866
1867/// Looks up a registered port by name.
1868///
1869/// If the atom `name` is a registered local port, writes it through `port` and
1870/// returns a non-zero value; returns `0` otherwise. `caller_env` may be null when
1871/// called from a thread that is not running a NIF.
1872///
1873/// [`enif_whereis_port`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_whereis_port) — NIF 2.12 — OTP 20
1874#[inline]
1875pub unsafe fn whereis_port(caller_env: *mut Env, name: Term, port: *mut Port) -> c_int {
1876 unsafe { (api().whereis_port)(caller_env, name, port) }
1877}
1878
1879// ===========================================================================
1880// NIF 2.13 — I/O queue
1881// ===========================================================================
1882
1883/// Creates an I/O queue.
1884///
1885/// Returns a new I/O queue, or null on failure. `opts` must be [`IOQ_NORMAL`].
1886/// Destroy it with [`ioq_destroy`].
1887///
1888/// [`enif_ioq_create`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_ioq_create) — NIF 2.12 — OTP 20.1
1889#[inline]
1890pub unsafe fn ioq_create(opts: IOQueueOpts) -> *mut IOQueue {
1891 unsafe { (api().ioq_create)(opts) }
1892}
1893
1894/// Destroys an I/O queue.
1895///
1896/// Frees a queue from [`ioq_create`] along with any data still in it.
1897///
1898/// [`enif_ioq_destroy`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_ioq_destroy) — NIF 2.12 — OTP 20.1
1899#[inline]
1900pub unsafe fn ioq_destroy(q: *mut IOQueue) {
1901 unsafe { (api().ioq_destroy)(q) }
1902}
1903
1904/// Appends a binary to an I/O queue.
1905///
1906/// Enqueues `bin` onto `q`, skipping its first `skip` bytes, and takes ownership
1907/// of the binary as [`make_binary`] would. Returns a non-zero value on success.
1908///
1909/// [`enif_ioq_enq_binary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_ioq_enq_binary) — NIF 2.12 — OTP 20.1
1910#[inline]
1911pub unsafe fn ioq_enq_binary(q: *mut IOQueue, bin: *mut Binary, skip: usize) -> c_int {
1912 unsafe { (api().ioq_enq_binary)(q, bin, skip) }
1913}
1914
1915/// Appends an iovec to an I/O queue.
1916///
1917/// Enqueues the [`IOVec`] `iovec` onto `q`, skipping the first `skip` bytes.
1918/// Returns a non-zero value on success.
1919///
1920/// [`enif_ioq_enqv`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_ioq_enqv) — NIF 2.12 — OTP 20.1
1921#[inline]
1922pub unsafe fn ioq_enqv(q: *mut IOQueue, iovec: *mut IOVec, skip: usize) -> c_int {
1923 unsafe { (api().ioq_enqv)(q, iovec, skip) }
1924}
1925
1926/// Returns the number of bytes queued.
1927///
1928/// Reports the total byte length currently held in `q`.
1929///
1930/// [`enif_ioq_size`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_ioq_size) — NIF 2.12 — OTP 20.1
1931#[inline]
1932pub unsafe fn ioq_size(q: *mut IOQueue) -> usize {
1933 unsafe { (api().ioq_size)(q) }
1934}
1935
1936/// Removes bytes from the front of an I/O queue.
1937///
1938/// Discards `count` bytes from the head of `q`; when `size` is non-null, the
1939/// queue's new byte length is written through it. Returns a non-zero value on
1940/// success.
1941///
1942/// [`enif_ioq_deq`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_ioq_deq) — NIF 2.12 — OTP 20.1
1943#[inline]
1944pub unsafe fn ioq_deq(q: *mut IOQueue, count: usize, size: *mut usize) -> c_int {
1945 unsafe { (api().ioq_deq)(q, count, size) }
1946}
1947
1948/// Borrows the queued data as an array of iovecs.
1949///
1950/// Returns a pointer to `q`'s data as an array of [`SysIOVec`]s and writes the
1951/// element count through `iovlen`. The array is read-only and valid until `q` is
1952/// next modified; no data is removed — use [`ioq_deq`] for that.
1953///
1954/// [`enif_ioq_peek`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_ioq_peek) — NIF 2.12 — OTP 20.1
1955#[inline]
1956pub unsafe fn ioq_peek(q: *mut IOQueue, iovlen: *mut c_int) -> *mut SysIOVec {
1957 unsafe { (api().ioq_peek)(q, iovlen) }
1958}
1959
1960/// Converts a list of binaries into an iovec.
1961///
1962/// Fills `iovec` with the binaries in the iolist `iovec_term`, handling at most
1963/// `max_elements` of them and writing the unprocessed remainder of the list
1964/// through `tail`. Returns a non-zero value on success. With a non-null `env`
1965/// the [`IOVec`] is freed automatically when the NIF returns; with a null `env`
1966/// you must free it yourself with [`free_iovec`].
1967///
1968/// [`enif_inspect_iovec`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_inspect_iovec) — NIF 2.12 — OTP 20.1
1969#[inline]
1970pub unsafe fn inspect_iovec(
1971 env: *mut Env,
1972 max_elements: usize,
1973 iovec_term: Term,
1974 tail: *mut Term,
1975 iovec: *mut *mut IOVec,
1976) -> c_int {
1977 unsafe { (api().inspect_iovec)(env, max_elements, iovec_term, tail, iovec) }
1978}
1979
1980/// Frees an iovec from [`inspect_iovec`].
1981///
1982/// Releases an [`IOVec`] returned by [`inspect_iovec`]. Needed only when that
1983/// call was made with a null environment.
1984///
1985/// [`enif_free_iovec`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_free_iovec) — NIF 2.12 — OTP 20.1
1986#[inline]
1987pub unsafe fn free_iovec(iov: *mut IOVec) {
1988 unsafe { (api().free_iovec)(iov) }
1989}
1990
1991// ===========================================================================
1992// NIF 2.14 — ioq_peek_head, *_name, make_map_from_arrays
1993// ===========================================================================
1994
1995/// Borrows the first binary in an I/O queue.
1996///
1997/// If `q` is non-empty, writes a binary term for the data at its head through
1998/// `bin_term`, writes that binary's size through `size`, and returns a non-zero
1999/// value; returns `0` if the queue is empty.
2000///
2001/// [`enif_ioq_peek_head`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_ioq_peek_head) — NIF 2.14 — OTP 21
2002#[inline]
2003pub unsafe fn ioq_peek_head(
2004 env: *mut Env,
2005 q: *mut IOQueue,
2006 size: *mut usize,
2007 bin_term: *mut Term,
2008) -> c_int {
2009 unsafe { (api().ioq_peek_head)(env, q, size, bin_term) }
2010}
2011
2012/// Returns a mutex's name.
2013///
2014/// Returns the identifying string given to [`mutex_create`]. Like
2015/// [`erl_drv_mutex_name`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_mutex_name).
2016///
2017/// [`enif_mutex_name`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_mutex_name) — NIF 2.14 — OTP 21
2018#[inline]
2019pub unsafe fn mutex_name(mtx: *mut Mutex) -> *mut c_char {
2020 unsafe { (api().mutex_name)(mtx) }
2021}
2022
2023/// Returns a condition variable's name.
2024///
2025/// Returns the identifying string given to [`cond_create`]. Like
2026/// [`erl_drv_cond_name`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_cond_name).
2027///
2028/// [`enif_cond_name`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_cond_name) — NIF 2.14 — OTP 21
2029#[inline]
2030pub unsafe fn cond_name(cnd: *mut Cond) -> *mut c_char {
2031 unsafe { (api().cond_name)(cnd) }
2032}
2033
2034/// Returns a read/write lock's name.
2035///
2036/// Returns the identifying string given to [`rwlock_create`]. Like
2037/// [`erl_drv_rwlock_name`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_rwlock_name).
2038///
2039/// [`enif_rwlock_name`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_rwlock_name) — NIF 2.14 — OTP 21
2040#[inline]
2041pub unsafe fn rwlock_name(rwlck: *mut RWLock) -> *mut c_char {
2042 unsafe { (api().rwlock_name)(rwlck) }
2043}
2044
2045/// Returns a thread's name.
2046///
2047/// Returns the name of thread `tid` (from [`thread_create`]). Like
2048/// [`erl_drv_thread_name`](https://www.erlang.org/doc/apps/erts/erl_driver.html#erl_drv_thread_name).
2049///
2050/// [`enif_thread_name`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_thread_name) — NIF 2.14 — OTP 21
2051#[inline]
2052pub unsafe fn thread_name(tid: Tid) -> *mut c_char {
2053 unsafe { (api().thread_name)(tid) }
2054}
2055
2056/// Builds a map from parallel key and value arrays.
2057///
2058/// Builds a map pairing the `cnt` keys at `keys` with the `cnt` values at
2059/// `values` (by position), writing it through `map_out` and returning a non-zero
2060/// value; returns `0` if the keys contain duplicates.
2061///
2062/// [`enif_make_map_from_arrays`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_map_from_arrays) — NIF 2.14 — OTP 21
2063#[inline]
2064pub unsafe fn make_map_from_arrays(
2065 env: *mut Env,
2066 keys: *const Term,
2067 values: *const Term,
2068 cnt: usize,
2069 map_out: *mut Term,
2070) -> c_int {
2071 unsafe { (api().make_map_from_arrays)(env, keys, values, cnt, map_out) }
2072}
2073
2074// ===========================================================================
2075// NIF 2.15 — select_x, monitor term, pid-undefined, term_type
2076// ===========================================================================
2077
2078/// Selects on an OS event with an explicit notification message.
2079///
2080/// Like [`select`], but instead of the default `{select, …}` notification it
2081/// sends `msg` (which lives in `msg_env`) to `pid`. The [`select_read`],
2082/// [`select_write`], and `select_error` wrappers build on this with
2083/// [`SelectFlags::CUSTOM_MSG`]. Same return value as [`select`].
2084///
2085/// [`enif_select_x`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_select_x) — NIF 2.15 — OTP 22
2086#[inline]
2087pub unsafe fn select_x(
2088 env: *mut Env,
2089 e: Event,
2090 flags: SelectFlags,
2091 obj: *mut c_void,
2092 pid: *const Pid,
2093 msg: Term,
2094 msg_env: *mut Env,
2095) -> c_int {
2096 unsafe { (api().select_x)(env, e, flags, obj, pid, msg, msg_env) }
2097}
2098
2099/// Builds a term identifying a monitor.
2100///
2101/// Returns a reference term naming the monitor `mon` (from [`monitor_process`]),
2102/// equal to the reference delivered to the resource type's `down` callback, so a
2103/// NIF can correlate the two.
2104///
2105/// [`enif_make_monitor_term`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_monitor_term) — NIF 2.15 — OTP 22
2106#[inline]
2107pub unsafe fn make_monitor_term(env: *mut Env, mon: *const Monitor) -> Term {
2108 unsafe { (api().make_monitor_term)(env, mon) }
2109}
2110
2111/// Marks a pid value as undefined.
2112///
2113/// Sets the [`Pid`] at `pid` to the reserved undefined value recognized by
2114/// [`is_pid_undefined`] — useful to flag an as-yet-unset pid field in a resource.
2115///
2116/// [`enif_set_pid_undefined`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_set_pid_undefined) — NIF 2.15 — OTP 22
2117#[inline]
2118pub unsafe fn set_pid_undefined(pid: *mut Pid) {
2119 unsafe { (api().set_pid_undefined)(pid) }
2120}
2121
2122/// Tests whether a pid value is the undefined marker.
2123///
2124/// Returns a non-zero value if `pid` was set by [`set_pid_undefined`], `0`
2125/// otherwise.
2126///
2127/// [`enif_is_pid_undefined`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_is_pid_undefined) — NIF 2.15 — OTP 22
2128#[inline]
2129pub unsafe fn is_pid_undefined(pid: *const Pid) -> c_int {
2130 unsafe { (api().is_pid_undefined)(pid) }
2131}
2132
2133/// Classifies a term by its top-level type.
2134///
2135/// Returns the type of `term` as a raw [`TermType`] code (decode it with
2136/// [`TermType::from_raw`]). `term` must be an ordinary term, not a special value
2137/// from [`raise_exception`], [`schedule_nif`], or similar.
2138///
2139/// [`enif_term_type`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_term_type) — NIF 2.15 — OTP 22
2140#[inline]
2141pub unsafe fn term_type(env: *mut Env, term: Term) -> c_int {
2142 unsafe { (api().term_type)(env, term) }
2143}
2144
2145// ===========================================================================
2146// NIF 2.16 (OTP 24)
2147// ===========================================================================
2148
2149/// Registers a resource type, including a dyncall callback.
2150///
2151/// Like [`open_resource_type_x`], but the [`ResourceTypeInit`] table may also
2152/// carry the `dyncall` callback invoked by [`dynamic_resource_call`]. Returns the
2153/// [`ResourceType`] handle or null; callable only from the module's `load` or
2154/// `upgrade` callback.
2155///
2156/// [`enif_init_resource_type`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_init_resource_type) — NIF 2.16 — OTP 24
2157#[cfg(feature = "nif_2_16")]
2158#[inline]
2159pub unsafe fn init_resource_type(
2160 env: *mut Env,
2161 name: *const c_char,
2162 init: *const ResourceTypeInit,
2163 flags: ResourceFlags,
2164 tried: *mut ResourceFlags,
2165) -> *mut ResourceType {
2166 unsafe { (api().init_resource_type)(env, name, init, flags, tried) }
2167}
2168
2169/// Calls into a resource type defined by another module.
2170///
2171/// Invokes the `dyncall` callback of the resource type identified by the atoms
2172/// `rt_module` and `rt_name` on `resource`, passing `call_data` through to it.
2173/// Returns `0` if the call was made, or a non-zero value if no such type or
2174/// callback exists — a way for modules to expose typed operations on each other's
2175/// resources.
2176///
2177/// [`enif_dynamic_resource_call`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_dynamic_resource_call) — NIF 2.16 — OTP 24
2178#[cfg(feature = "nif_2_16")]
2179#[inline]
2180pub unsafe fn dynamic_resource_call(
2181 caller_env: *mut Env,
2182 rt_module: Term,
2183 rt_name: Term,
2184 resource: Term,
2185 call_data: *mut c_void,
2186) -> c_int {
2187 unsafe { (api().dynamic_resource_call)(caller_env, rt_module, rt_name, resource, call_data) }
2188}
2189
2190// ===========================================================================
2191// NIF 2.17 (OTP 26)
2192// ===========================================================================
2193
2194/// Measures the length of an Erlang string.
2195///
2196/// If `list` is a string, writes its length in bytes — excluding any terminating
2197/// NUL, in the given [`CharEncoding`] — through `len` and returns a non-zero
2198/// value; returns `0` otherwise. Pair with [`get_string`] to size a buffer first.
2199///
2200/// [`enif_get_string_length`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_string_length) — NIF 2.17 — OTP 26
2201#[cfg(feature = "nif_2_17")]
2202#[inline]
2203pub unsafe fn get_string_length(
2204 env: *mut Env,
2205 list: Term,
2206 len: *mut c_uint,
2207 encoding: CharEncoding,
2208) -> c_int {
2209 unsafe { (api().get_string_length)(env, list, len, encoding) }
2210}
2211
2212/// Creates an atom from a Latin-1 or UTF-8 C string.
2213///
2214/// Creates, or reuses, the atom named by the NUL-terminated `name` in the given
2215/// [`CharEncoding`], writing it through `atom` and returning a non-zero value;
2216/// returns `0` if the name exceeds the 255-character atom limit. Unlike
2217/// [`make_existing_atom`], it creates the atom if it does not yet exist.
2218///
2219/// [`enif_make_new_atom`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_new_atom) — NIF 2.17 — OTP 26
2220#[cfg(feature = "nif_2_17")]
2221#[inline]
2222pub unsafe fn make_new_atom(
2223 env: *mut Env,
2224 name: *const c_char,
2225 atom: *mut Term,
2226 encoding: CharEncoding,
2227) -> c_int {
2228 unsafe { (api().make_new_atom)(env, name, atom, encoding) }
2229}
2230
2231/// Creates an atom from a length-counted string.
2232///
2233/// Like [`make_new_atom`], but reads exactly `len` bytes of `name`, so embedded
2234/// NUL bytes are ordinary characters.
2235///
2236/// [`enif_make_new_atom_len`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_new_atom_len) — NIF 2.17 — OTP 26
2237#[cfg(feature = "nif_2_17")]
2238#[inline]
2239pub unsafe fn make_new_atom_len(
2240 env: *mut Env,
2241 name: *const c_char,
2242 len: usize,
2243 atom: *mut Term,
2244 encoding: CharEncoding,
2245) -> c_int {
2246 unsafe { (api().make_new_atom_len)(env, name, len, atom, encoding) }
2247}
2248
2249// ===========================================================================
2250// NIF 2.18 (OTP 29)
2251// ===========================================================================
2252
2253/// Returns the heap size a term occupies.
2254///
2255/// Reports the number of bytes needed to store `term`, excluding the [`Term`]
2256/// word itself and any reference-counted binary data it points at — useful to
2257/// budget a copy into an [`alloc_env`] environment.
2258///
2259/// [`enif_term_size`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_term_size) — NIF 2.18 — OTP 29
2260#[cfg(feature = "nif_2_18")]
2261#[inline]
2262pub unsafe fn term_size(term: Term) -> usize {
2263 unsafe { (api().term_size)(term) }
2264}
2265
2266/// Returns an atom's distribution cache index.
2267///
2268/// If `atom` is an atom, writes its index within the distribution atom cache
2269/// through `index` and returns a non-zero value; returns `0` otherwise.
2270///
2271/// [`enif_get_atom_cache_index`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_get_atom_cache_index) — NIF 2.18 — OTP 29
2272#[cfg(feature = "nif_2_18")]
2273#[inline]
2274pub unsafe fn get_atom_cache_index(env: *mut Env, atom: Term, index: *mut c_uint) -> c_int {
2275 unsafe { (api().get_atom_cache_index)(env, atom, index) }
2276}
2277
2278/// Returns the largest possible atom cache index.
2279///
2280/// Reports the upper bound on the values [`get_atom_cache_index`] can produce.
2281///
2282/// [`enif_max_atom_cache_index`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_max_atom_cache_index) — NIF 2.18 — OTP 29
2283#[cfg(feature = "nif_2_18")]
2284#[inline]
2285pub unsafe fn max_atom_cache_index() -> c_uint {
2286 unsafe { (api().max_atom_cache_index)() }
2287}
2288
2289// ===========================================================================
2290// Convenience wrappers for C macros (no exported symbol)
2291// ===========================================================================
2292
2293/// Builds a pid term, or the atom `undefined`.
2294///
2295/// Returns the term for `pid`, or the atom `undefined` if it was set by
2296/// [`set_pid_undefined`]. Reimplements the `enif_make_pid` macro, so `env` is
2297/// accepted for signature compatibility but unused.
2298///
2299/// [`enif_make_pid`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_pid) — NIF 2.0 — OTP R14A
2300#[inline]
2301pub unsafe fn make_pid(_env: *mut Env, pid: Pid) -> Term {
2302 pid.pid
2303}
2304
2305/// Orders two pids by Erlang term order.
2306///
2307/// Returns a negative, zero, or positive value according to whether `*pid1` sorts
2308/// before, equal to, or after `*pid2`, using the term order of [`compare`].
2309///
2310/// [`enif_compare_pids`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_compare_pids) — NIF 2.15 — OTP 22
2311#[inline]
2312pub unsafe fn compare_pids(pid1: *const Pid, pid2: *const Pid) -> c_int {
2313 unsafe { compare((*pid1).pid, (*pid2).pid) }
2314}
2315
2316/// Selects an event for read readiness, with a custom message.
2317///
2318/// Calls [`select_x`] with [`SelectFlags::READ`] | [`SelectFlags::CUSTOM_MSG`],
2319/// so `msg` (in `msg_env`) is delivered to `pid` when the event becomes
2320/// readable. See [`select_x`] for the full semantics.
2321///
2322/// [`enif_select_read`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_select_read) — NIF 2.15 — OTP 22
2323#[inline]
2324pub unsafe fn select_read(
2325 env: *mut Env,
2326 event: Event,
2327 obj: *mut c_void,
2328 pid: *const Pid,
2329 msg: Term,
2330 msg_env: *mut Env,
2331) -> c_int {
2332 unsafe {
2333 select_x(
2334 env,
2335 event,
2336 SelectFlags::READ | SelectFlags::CUSTOM_MSG,
2337 obj,
2338 pid,
2339 msg,
2340 msg_env,
2341 )
2342 }
2343}
2344
2345/// Selects an event for write readiness, with a custom message.
2346///
2347/// Calls [`select_x`] with [`SelectFlags::WRITE`] | [`SelectFlags::CUSTOM_MSG`],
2348/// so `msg` (in `msg_env`) is delivered to `pid` when the event becomes
2349/// writable. See [`select_x`] for the full semantics.
2350///
2351/// [`enif_select_write`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_select_write) — NIF 2.15 — OTP 22
2352#[inline]
2353pub unsafe fn select_write(
2354 env: *mut Env,
2355 e: Event,
2356 obj: *mut c_void,
2357 pid: *const Pid,
2358 msg: Term,
2359 msg_env: *mut Env,
2360) -> c_int {
2361 unsafe {
2362 select_x(
2363 env,
2364 e,
2365 SelectFlags::WRITE | SelectFlags::CUSTOM_MSG,
2366 obj,
2367 pid,
2368 msg,
2369 msg_env,
2370 )
2371 }
2372}
2373
2374/// Selects an event for error conditions, with a custom message.
2375///
2376/// Calls [`select_x`] with [`SelectFlags::ERROR`] | [`SelectFlags::CUSTOM_MSG`],
2377/// so `msg` (in `msg_env`) is delivered to `pid` on an error condition. See
2378/// [`select_x`] for the full semantics.
2379///
2380/// [`enif_select_error`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_select_error) — NIF 2.16 — OTP 24
2381#[cfg(feature = "nif_2_16")]
2382#[inline]
2383pub unsafe fn select_error(
2384 env: *mut Env,
2385 e: Event,
2386 obj: *mut c_void,
2387 pid: *const Pid,
2388 msg: Term,
2389 msg_env: *mut Env,
2390) -> c_int {
2391 unsafe {
2392 select_x(
2393 env,
2394 e,
2395 SelectFlags::ERROR | SelectFlags::CUSTOM_MSG,
2396 obj,
2397 pid,
2398 msg,
2399 msg_env,
2400 )
2401 }
2402}
2403
2404/// Requests that runtime halt wait for this library's NIF calls.
2405///
2406/// Sets the [`Option_::DelayHalt`] option, so the runtime defers halting until
2407/// in-progress NIF calls into this library have returned. Settable only from the
2408/// module's `load` callback; returns `0` on success.
2409///
2410/// [`enif_set_option_delay_halt`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_set_option_delay_halt) — NIF 2.17 — OTP 26
2411#[cfg(feature = "nif_2_17")]
2412#[inline]
2413pub unsafe fn set_option_delay_halt(env: *mut Env) -> c_int {
2414 unsafe { (api().set_option)(env, Option_::DelayHalt) }
2415}
2416
2417/// Installs a callback run when the runtime halts.
2418///
2419/// Sets the [`Option_::OnHalt`] option, registering `on_halt` to run when the
2420/// runtime system halts. Settable only from the module's `load` callback;
2421/// returns `0` on success.
2422///
2423/// [`enif_set_option_on_halt`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_set_option_on_halt) — NIF 2.17 — OTP 26
2424#[cfg(feature = "nif_2_17")]
2425#[inline]
2426pub unsafe fn set_option_on_halt(
2427 env: *mut Env,
2428 on_halt: unsafe extern "C" fn(*mut c_void),
2429) -> c_int {
2430 unsafe { (api().set_option)(env, Option_::OnHalt, on_halt) }
2431}
2432
2433/// Installs a per-scheduler callback run when the library unloads.
2434///
2435/// Sets the [`Option_::OnUnloadThread`] option, registering `on_unload_thread` to
2436/// run on each scheduler thread as the library is unloaded. Settable only from
2437/// the module's `load` callback; returns `0` on success. The option itself
2438/// requires OTP 27, even though the surrounding API is NIF 2.17.
2439///
2440/// [`enif_set_option_on_unload_thread`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_set_option_on_unload_thread) — NIF 2.17 — OTP 27
2441#[cfg(feature = "nif_2_17")]
2442#[inline]
2443pub unsafe fn set_option_on_unload_thread(
2444 env: *mut Env,
2445 on_unload_thread: unsafe extern "C" fn(*mut c_void),
2446) -> c_int {
2447 unsafe { (api().set_option)(env, Option_::OnUnloadThread, on_unload_thread) }
2448}
2449
2450// ---------------------------------------------------------------------------
2451// Fixed-arity tuple constructors (call the variadic `enif_make_tuple`)
2452// ---------------------------------------------------------------------------
2453
2454/// Builds a 1-tuple.
2455///
2456/// Returns `{e1}` in `env`; a fixed-arity form of [`make_tuple_from_array`].
2457///
2458/// [`enif_make_tuple1`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_tuple1) — NIF 1.0 — OTP R13B04
2459#[inline]
2460pub unsafe fn make_tuple1(env: *mut Env, e1: Term) -> Term {
2461 unsafe { (api().make_tuple)(env, 1, e1) }
2462}
2463
2464/// Builds a 2-tuple.
2465///
2466/// Returns `{e1, e2}` in `env`; a fixed-arity form of [`make_tuple_from_array`].
2467///
2468/// [`enif_make_tuple2`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_tuple2) — NIF 1.0 — OTP R13B04
2469#[inline]
2470pub unsafe fn make_tuple2(env: *mut Env, e1: Term, e2: Term) -> Term {
2471 unsafe { (api().make_tuple)(env, 2, e1, e2) }
2472}
2473
2474/// Builds a 3-tuple.
2475///
2476/// Returns `{e1, e2, e3}` in `env`; a fixed-arity form of
2477/// [`make_tuple_from_array`].
2478///
2479/// [`enif_make_tuple3`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_tuple3) — NIF 1.0 — OTP R13B04
2480#[inline]
2481pub unsafe fn make_tuple3(env: *mut Env, e1: Term, e2: Term, e3: Term) -> Term {
2482 unsafe { (api().make_tuple)(env, 3, e1, e2, e3) }
2483}
2484
2485/// Builds a 4-tuple.
2486///
2487/// Returns `{e1, …, e4}` in `env`; a fixed-arity form of
2488/// [`make_tuple_from_array`].
2489///
2490/// [`enif_make_tuple4`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_tuple4) — NIF 1.0 — OTP R13B04
2491#[inline]
2492pub unsafe fn make_tuple4(env: *mut Env, e1: Term, e2: Term, e3: Term, e4: Term) -> Term {
2493 unsafe { (api().make_tuple)(env, 4, e1, e2, e3, e4) }
2494}
2495
2496/// Builds a 5-tuple.
2497///
2498/// Returns `{e1, …, e5}` in `env`; a fixed-arity form of
2499/// [`make_tuple_from_array`].
2500///
2501/// [`enif_make_tuple5`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_tuple5) — NIF 1.0 — OTP R13B04
2502#[inline]
2503pub unsafe fn make_tuple5(env: *mut Env, e1: Term, e2: Term, e3: Term, e4: Term, e5: Term) -> Term {
2504 unsafe { (api().make_tuple)(env, 5, e1, e2, e3, e4, e5) }
2505}
2506
2507/// Builds a 6-tuple.
2508///
2509/// Returns `{e1, …, e6}` in `env`; a fixed-arity form of
2510/// [`make_tuple_from_array`].
2511///
2512/// [`enif_make_tuple6`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_tuple6) — NIF 1.0 — OTP R13B04
2513#[inline]
2514pub unsafe fn make_tuple6(
2515 env: *mut Env,
2516 e1: Term,
2517 e2: Term,
2518 e3: Term,
2519 e4: Term,
2520 e5: Term,
2521 e6: Term,
2522) -> Term {
2523 unsafe { (api().make_tuple)(env, 6, e1, e2, e3, e4, e5, e6) }
2524}
2525
2526/// Builds a 7-tuple.
2527///
2528/// Returns `{e1, …, e7}` in `env`; a fixed-arity form of
2529/// [`make_tuple_from_array`].
2530///
2531/// [`enif_make_tuple7`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_tuple7) — NIF 1.0 — OTP R13B04
2532#[allow(clippy::too_many_arguments)]
2533#[inline]
2534pub unsafe fn make_tuple7(
2535 env: *mut Env,
2536 e1: Term,
2537 e2: Term,
2538 e3: Term,
2539 e4: Term,
2540 e5: Term,
2541 e6: Term,
2542 e7: Term,
2543) -> Term {
2544 unsafe { (api().make_tuple)(env, 7, e1, e2, e3, e4, e5, e6, e7) }
2545}
2546
2547/// Builds an 8-tuple.
2548///
2549/// Returns `{e1, …, e8}` in `env`; a fixed-arity form of
2550/// [`make_tuple_from_array`].
2551///
2552/// [`enif_make_tuple8`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_tuple8) — NIF 1.0 — OTP R13B04
2553#[allow(clippy::too_many_arguments)]
2554#[inline]
2555pub unsafe fn make_tuple8(
2556 env: *mut Env,
2557 e1: Term,
2558 e2: Term,
2559 e3: Term,
2560 e4: Term,
2561 e5: Term,
2562 e6: Term,
2563 e7: Term,
2564 e8: Term,
2565) -> Term {
2566 unsafe { (api().make_tuple)(env, 8, e1, e2, e3, e4, e5, e6, e7, e8) }
2567}
2568
2569/// Builds a 9-tuple.
2570///
2571/// Returns `{e1, …, e9}` in `env`; a fixed-arity form of
2572/// [`make_tuple_from_array`].
2573///
2574/// [`enif_make_tuple9`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_tuple9) — NIF 1.0 — OTP R13B04
2575#[allow(clippy::too_many_arguments)]
2576#[inline]
2577pub unsafe fn make_tuple9(
2578 env: *mut Env,
2579 e1: Term,
2580 e2: Term,
2581 e3: Term,
2582 e4: Term,
2583 e5: Term,
2584 e6: Term,
2585 e7: Term,
2586 e8: Term,
2587 e9: Term,
2588) -> Term {
2589 unsafe { (api().make_tuple)(env, 9, e1, e2, e3, e4, e5, e6, e7, e8, e9) }
2590}
2591
2592// ---------------------------------------------------------------------------
2593// Fixed-arity list constructors (call the variadic `enif_make_list`)
2594// ---------------------------------------------------------------------------
2595
2596/// Builds a 1-element list.
2597///
2598/// Returns `[e1]` in `env`; a fixed-arity form of [`make_list_from_array`].
2599///
2600/// [`enif_make_list1`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list1) — NIF 1.0 — OTP R13B04
2601#[inline]
2602pub unsafe fn make_list1(env: *mut Env, e1: Term) -> Term {
2603 unsafe { (api().make_list)(env, 1, e1) }
2604}
2605
2606/// Builds a 2-element list.
2607///
2608/// Returns `[e1, e2]` in `env`; a fixed-arity form of [`make_list_from_array`].
2609///
2610/// [`enif_make_list2`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list2) — NIF 1.0 — OTP R13B04
2611#[inline]
2612pub unsafe fn make_list2(env: *mut Env, e1: Term, e2: Term) -> Term {
2613 unsafe { (api().make_list)(env, 2, e1, e2) }
2614}
2615
2616/// Builds a 3-element list.
2617///
2618/// Returns `[e1, e2, e3]` in `env`; a fixed-arity form of
2619/// [`make_list_from_array`].
2620///
2621/// [`enif_make_list3`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list3) — NIF 1.0 — OTP R13B04
2622#[inline]
2623pub unsafe fn make_list3(env: *mut Env, e1: Term, e2: Term, e3: Term) -> Term {
2624 unsafe { (api().make_list)(env, 3, e1, e2, e3) }
2625}
2626
2627/// Builds a 4-element list.
2628///
2629/// Returns `[e1, …, e4]` in `env`; a fixed-arity form of
2630/// [`make_list_from_array`].
2631///
2632/// [`enif_make_list4`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list4) — NIF 1.0 — OTP R13B04
2633#[inline]
2634pub unsafe fn make_list4(env: *mut Env, e1: Term, e2: Term, e3: Term, e4: Term) -> Term {
2635 unsafe { (api().make_list)(env, 4, e1, e2, e3, e4) }
2636}
2637
2638/// Builds a 5-element list.
2639///
2640/// Returns `[e1, …, e5]` in `env`; a fixed-arity form of
2641/// [`make_list_from_array`].
2642///
2643/// [`enif_make_list5`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list5) — NIF 1.0 — OTP R13B04
2644#[inline]
2645pub unsafe fn make_list5(env: *mut Env, e1: Term, e2: Term, e3: Term, e4: Term, e5: Term) -> Term {
2646 unsafe { (api().make_list)(env, 5, e1, e2, e3, e4, e5) }
2647}
2648
2649/// Builds a 6-element list.
2650///
2651/// Returns `[e1, …, e6]` in `env`; a fixed-arity form of
2652/// [`make_list_from_array`].
2653///
2654/// [`enif_make_list6`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list6) — NIF 1.0 — OTP R13B04
2655#[inline]
2656pub unsafe fn make_list6(
2657 env: *mut Env,
2658 e1: Term,
2659 e2: Term,
2660 e3: Term,
2661 e4: Term,
2662 e5: Term,
2663 e6: Term,
2664) -> Term {
2665 unsafe { (api().make_list)(env, 6, e1, e2, e3, e4, e5, e6) }
2666}
2667
2668/// Builds a 7-element list.
2669///
2670/// Returns `[e1, …, e7]` in `env`; a fixed-arity form of
2671/// [`make_list_from_array`].
2672///
2673/// [`enif_make_list7`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list7) — NIF 1.0 — OTP R13B04
2674#[allow(clippy::too_many_arguments)]
2675#[inline]
2676pub unsafe fn make_list7(
2677 env: *mut Env,
2678 e1: Term,
2679 e2: Term,
2680 e3: Term,
2681 e4: Term,
2682 e5: Term,
2683 e6: Term,
2684 e7: Term,
2685) -> Term {
2686 unsafe { (api().make_list)(env, 7, e1, e2, e3, e4, e5, e6, e7) }
2687}
2688
2689/// Builds an 8-element list.
2690///
2691/// Returns `[e1, …, e8]` in `env`; a fixed-arity form of
2692/// [`make_list_from_array`].
2693///
2694/// [`enif_make_list8`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list8) — NIF 1.0 — OTP R13B04
2695#[allow(clippy::too_many_arguments)]
2696#[inline]
2697pub unsafe fn make_list8(
2698 env: *mut Env,
2699 e1: Term,
2700 e2: Term,
2701 e3: Term,
2702 e4: Term,
2703 e5: Term,
2704 e6: Term,
2705 e7: Term,
2706 e8: Term,
2707) -> Term {
2708 unsafe { (api().make_list)(env, 8, e1, e2, e3, e4, e5, e6, e7, e8) }
2709}
2710
2711/// Builds a 9-element list.
2712///
2713/// Returns `[e1, …, e9]` in `env`; a fixed-arity form of
2714/// [`make_list_from_array`].
2715///
2716/// [`enif_make_list9`](https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_make_list9) — NIF 1.0 — OTP R13B04
2717#[allow(clippy::too_many_arguments)]
2718#[inline]
2719pub unsafe fn make_list9(
2720 env: *mut Env,
2721 e1: Term,
2722 e2: Term,
2723 e3: Term,
2724 e4: Term,
2725 e5: Term,
2726 e6: Term,
2727 e7: Term,
2728 e8: Term,
2729 e9: Term,
2730) -> Term {
2731 unsafe { (api().make_list)(env, 9, e1, e2, e3, e4, e5, e6, e7, e8, e9) }
2732}