Skip to main content

enif_ffi/
types.rs

1//! Raw C ABI types and constants mirroring `erl_nif.h` and `erl_drv_nif.h`.
2//!
3//! Direct `#[repr(C)]` transcriptions — no logic, no safety wrappers. Prefixes
4//! are dropped per the crate naming convention; names that would shadow a Rust
5//! keyword or a `std` prelude item take a trailing underscore (`Option_`).
6//!
7//! Each item ends with a `[`ErlNif…`](…) — NIF x.y — OTP z` line naming the C
8//! entity and the release that introduced it; struct fields and enum variants
9//! added in a later release carry their own inline note. The crate floor is
10//! NIF 2.15 (OTP 22); anything newer is gated behind its rung.
11
12use std::ffi::{c_char, c_int, c_uint, c_void, CStr};
13use std::marker::{PhantomData, PhantomPinned};
14use std::ops::BitOr;
15
16// `SysIOVec` is platform-divergent; its definition lives in the active platform
17// module. Re-export it here so it sits with the rest of the type mirror and
18// reaches the crate root through `lib.rs`'s `pub use types::*`.
19#[cfg(unix)]
20pub use crate::unix::SysIOVec;
21#[cfg(windows)]
22pub use crate::windows::SysIOVec;
23
24// ---------------------------------------------------------------------------
25// Library version
26// ---------------------------------------------------------------------------
27
28/// The major NIF API version this build targets.
29///
30/// Always 2; the major number has not changed since the modern NIF API. Written
31/// into the library [`Entry`] reported to the BEAM at load.
32///
33/// [`ERL_NIF_MAJOR_VERSION`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_MAJOR_VERSION) — NIF 0.1 — OTP R13B03
34pub const MAJOR_VERSION: c_int = 2;
35
36/// The highest NIF minor version this build targets.
37///
38/// Set from the enabled feature rung (15, 16, 17, or 18) and written into the
39/// library [`Entry`]. The BEAM refuses to load the library if its own NIF
40/// version is lower than this.
41///
42/// [`ERL_NIF_MINOR_VERSION`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_MINOR_VERSION) — NIF 0.1 — OTP R13B03
43#[cfg(not(feature = "nif_2_16"))]
44pub const MINOR_VERSION: c_int = 15;
45#[cfg(all(feature = "nif_2_16", not(feature = "nif_2_17")))]
46pub const MINOR_VERSION: c_int = 16;
47#[cfg(all(feature = "nif_2_17", not(feature = "nif_2_18")))]
48pub const MINOR_VERSION: c_int = 17;
49#[cfg(feature = "nif_2_18")]
50pub const MINOR_VERSION: c_int = 18;
51
52/// The minimum ERTS version the library requires.
53///
54/// An `erts-X.Y` string tracking the enabled feature rung, written into the
55/// [`Entry`]. The BEAM refuses to load the library on an older runtime.
56///
57/// [`ERL_NIF_MIN_ERTS_VERSION`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_MIN_ERTS_VERSION) — NIF 2.14 — OTP 21
58#[cfg(not(feature = "nif_2_16"))]
59pub const MIN_ERTS_VERSION: &CStr = c"erts-10.4";
60#[cfg(all(feature = "nif_2_16", not(feature = "nif_2_17")))]
61pub const MIN_ERTS_VERSION: &CStr = c"erts-12.0";
62#[cfg(feature = "nif_2_17")]
63pub const MIN_ERTS_VERSION: &CStr = c"erts-14.0";
64
65/// The VM variant the library is built for.
66///
67/// Always `"beam.vanilla"`. Written into the [`Entry`]; the BEAM checks it
68/// against the running emulator at load.
69///
70/// [`ERL_NIF_VM_VARIANT`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_VM_VARIANT) — NIF 2.1 — OTP R14B02
71pub const VM_VARIANT: &CStr = c"beam.vanilla";
72
73// ---------------------------------------------------------------------------
74// Core term type
75// ---------------------------------------------------------------------------
76
77/// Any Erlang term, as an opaque tagged word.
78///
79/// A pointer-sized tagged machine word whose bit layout is private to the
80/// runtime. A NIF must only ever inspect or build terms through the `enif_*`
81/// functions, never by interpreting the integer directly.
82///
83/// [`ERL_NIF_TERM`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM) — NIF 0.1 — OTP R13B03
84pub type Term = usize;
85
86// ---------------------------------------------------------------------------
87// Opaque environment
88// ---------------------------------------------------------------------------
89
90/// A NIF environment that owns terms.
91///
92/// Always handled as `*mut Env` and never constructed by a NIF. A call
93/// environment is passed into each NIF and lives for the duration of the call; a
94/// process-independent one from [`alloc_env`](crate::alloc_env) lives until [`free_env`](crate::free_env). Every
95/// term is bound to some environment.
96///
97/// [`ErlNifEnv`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifEnv) — NIF 0.1 — OTP R13B03
98#[repr(C)]
99pub struct Env {
100    _opaque: [u8; 0],
101    _marker: PhantomData<(*mut u8, PhantomPinned)>,
102}
103
104// ---------------------------------------------------------------------------
105// Function and entry descriptors
106// ---------------------------------------------------------------------------
107
108/// The descriptor for a single exported NIF.
109///
110/// Pairs an Erlang function `name` and `arity` with the C function pointer
111/// `fptr`. `flags` is `0` for a regular NIF, or [`DIRTY_JOB_CPU_BOUND`] /
112/// [`DIRTY_JOB_IO_BOUND`] (cast to `c_uint`) for a dirty NIF; the `flags` field
113/// itself was added in NIF 2.7 (OTP 17.3).
114///
115/// [`ErlNifFunc`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifFunc) — NIF 0.1 — OTP R13B03
116#[repr(C)]
117pub struct Func {
118    pub name: *const c_char,
119    pub arity: c_uint,
120    pub fptr: unsafe extern "C" fn(env: *mut Env, argc: c_int, argv: *const Term) -> Term,
121    pub flags: c_uint,
122}
123
124/// The library descriptor the BEAM reads at load.
125///
126/// Built and returned by `nif_init`, it lists the module's functions and the
127/// load/upgrade/unload callbacks, plus version and metadata fields. All tail
128/// fields through `min_erts` are always present; an older BEAM simply reads
129/// fewer of them.
130///
131/// [`ErlNifEntry`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifEntry) — NIF 0.1 — OTP R13B03
132#[repr(C)]
133pub struct Entry {
134    pub major: c_int,
135    pub minor: c_int,
136    pub name: *const c_char,
137    pub num_of_funcs: c_int,
138    pub funcs: *mut Func,
139    pub load: Option<unsafe extern "C" fn(*mut Env, *mut *mut c_void, Term) -> c_int>,
140    pub reload: Option<unsafe extern "C" fn(*mut Env, *mut *mut c_void, Term) -> c_int>,
141    pub upgrade:
142        Option<unsafe extern "C" fn(*mut Env, *mut *mut c_void, *mut *mut c_void, Term) -> c_int>,
143    pub unload: Option<unsafe extern "C" fn(*mut Env, *mut c_void)>,
144    /// The VM variant the library was built for.
145    ///
146    /// Set to [`VM_VARIANT`]; the BEAM rejects a mismatch at load.
147    ///
148    /// NIF 2.1 (OTP R14B02).
149    pub vm_variant: *const c_char,
150    /// Options word signalling which tail fields are populated.
151    ///
152    /// Set to `1` to indicate that `sizeof_resource_type_init` is present,
153    /// otherwise `0`.
154    ///
155    /// NIF 2.7 (OTP 17.3).
156    pub options: c_uint,
157    /// Size of [`ResourceTypeInit`], for forward-compatible resources.
158    ///
159    /// Must equal `size_of::<ResourceTypeInit>()` so the BEAM knows how much of
160    /// the callback struct this build understands. Read only when `options` is
161    /// `1`.
162    ///
163    /// NIF 2.12 (OTP 20.0).
164    pub sizeof_resource_type_init: usize,
165    /// The minimum ERTS version the library requires.
166    ///
167    /// Set to [`MIN_ERTS_VERSION`]; the BEAM refuses to load on an older runtime.
168    ///
169    /// NIF 2.14 (OTP 21).
170    pub min_erts: *const c_char,
171}
172
173// ---------------------------------------------------------------------------
174// Binary
175// ---------------------------------------------------------------------------
176
177/// A binary's bytes, as a size and data pointer.
178///
179/// `size` and `data` describe the bytes; the `ref_bin`/`_spare` fields are
180/// BEAM-internal bookkeeping and must be left untouched. Filled by
181/// [`inspect_binary`](crate::inspect_binary) for borrowing, or [`alloc_binary`](crate::alloc_binary) for an owned, mutable
182/// binary.
183///
184/// [`ErlNifBinary`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifBinary) — NIF 0.1 — OTP R13B03
185#[repr(C)]
186pub struct Binary {
187    pub size: usize,
188    pub data: *mut u8,
189    ref_bin: *mut c_void,
190    _spare: [*mut c_void; 2],
191}
192
193// ---------------------------------------------------------------------------
194// Pid and Port
195// ---------------------------------------------------------------------------
196
197/// A local process identifier.
198///
199/// Wraps the pid term in `pid`. Obtained from [`self_`](crate::self_), [`get_local_pid`](crate::get_local_pid), or
200/// [`whereis_pid`](crate::whereis_pid), turned back into a term with [`make_pid`](crate::make_pid), and may be flagged
201/// undefined with [`set_pid_undefined`](crate::set_pid_undefined).
202///
203/// [`ErlNifPid`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifPid) — NIF 2.0 — OTP R14A
204#[repr(C)]
205#[derive(Clone, Copy)]
206pub struct Pid {
207    pub pid: Term,
208}
209
210/// A port identifier.
211///
212/// Wraps the port term in `port_id`. Obtained from [`get_local_port`](crate::get_local_port) or
213/// [`whereis_port`](crate::whereis_port).
214///
215/// [`ErlNifPort`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifPort) — NIF 2.11 — OTP 19
216#[repr(C)]
217#[derive(Clone, Copy)]
218pub struct Port {
219    pub port_id: Term,
220}
221
222// ---------------------------------------------------------------------------
223// Monitor
224// ---------------------------------------------------------------------------
225
226/// A process-monitor handle.
227///
228/// A 32-byte opaque value — the C type is also `ErlDrvMonitor` — always passed by
229/// pointer and never interpreted. Produced by [`monitor_process`](crate::monitor_process), ordered with
230/// [`compare_monitors`](crate::compare_monitors), and turned into a term with [`make_monitor_term`](crate::make_monitor_term).
231///
232/// [`ErlNifMonitor`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifMonitor) — NIF 2.12 — OTP 20
233#[repr(C, align(8))]
234#[derive(Clone, Copy)]
235pub struct Monitor(pub [u8; 32]);
236
237// ---------------------------------------------------------------------------
238// Resource type
239// ---------------------------------------------------------------------------
240
241/// A handle to a registered resource type.
242///
243/// An opaque value returned by [`open_resource_type`](crate::open_resource_type),
244/// [`open_resource_type_x`](crate::open_resource_type_x), or `init_resource_type`
245/// and passed to [`alloc_resource`](crate::alloc_resource) and
246/// [`get_resource`](crate::get_resource). Always handled as `*mut ResourceType`.
247///
248/// [`ErlNifResourceType`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifResourceType) — NIF 1.0 — OTP R13B04
249#[repr(C)]
250pub struct ResourceType {
251    _opaque: [u8; 0],
252    _marker: PhantomData<(*mut u8, PhantomPinned)>,
253}
254
255/// Callback table for resource type registration.
256///
257/// `members` must equal the number of callback fields provided, counting from
258/// the start: 1 = dtor, 2 = +stop, 3 = +down, 4 = +dyncall; `dyncall` was added
259/// in NIF 2.16 (OTP 24). The field is always present — set `members` to bound
260/// what the target BEAM understands.
261///
262/// [`ErlNifResourceTypeInit`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifResourceTypeInit) — NIF 2.12 — OTP 20
263#[repr(C)]
264pub struct ResourceTypeInit {
265    pub dtor: Option<unsafe extern "C" fn(*mut Env, *mut c_void)>,
266    pub stop: Option<unsafe extern "C" fn(*mut Env, *mut c_void, Event, c_int)>,
267    pub down: Option<unsafe extern "C" fn(*mut Env, *mut c_void, *mut Pid, *mut Monitor)>,
268    pub members: c_int,
269    pub dyncall: Option<unsafe extern "C" fn(*mut Env, *mut c_void, *mut c_void)>,
270}
271
272/// Create-or-take-over flags for registering a resource type.
273///
274/// Combine with `|`, e.g. `ResourceFlags::CREATE | ResourceFlags::TAKEOVER`.
275/// Passed to [`open_resource_type`](crate::open_resource_type) and friends, which report through their
276/// `tried` out-parameter which operation actually occurred.
277///
278/// [`ErlNifResourceFlags`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifResourceFlags) — NIF 1.0 — OTP R13B04
279#[repr(transparent)]
280#[derive(Clone, Copy, PartialEq, Eq)]
281pub struct ResourceFlags(pub c_int);
282
283impl ResourceFlags {
284    /// Register the name as a new resource type.
285    ///
286    /// Combine with [`ResourceFlags::TAKEOVER`] to accept either a fresh
287    /// registration or a takeover of an existing one.
288    ///
289    /// [`ERL_NIF_RT_CREATE`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_RT_CREATE) — NIF 1.0 — OTP R13B04
290    pub const CREATE: Self = Self(1);
291    /// Take over an existing resource type during a code upgrade.
292    ///
293    /// Lets the new library inherit a type registered by the version it replaces.
294    /// Combine with [`ResourceFlags::CREATE`] to allow either.
295    ///
296    /// [`ERL_NIF_RT_TAKEOVER`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_RT_TAKEOVER) — NIF 1.0 — OTP R13B04
297    pub const TAKEOVER: Self = Self(2);
298}
299
300impl BitOr for ResourceFlags {
301    type Output = Self;
302    fn bitor(self, rhs: Self) -> Self {
303        Self(self.0 | rhs.0)
304    }
305}
306
307// ---------------------------------------------------------------------------
308// OS event handle (for enif_select)
309// ---------------------------------------------------------------------------
310
311/// An OS event handle for use with [`select`](crate::select).
312///
313/// A file descriptor on Unix (`c_int`) or a `HANDLE` on Windows (`*mut c_void`).
314/// Registered for readiness notifications through [`select`](crate::select), with a resource
315/// owning its lifetime.
316///
317/// [`ErlNifEvent`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifEvent) — NIF 2.12 — OTP 20
318#[cfg(unix)]
319pub type Event = c_int;
320#[cfg(windows)]
321pub type Event = *mut c_void;
322
323// ---------------------------------------------------------------------------
324// Map iterator
325// ---------------------------------------------------------------------------
326
327/// Starting position for a map iterator.
328///
329/// [`ErlNifMapIteratorEntry`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifMapIteratorEntry) — NIF 2.6 — OTP 17
330#[repr(i32)]
331#[derive(Clone, Copy, PartialEq, Eq)]
332pub enum MapIteratorEntry {
333    /// Start iterating at the first entry.
334    ///
335    /// [`ERL_NIF_MAP_ITERATOR_FIRST`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_MAP_ITERATOR_FIRST) — NIF 2.6 — OTP 17
336    First = 1,
337    /// Start iterating at the last entry.
338    ///
339    /// [`ERL_NIF_MAP_ITERATOR_LAST`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_MAP_ITERATOR_LAST) — NIF 2.6 — OTP 17
340    Last = 2,
341}
342
343#[repr(C)]
344#[derive(Clone, Copy)]
345struct MapIteratorFlat {
346    ks: *mut Term,
347    vs: *mut Term,
348}
349
350#[repr(C)]
351#[derive(Clone, Copy)]
352struct MapIteratorHash {
353    wstack: *mut c_void,
354    kv: *mut Term,
355}
356
357#[repr(C)]
358union MapIteratorUnion {
359    flat: MapIteratorFlat,
360    hash: MapIteratorHash,
361}
362
363/// A cursor for iterating a map's entries.
364///
365/// Only `map` is public; the remaining fields are BEAM-internal. Initialized by
366/// [`map_iterator_create`](crate::map_iterator_create) and released by [`map_iterator_destroy`](crate::map_iterator_destroy), it must not
367/// be moved after initialization. Iteration order is unspecified.
368///
369/// [`ErlNifMapIterator`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifMapIterator) — NIF 2.6 — OTP 17
370#[repr(C)]
371pub struct MapIterator {
372    pub map: Term,
373    size: usize,
374    idx: usize,
375    u: MapIteratorUnion,
376    _spare: [*mut c_void; 2],
377}
378
379// ---------------------------------------------------------------------------
380// Term type tag
381// ---------------------------------------------------------------------------
382
383/// The canonical term types returned by `term_type`.
384///
385/// The C header reserves a `-1` sentinel and may add new types, so an
386/// unrecognized code must never be transmuted into this enum.
387///
388/// [`ErlNifTermType`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifTermType) — NIF 2.15 — OTP 22
389#[repr(i32)]
390#[derive(Clone, Copy, PartialEq, Eq, Debug)]
391pub enum TermType {
392    /// Matches an atom.
393    ///
394    /// [`ERL_NIF_TERM_TYPE_ATOM`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_ATOM) — NIF 2.15 — OTP 22
395    Atom = 1,
396    /// Matches a bitstring (binaries included).
397    ///
398    /// [`ERL_NIF_TERM_TYPE_BITSTRING`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_BITSTRING) — NIF 2.15 — OTP 22
399    Bitstring = 2,
400    /// Matches a float.
401    ///
402    /// [`ERL_NIF_TERM_TYPE_FLOAT`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_FLOAT) — NIF 2.15 — OTP 22
403    Float = 3,
404    /// Matches a fun.
405    ///
406    /// [`ERL_NIF_TERM_TYPE_FUN`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_FUN) — NIF 2.15 — OTP 22
407    Fun = 4,
408    /// Matches an integer.
409    ///
410    /// [`ERL_NIF_TERM_TYPE_INTEGER`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_INTEGER) — NIF 2.15 — OTP 22
411    Integer = 5,
412    /// Matches a list (the empty list included).
413    ///
414    /// [`ERL_NIF_TERM_TYPE_LIST`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_LIST) — NIF 2.15 — OTP 22
415    List = 6,
416    /// Matches a map.
417    ///
418    /// [`ERL_NIF_TERM_TYPE_MAP`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_MAP) — NIF 2.15 — OTP 22
419    Map = 7,
420    /// Matches a pid.
421    ///
422    /// [`ERL_NIF_TERM_TYPE_PID`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_PID) — NIF 2.15 — OTP 22
423    Pid = 8,
424    /// Matches a port.
425    ///
426    /// [`ERL_NIF_TERM_TYPE_PORT`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_PORT) — NIF 2.15 — OTP 22
427    Port = 9,
428    /// Matches a reference.
429    ///
430    /// [`ERL_NIF_TERM_TYPE_REFERENCE`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_REFERENCE) — NIF 2.15 — OTP 22
431    Reference = 10,
432    /// Matches a tuple.
433    ///
434    /// [`ERL_NIF_TERM_TYPE_TUPLE`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TERM_TYPE_TUPLE) — NIF 2.15 — OTP 22
435    Tuple = 11,
436}
437
438impl TermType {
439    /// Map a raw `term_type` return code to a known variant, or `None` for any
440    /// code outside the canonical `1..=11` (an unknown/future term type).
441    pub fn from_raw(code: c_int) -> Option<Self> {
442        match code {
443            1 => Some(Self::Atom),
444            2 => Some(Self::Bitstring),
445            3 => Some(Self::Float),
446            4 => Some(Self::Fun),
447            5 => Some(Self::Integer),
448            6 => Some(Self::List),
449            7 => Some(Self::Map),
450            8 => Some(Self::Pid),
451            9 => Some(Self::Port),
452            10 => Some(Self::Reference),
453            11 => Some(Self::Tuple),
454            _ => None,
455        }
456    }
457}
458
459// ---------------------------------------------------------------------------
460// Character encoding
461// ---------------------------------------------------------------------------
462
463/// Encoding for reading and writing atom and string bytes.
464///
465/// Selects how the byte buffer in functions like [`make_atom`](crate::make_atom), [`get_string`](crate::get_string),
466/// and [`make_string`](crate::make_string) is interpreted. `Latin1` is one byte per character;
467/// `Utf8` (NIF 2.17) is variable-width.
468///
469/// [`ErlNifCharEncoding`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifCharEncoding) — NIF 1.0 — OTP R13B04
470#[repr(i32)]
471#[derive(Clone, Copy, PartialEq, Eq)]
472pub enum CharEncoding {
473    /// Latin-1 (ISO-8859-1).
474    ///
475    /// [`ERL_NIF_LATIN1`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_LATIN1) — NIF 1.0 — OTP R13B04
476    Latin1 = 1,
477    /// UTF-8.
478    ///
479    /// [`ERL_NIF_UTF8`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_UTF8) — NIF 2.17 — OTP 26
480    #[cfg(feature = "nif_2_17")]
481    Utf8 = 2,
482}
483
484// ---------------------------------------------------------------------------
485// Time
486// ---------------------------------------------------------------------------
487
488/// A time value in BEAM time units.
489///
490/// A signed 64-bit count whose unit is given by an accompanying [`TimeUnit`].
491/// Monotonic times are frequently negative; see [`monotonic_time`](crate::monotonic_time).
492///
493/// [`ErlNifTime`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifTime) — NIF 2.10 — OTP 18.3
494pub type Time = i64;
495
496/// Sentinel returned by the time functions on error.
497///
498/// Equal to `i64::MIN`. Returned when a time value cannot be represented in the
499/// requested [`TimeUnit`].
500///
501/// [`ERL_NIF_TIME_ERROR`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TIME_ERROR) — NIF 2.10 — OTP 18.3
502pub const TIME_ERROR: Time = i64::MIN;
503
504/// The unit of a [`Time`] value.
505///
506/// Selects the unit passed to or returned by [`monotonic_time`](crate::monotonic_time), [`time_offset`](crate::time_offset),
507/// and [`convert_time_unit`](crate::convert_time_unit).
508///
509/// [`ErlNifTimeUnit`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifTimeUnit) — NIF 2.10 — OTP 18.3
510#[repr(i32)]
511#[derive(Clone, Copy, PartialEq, Eq, Debug)]
512pub enum TimeUnit {
513    /// Seconds.
514    ///
515    /// [`ERL_NIF_SEC`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SEC) — NIF 2.10 — OTP 18.3
516    Second = 0,
517    /// Milliseconds.
518    ///
519    /// [`ERL_NIF_MSEC`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_MSEC) — NIF 2.10 — OTP 18.3
520    Millisecond = 1,
521    /// Microseconds.
522    ///
523    /// [`ERL_NIF_USEC`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_USEC) — NIF 2.10 — OTP 18.3
524    Microsecond = 2,
525    /// Nanoseconds.
526    ///
527    /// [`ERL_NIF_NSEC`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_NSEC) — NIF 2.10 — OTP 18.3
528    Nanosecond = 3,
529}
530
531// ---------------------------------------------------------------------------
532// Unique integer flags
533// ---------------------------------------------------------------------------
534
535/// Flags shaping the result of [`make_unique_integer`](crate::make_unique_integer). Combine with `|`.
536///
537/// The same options as `erlang:unique_integer/1`. With no flags the integer is
538/// merely unique and may be negative; the flags constrain it to be positive
539/// and/or strictly monotonic.
540///
541/// [`ErlNifUniqueInteger`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifUniqueInteger) — NIF 2.11 — OTP 19
542#[repr(transparent)]
543#[derive(Clone, Copy, PartialEq, Eq)]
544pub struct UniqueInteger(pub c_int);
545
546impl UniqueInteger {
547    /// Return a positive integer only.
548    ///
549    /// [`ERL_NIF_UNIQUE_POSITIVE`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_UNIQUE_POSITIVE) — NIF 2.11 — OTP 19
550    pub const POSITIVE: Self = Self(1 << 0);
551    /// Return a strictly monotonic integer.
552    ///
553    /// [`ERL_NIF_UNIQUE_MONOTONIC`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_UNIQUE_MONOTONIC) — NIF 2.11 — OTP 19
554    pub const MONOTONIC: Self = Self(1 << 1);
555}
556
557impl BitOr for UniqueInteger {
558    type Output = Self;
559    fn bitor(self, rhs: Self) -> Self {
560        Self(self.0 | rhs.0)
561    }
562}
563
564// ---------------------------------------------------------------------------
565// Hash
566// ---------------------------------------------------------------------------
567
568/// The hash algorithm selector for [`hash`](crate::hash).
569///
570/// Chooses between a fast non-portable internal hash and the portable `phash2`
571/// that matches `erlang:phash2/1`.
572///
573/// [`ErlNifHash`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifHash) — NIF 2.12 — OTP 20
574#[repr(i32)]
575#[derive(Clone, Copy, PartialEq, Eq, Debug)]
576pub enum Hash {
577    /// Non-portable internal hash; fast, but may change between ERTS versions.
578    ///
579    /// [`ERL_NIF_INTERNAL_HASH`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_INTERNAL_HASH) — NIF 2.12 — OTP 20
580    InternalHash = 1,
581    /// Portable `phash2` hash, matching `erlang:phash2/1`.
582    ///
583    /// [`ERL_NIF_PHASH2`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_PHASH2) — NIF 2.12 — OTP 20
584    Phash2 = 2,
585}
586
587// ---------------------------------------------------------------------------
588// Select (I/O event multiplexing)
589// ---------------------------------------------------------------------------
590
591/// Mode flags for [`select`](crate::select). Combine with `|`.
592///
593/// For example `SelectFlags::READ | SelectFlags::CUSTOM_MSG`. Defined in
594/// `erl_drv_nif.h`; each flag carries its own introduction version, as the
595/// cancel, custom-message, and error modes were added after the base ones.
596///
597/// [`ErlNifSelectFlags`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifSelectFlags) — NIF 2.12 — OTP 20
598#[repr(transparent)]
599#[derive(Clone, Copy, PartialEq, Eq)]
600pub struct SelectFlags(pub c_int);
601
602impl SelectFlags {
603    /// Select for read readiness.
604    ///
605    /// [`ERL_NIF_SELECT_READ`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_READ) — NIF 2.12 — OTP 20
606    pub const READ: Self = Self(1 << 0);
607    /// Select for write readiness.
608    ///
609    /// [`ERL_NIF_SELECT_WRITE`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_WRITE) — NIF 2.12 — OTP 20
610    pub const WRITE: Self = Self(1 << 1);
611    /// Stop selecting on the event and trigger the resource stop callback.
612    ///
613    /// The safe way to retire an OS event before closing it: any active read/write
614    /// selections are cancelled first, then the resource's stop callback is called
615    /// — directly or scheduled — once no notification can still be in flight. The
616    /// event must not be closed until that callback has run. `pid` and `ref` are
617    /// ignored.
618    ///
619    /// [`ERL_NIF_SELECT_STOP`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_STOP) — NIF 2.12 — OTP 20
620    pub const STOP: Self = Self(1 << 2);
621    /// Cancel a pending read or write select without stopping.
622    ///
623    /// Combine with [`SelectFlags::READ`] and/or [`SelectFlags::WRITE`] to choose
624    /// which selections to cancel; `pid` and `ref` are ignored. The return
625    /// value's `*_CANCELLED` bits report whether each was actually removed or
626    /// whether a notification may already have been sent.
627    ///
628    /// [`ERL_NIF_SELECT_CANCEL`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_CANCEL) — NIF 2.15 — OTP 22
629    pub const CANCEL: Self = Self(1 << 3);
630    /// Deliver `msg` as a custom message instead of the default select message.
631    ///
632    /// [`ERL_NIF_SELECT_CUSTOM_MSG`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_CUSTOM_MSG) — NIF 2.15 — OTP 22
633    pub const CUSTOM_MSG: Self = Self(1 << 4);
634    /// Select for error conditions on the event.
635    ///
636    /// [`ERL_NIF_SELECT_ERROR`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_ERROR) — NIF 2.16 — OTP 24
637    #[cfg(feature = "nif_2_16")]
638    pub const ERROR: Self = Self(1 << 5);
639}
640
641impl BitOr for SelectFlags {
642    type Output = Self;
643    fn bitor(self, rhs: Self) -> Self {
644        Self(self.0 | rhs.0)
645    }
646}
647
648/// `select`'s stop callback ran on the calling thread.
649///
650/// A success bit in the value returned by [`select`](crate::select) /
651/// [`select_x`](crate::select_x): the resource's stop callback was invoked
652/// directly, so the event is fully retired on return. Test it with bitwise AND.
653///
654/// [`ERL_NIF_SELECT_STOP_CALLED`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_STOP_CALLED) — NIF 2.12 — OTP 20
655pub const SELECT_STOP_CALLED: c_int = 1 << 0;
656/// `select`'s stop callback was scheduled to run later.
657///
658/// A success bit: the stop callback could not run synchronously and was scheduled
659/// to run later, on this or another thread, so the event is not yet retired when
660/// [`select`](crate::select) returns.
661///
662/// [`ERL_NIF_SELECT_STOP_SCHEDULED`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_STOP_SCHEDULED) — NIF 2.12 — OTP 20
663pub const SELECT_STOP_SCHEDULED: c_int = 1 << 1;
664/// `select` was given an invalid event object.
665///
666/// A failure bit — the [`select`](crate::select) return value is negative —
667/// meaning `event` was not a valid OS event object.
668///
669/// [`ERL_NIF_SELECT_INVALID_EVENT`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_INVALID_EVENT) — NIF 2.12 — OTP 20
670pub const SELECT_INVALID_EVENT: c_int = 1 << 2;
671/// `select` failed to add the event to the poll set.
672///
673/// A failure bit (negative return): the underlying system call could not add the
674/// event object to the poll set.
675///
676/// [`ERL_NIF_SELECT_FAILED`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_FAILED) — NIF 2.12 — OTP 20
677pub const SELECT_FAILED: c_int = 1 << 3;
678/// A pending read `select` was cancelled.
679///
680/// A success bit: a read selection was removed by [`SelectFlags::CANCEL`] or
681/// [`SelectFlags::STOP`] and is guaranteed not to produce a further `ready_input`
682/// message.
683///
684/// [`ERL_NIF_SELECT_READ_CANCELLED`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_READ_CANCELLED) — NIF 2.15 — OTP 22
685pub const SELECT_READ_CANCELLED: c_int = 1 << 4;
686/// A pending write `select` was cancelled.
687///
688/// A success bit: a write selection was removed by [`SelectFlags::CANCEL`] or
689/// [`SelectFlags::STOP`] and is guaranteed not to produce a further
690/// `ready_output` message.
691///
692/// [`ERL_NIF_SELECT_WRITE_CANCELLED`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_WRITE_CANCELLED) — NIF 2.15 — OTP 22
693pub const SELECT_WRITE_CANCELLED: c_int = 1 << 5;
694/// A pending error `select` was cancelled.
695///
696/// A success bit: an error selection (see [`SelectFlags::ERROR`]) was removed by
697/// [`SelectFlags::CANCEL`] or [`SelectFlags::STOP`].
698///
699/// [`ERL_NIF_SELECT_ERROR_CANCELLED`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_ERROR_CANCELLED) — NIF 2.16 — OTP 24
700#[cfg(feature = "nif_2_16")]
701pub const SELECT_ERROR_CANCELLED: c_int = 1 << 6;
702/// The requested `select` mode is not supported for the event object.
703///
704/// A failure bit (negative return): the requested mode — typically
705/// [`SelectFlags::ERROR`] — is not supported for this event object on this
706/// platform.
707///
708/// [`ERL_NIF_SELECT_NOTSUP`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_NOTSUP) — NIF 2.16 — OTP 24
709#[cfg(feature = "nif_2_16")]
710pub const SELECT_NOTSUP: c_int = 1 << 7;
711
712// ---------------------------------------------------------------------------
713// binary_to_term options
714// ---------------------------------------------------------------------------
715
716/// Safe decoding for `binary_to_term`: reject encoded atoms that don't already
717/// exist.
718///
719/// [`ERL_NIF_BIN2TERM_SAFE`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_BIN2TERM_SAFE) — NIF 2.11 — OTP 19
720pub const BIN2TERM_SAFE: c_uint = 0x2000_0000;
721
722// ---------------------------------------------------------------------------
723// System info
724// ---------------------------------------------------------------------------
725
726/// A snapshot of BEAM runtime information.
727///
728/// Filled by [`system_info`](crate::system_info) (the C type is also `ErlDrvSysInfo`): ERTS and OTP
729/// version strings, the NIF and driver version numbers, scheduler counts, and the
730/// SMP, thread, and dirty-scheduler support flags.
731///
732/// [`ErlNifSysInfo`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifSysInfo) — NIF 1.0 — OTP R13B04
733#[repr(C)]
734pub struct SysInfo {
735    pub driver_major_version: c_int,
736    pub driver_minor_version: c_int,
737    pub erts_version: *mut c_char,
738    pub otp_release: *mut c_char,
739    pub thread_support: c_int,
740    pub smp_support: c_int,
741    pub async_threads: c_int,
742    pub scheduler_threads: c_int,
743    pub nif_major_version: c_int,
744    pub nif_minor_version: c_int,
745    pub dirty_scheduler_support: c_int,
746}
747
748// ---------------------------------------------------------------------------
749// NIF options (enif_set_option) — NIF 2.17 (OTP 26.0)
750// ---------------------------------------------------------------------------
751
752/// The key selecting which runtime option `set_option` sets.
753///
754/// Used by the [`set_option_delay_halt`](crate::set_option_delay_halt), [`set_option_on_halt`](crate::set_option_on_halt), and
755/// [`set_option_on_unload_thread`](crate::set_option_on_unload_thread) wrappers. The trailing underscore avoids
756/// shadowing the `std` prelude `Option`.
757///
758/// [`ErlNifOption`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifOption) — NIF 2.17 — OTP 26
759#[cfg(feature = "nif_2_17")]
760#[repr(i32)]
761#[derive(Clone, Copy, PartialEq, Eq, Debug)]
762pub enum Option_ {
763    /// Delay runtime-system halt until running NIF calls have returned.
764    ///
765    /// [`ERL_NIF_OPT_DELAY_HALT`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_OPT_DELAY_HALT) — NIF 2.17 — OTP 26
766    DelayHalt = 1,
767    /// Register an on-halt callback, run when the runtime system halts.
768    ///
769    /// [`ERL_NIF_OPT_ON_HALT`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_OPT_ON_HALT) — NIF 2.17 — OTP 26
770    OnHalt = 2,
771    /// Register an on-unload-thread callback. Added within the 2.17 line, so
772    /// passing it to an OTP-26 runtime is a caller error.
773    ///
774    /// [`ERL_NIF_OPT_ON_UNLOAD_THREAD`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_OPT_ON_UNLOAD_THREAD) — NIF 2.17 — OTP 27
775    OnUnloadThread = 3,
776}
777
778// ---------------------------------------------------------------------------
779// Thread type (return values from enif_thread_type)
780// ---------------------------------------------------------------------------
781
782/// Not a scheduler thread.
783///
784/// [`ERL_NIF_THR_UNDEFINED`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_THR_UNDEFINED) — NIF 2.11 — OTP 19
785pub const THR_UNDEFINED: c_int = 0;
786/// Normal BEAM scheduler thread.
787///
788/// [`ERL_NIF_THR_NORMAL_SCHEDULER`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_THR_NORMAL_SCHEDULER) — NIF 2.11 — OTP 19
789pub const THR_NORMAL_SCHEDULER: c_int = 1;
790/// Dirty CPU scheduler thread.
791///
792/// [`ERL_NIF_THR_DIRTY_CPU_SCHEDULER`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_THR_DIRTY_CPU_SCHEDULER) — NIF 2.11 — OTP 19
793pub const THR_DIRTY_CPU_SCHEDULER: c_int = 2;
794/// Dirty I/O scheduler thread.
795///
796/// [`ERL_NIF_THR_DIRTY_IO_SCHEDULER`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_THR_DIRTY_IO_SCHEDULER) — NIF 2.11 — OTP 19
797pub const THR_DIRTY_IO_SCHEDULER: c_int = 3;
798
799// ---------------------------------------------------------------------------
800// Dirty scheduler flags
801// ---------------------------------------------------------------------------
802// The two `ERL_NIF_DIRTY_JOB_*` constants. They apply to both the
803// `enif_schedule_nif` `flags` argument and the [`Func::flags`] field (the
804// latter is `c_uint`, so cast there); a regular NIF is just `0`.
805
806/// Run on a dirty CPU scheduler.
807///
808/// [`ERL_NIF_DIRTY_JOB_CPU_BOUND`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_DIRTY_JOB_CPU_BOUND) — NIF 2.6 — OTP 17
809pub const DIRTY_JOB_CPU_BOUND: c_int = 1;
810/// Run on a dirty I/O scheduler.
811///
812/// [`ERL_NIF_DIRTY_JOB_IO_BOUND`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_DIRTY_JOB_IO_BOUND) — NIF 2.6 — OTP 17
813pub const DIRTY_JOB_IO_BOUND: c_int = 2;
814
815// ---------------------------------------------------------------------------
816// I/O queue and iovec
817// ---------------------------------------------------------------------------
818
819/// An opaque I/O queue handle.
820///
821/// A FIFO of binary data used to stage output without copying. Created with
822/// [`ioq_create`](crate::ioq_create) and destroyed with [`ioq_destroy`](crate::ioq_destroy); always handled as
823/// `*mut IOQueue`.
824///
825/// [`ErlNifIOQueue`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifIOQueue) — NIF 2.12 — OTP 20.1
826#[repr(C)]
827pub struct IOQueue {
828    _opaque: [u8; 0],
829    _marker: PhantomData<(*mut u8, PhantomPinned)>,
830}
831
832/// Creation mode for an I/O queue.
833///
834/// The `opts` argument to [`ioq_create`](crate::ioq_create); the only defined value is
835/// [`IOQ_NORMAL`].
836///
837/// [`ErlNifIOQueueOpts`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifIOQueueOpts) — NIF 2.12 — OTP 20.1
838pub type IOQueueOpts = c_int;
839
840/// Normal I/O queue mode.
841///
842/// [`ERL_NIF_IOQ_NORMAL`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_IOQ_NORMAL) — NIF 2.12 — OTP 20.1
843pub const IOQ_NORMAL: IOQueueOpts = 1;
844
845/// A scatter/gather I/O vector.
846///
847/// `iovcnt` [`SysIOVec`] segments at `iov` spanning `size` total bytes; the
848/// remaining fields are BEAM-internal. Produced from an iolist by
849/// [`inspect_iovec`](crate::inspect_iovec) and consumed by [`ioq_enqv`](crate::ioq_enqv).
850///
851/// [`ErlNifIOVec`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifIOVec) — NIF 2.12 — OTP 20.1
852#[repr(C)]
853pub struct IOVec {
854    pub iovcnt: c_int,
855    pub size: usize,
856    pub iov: *mut SysIOVec,
857    ref_bins: *mut *mut c_void,
858    flags: c_int,
859    small_iov: [SysIOVec; 16],
860    small_ref_bin: [*mut c_void; 16],
861}
862
863// ---------------------------------------------------------------------------
864// Opaque thread-primitive handles
865// ---------------------------------------------------------------------------
866
867/// An opaque mutex handle.
868///
869/// Created with [`mutex_create`](crate::mutex_create) and destroyed with [`mutex_destroy`](crate::mutex_destroy); always
870/// handled as `*mut Mutex`.
871///
872/// [`ErlNifMutex`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifMutex) — NIF 1.0 — OTP R13B04
873#[repr(C)]
874pub struct Mutex {
875    _opaque: [u8; 0],
876    _marker: PhantomData<(*mut u8, PhantomPinned)>,
877}
878
879/// An opaque condition variable handle.
880///
881/// Created with [`cond_create`](crate::cond_create) and destroyed with [`cond_destroy`](crate::cond_destroy); waited on
882/// with [`cond_wait`](crate::cond_wait). Always handled as `*mut Cond`.
883///
884/// [`ErlNifCond`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifCond) — NIF 1.0 — OTP R13B04
885#[repr(C)]
886pub struct Cond {
887    _opaque: [u8; 0],
888    _marker: PhantomData<(*mut u8, PhantomPinned)>,
889}
890
891/// An opaque read/write lock handle.
892///
893/// Created with [`rwlock_create`](crate::rwlock_create) and destroyed with [`rwlock_destroy`](crate::rwlock_destroy); always
894/// handled as `*mut RWLock`.
895///
896/// [`ErlNifRWLock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifRWLock) — NIF 1.0 — OTP R13B04
897#[repr(C)]
898pub struct RWLock {
899    _opaque: [u8; 0],
900    _marker: PhantomData<(*mut u8, PhantomPinned)>,
901}
902
903/// A thread identifier.
904///
905/// Returned by [`thread_self`](crate::thread_self), written by [`thread_create`](crate::thread_create), and compared with
906/// [`equal_tids`](crate::equal_tids). An opaque pointer (in C, `struct ErlDrvTid_ *`).
907///
908/// [`ErlNifTid`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifTid) — NIF 1.0 — OTP R13B04
909pub type Tid = *mut c_void;
910
911/// A thread-specific data key.
912///
913/// Created with [`tsd_key_create`](crate::tsd_key_create); each thread stores and reads its own pointer
914/// for the key with [`tsd_set`](crate::tsd_set) and [`tsd_get`](crate::tsd_get).
915///
916/// [`ErlNifTSDKey`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifTSDKey) — NIF 1.0 — OTP R13B04
917pub type TSDKey = c_int;
918
919/// Options for creating a thread.
920///
921/// Allocated with [`thread_opts_create`](crate::thread_opts_create) and passed to [`thread_create`](crate::thread_create). The
922/// single field `suggested_stack_size` is a stack-size suggestion in kilowords;
923/// a value below zero requests the default size.
924///
925/// [`ErlNifThreadOpts`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifThreadOpts) — NIF 1.0 — OTP R13B04
926#[repr(C)]
927pub struct ThreadOpts {
928    pub suggested_stack_size: c_int,
929}