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 `sizeof(void*) * 4`-byte opaque value — the C type is also `ErlDrvMonitor` —
229/// always passed by 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/// The length tracks the C definition `unsigned char data[sizeof(void*)*4]`
233/// (32 bytes on 64-bit, 16 on 32-bit) rather than a hardcoded 32, and the type
234/// carries no forced alignment — the C struct is a bare `char` array (align 1),
235/// so there is none to match.
236///
237/// [`ErlNifMonitor`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifMonitor) — NIF 2.12 — OTP 20
238#[repr(C)]
239#[derive(Clone, Copy)]
240pub struct Monitor(pub [u8; core::mem::size_of::<*const ()>() * 4]);
241
242// Pin the layout to the C ABI so a future edit cannot silently change it: the
243// mismatch would only show as memory corruption at the enif boundary, never a
244// failing test. `sizeof(void*)*4` bytes, align 1 (a bare `char` array).
245const _: () = assert!(
246    core::mem::size_of::<Monitor>() == core::mem::size_of::<*const ()>() * 4
247        && core::mem::align_of::<Monitor>() == 1,
248);
249
250// ---------------------------------------------------------------------------
251// Resource type
252// ---------------------------------------------------------------------------
253
254/// A handle to a registered resource type.
255///
256/// An opaque value returned by [`open_resource_type`](crate::open_resource_type),
257/// [`open_resource_type_x`](crate::open_resource_type_x), or `init_resource_type`
258/// and passed to [`alloc_resource`](crate::alloc_resource) and
259/// [`get_resource`](crate::get_resource). Always handled as `*mut ResourceType`.
260///
261/// [`ErlNifResourceType`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifResourceType) — NIF 1.0 — OTP R13B04
262#[repr(C)]
263pub struct ResourceType {
264    _opaque: [u8; 0],
265    _marker: PhantomData<(*mut u8, PhantomPinned)>,
266}
267
268/// Callback table for resource type registration.
269///
270/// `members` must equal the number of callback fields provided, counting from
271/// the start: 1 = dtor, 2 = +stop, 3 = +down, 4 = +dyncall; `dyncall` was added
272/// in NIF 2.16 (OTP 24). The field is always present — set `members` to bound
273/// what the target BEAM understands.
274///
275/// [`ErlNifResourceTypeInit`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifResourceTypeInit) — NIF 2.12 — OTP 20
276#[repr(C)]
277pub struct ResourceTypeInit {
278    pub dtor: Option<unsafe extern "C" fn(*mut Env, *mut c_void)>,
279    pub stop: Option<unsafe extern "C" fn(*mut Env, *mut c_void, Event, c_int)>,
280    pub down: Option<unsafe extern "C" fn(*mut Env, *mut c_void, *mut Pid, *mut Monitor)>,
281    pub members: c_int,
282    pub dyncall: Option<unsafe extern "C" fn(*mut Env, *mut c_void, *mut c_void)>,
283}
284
285/// Create-or-take-over flags for registering a resource type.
286///
287/// Combine with `|`, e.g. `ResourceFlags::CREATE | ResourceFlags::TAKEOVER`.
288/// Passed to [`open_resource_type`](crate::open_resource_type) and friends, which report through their
289/// `tried` out-parameter which operation actually occurred.
290///
291/// [`ErlNifResourceFlags`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifResourceFlags) — NIF 1.0 — OTP R13B04
292#[repr(transparent)]
293#[derive(Clone, Copy, PartialEq, Eq)]
294pub struct ResourceFlags(pub c_int);
295
296impl ResourceFlags {
297    /// Register the name as a new resource type.
298    ///
299    /// Combine with [`ResourceFlags::TAKEOVER`] to accept either a fresh
300    /// registration or a takeover of an existing one.
301    ///
302    /// [`ERL_NIF_RT_CREATE`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_RT_CREATE) — NIF 1.0 — OTP R13B04
303    pub const CREATE: Self = Self(1);
304    /// Take over an existing resource type during a code upgrade.
305    ///
306    /// Lets the new library inherit a type registered by the version it replaces.
307    /// Combine with [`ResourceFlags::CREATE`] to allow either.
308    ///
309    /// [`ERL_NIF_RT_TAKEOVER`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_RT_TAKEOVER) — NIF 1.0 — OTP R13B04
310    pub const TAKEOVER: Self = Self(2);
311}
312
313impl BitOr for ResourceFlags {
314    type Output = Self;
315    fn bitor(self, rhs: Self) -> Self {
316        Self(self.0 | rhs.0)
317    }
318}
319
320// ---------------------------------------------------------------------------
321// OS event handle (for enif_select)
322// ---------------------------------------------------------------------------
323
324/// An OS event handle for use with [`select`](crate::select).
325///
326/// A file descriptor on Unix (`c_int`) or a `HANDLE` on Windows (`*mut c_void`).
327/// Registered for readiness notifications through [`select`](crate::select), with a resource
328/// owning its lifetime.
329///
330/// [`ErlNifEvent`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifEvent) — NIF 2.12 — OTP 20
331#[cfg(unix)]
332pub type Event = c_int;
333#[cfg(windows)]
334pub type Event = *mut c_void;
335
336// ---------------------------------------------------------------------------
337// Map iterator
338// ---------------------------------------------------------------------------
339
340/// Starting position for a map iterator.
341///
342/// [`ErlNifMapIteratorEntry`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifMapIteratorEntry) — NIF 2.6 — OTP 17
343#[repr(i32)]
344#[derive(Clone, Copy, PartialEq, Eq)]
345pub enum MapIteratorEntry {
346    /// Start iterating at the first entry.
347    ///
348    /// [`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
349    First = 1,
350    /// Start iterating at the last entry.
351    ///
352    /// [`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
353    Last = 2,
354}
355
356#[repr(C)]
357#[derive(Clone, Copy)]
358struct MapIteratorFlat {
359    ks: *mut Term,
360    vs: *mut Term,
361}
362
363#[repr(C)]
364#[derive(Clone, Copy)]
365struct MapIteratorHash {
366    wstack: *mut c_void,
367    kv: *mut Term,
368}
369
370#[repr(C)]
371union MapIteratorUnion {
372    flat: MapIteratorFlat,
373    hash: MapIteratorHash,
374}
375
376/// A cursor for iterating a map's entries.
377///
378/// Only `map` is public; the remaining fields are BEAM-internal. Initialized by
379/// [`map_iterator_create`](crate::map_iterator_create) and released by [`map_iterator_destroy`](crate::map_iterator_destroy), it must not
380/// be moved after initialization. Iteration order is unspecified.
381///
382/// [`ErlNifMapIterator`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifMapIterator) — NIF 2.6 — OTP 17
383#[repr(C)]
384pub struct MapIterator {
385    pub map: Term,
386    size: usize,
387    idx: usize,
388    u: MapIteratorUnion,
389    _spare: [*mut c_void; 2],
390}
391
392// ---------------------------------------------------------------------------
393// Term type tag
394// ---------------------------------------------------------------------------
395
396/// The canonical term types returned by `term_type`.
397///
398/// The C header reserves a `-1` sentinel and may add new types, so an
399/// unrecognized code must never be transmuted into this enum.
400///
401/// [`ErlNifTermType`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifTermType) — NIF 2.15 — OTP 22
402#[repr(i32)]
403#[derive(Clone, Copy, PartialEq, Eq, Debug)]
404pub enum TermType {
405    /// Matches an atom.
406    ///
407    /// [`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
408    Atom = 1,
409    /// Matches a bitstring (binaries included).
410    ///
411    /// [`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
412    Bitstring = 2,
413    /// Matches a float.
414    ///
415    /// [`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
416    Float = 3,
417    /// Matches a fun.
418    ///
419    /// [`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
420    Fun = 4,
421    /// Matches an integer.
422    ///
423    /// [`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
424    Integer = 5,
425    /// Matches a list (the empty list included).
426    ///
427    /// [`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
428    List = 6,
429    /// Matches a map.
430    ///
431    /// [`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
432    Map = 7,
433    /// Matches a pid.
434    ///
435    /// [`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
436    Pid = 8,
437    /// Matches a port.
438    ///
439    /// [`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
440    Port = 9,
441    /// Matches a reference.
442    ///
443    /// [`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
444    Reference = 10,
445    /// Matches a tuple.
446    ///
447    /// [`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
448    Tuple = 11,
449}
450
451impl TermType {
452    /// Map a raw `term_type` return code to a known variant, or `None` for any
453    /// code outside the canonical `1..=11` (an unknown/future term type).
454    pub fn from_raw(code: c_int) -> Option<Self> {
455        match code {
456            1 => Some(Self::Atom),
457            2 => Some(Self::Bitstring),
458            3 => Some(Self::Float),
459            4 => Some(Self::Fun),
460            5 => Some(Self::Integer),
461            6 => Some(Self::List),
462            7 => Some(Self::Map),
463            8 => Some(Self::Pid),
464            9 => Some(Self::Port),
465            10 => Some(Self::Reference),
466            11 => Some(Self::Tuple),
467            _ => None,
468        }
469    }
470}
471
472// ---------------------------------------------------------------------------
473// Character encoding
474// ---------------------------------------------------------------------------
475
476/// Encoding for reading and writing atom and string bytes.
477///
478/// Selects how the byte buffer in functions like [`make_atom`](crate::make_atom), [`get_string`](crate::get_string),
479/// and [`make_string`](crate::make_string) is interpreted. `Latin1` is one byte per character;
480/// `Utf8` (NIF 2.17) is variable-width.
481///
482/// [`ErlNifCharEncoding`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifCharEncoding) — NIF 1.0 — OTP R13B04
483#[repr(i32)]
484#[derive(Clone, Copy, PartialEq, Eq)]
485pub enum CharEncoding {
486    /// Latin-1 (ISO-8859-1).
487    ///
488    /// [`ERL_NIF_LATIN1`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_LATIN1) — NIF 1.0 — OTP R13B04
489    Latin1 = 1,
490    /// UTF-8.
491    ///
492    /// [`ERL_NIF_UTF8`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_UTF8) — NIF 2.17 — OTP 26
493    #[cfg(feature = "nif_2_17")]
494    Utf8 = 2,
495}
496
497// ---------------------------------------------------------------------------
498// Time
499// ---------------------------------------------------------------------------
500
501/// A time value in BEAM time units.
502///
503/// A signed 64-bit count whose unit is given by an accompanying [`TimeUnit`].
504/// Monotonic times are frequently negative; see [`monotonic_time`](crate::monotonic_time).
505///
506/// [`ErlNifTime`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifTime) — NIF 2.10 — OTP 18.3
507pub type Time = i64;
508
509/// Sentinel returned by the time functions on error.
510///
511/// Equal to `i64::MIN`. Returned when a time value cannot be represented in the
512/// requested [`TimeUnit`].
513///
514/// [`ERL_NIF_TIME_ERROR`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_TIME_ERROR) — NIF 2.10 — OTP 18.3
515pub const TIME_ERROR: Time = i64::MIN;
516
517/// The unit of a [`Time`] value.
518///
519/// Selects the unit passed to or returned by [`monotonic_time`](crate::monotonic_time), [`time_offset`](crate::time_offset),
520/// and [`convert_time_unit`](crate::convert_time_unit).
521///
522/// [`ErlNifTimeUnit`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifTimeUnit) — NIF 2.10 — OTP 18.3
523#[repr(i32)]
524#[derive(Clone, Copy, PartialEq, Eq, Debug)]
525pub enum TimeUnit {
526    /// Seconds.
527    ///
528    /// [`ERL_NIF_SEC`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SEC) — NIF 2.10 — OTP 18.3
529    Second = 0,
530    /// Milliseconds.
531    ///
532    /// [`ERL_NIF_MSEC`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_MSEC) — NIF 2.10 — OTP 18.3
533    Millisecond = 1,
534    /// Microseconds.
535    ///
536    /// [`ERL_NIF_USEC`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_USEC) — NIF 2.10 — OTP 18.3
537    Microsecond = 2,
538    /// Nanoseconds.
539    ///
540    /// [`ERL_NIF_NSEC`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_NSEC) — NIF 2.10 — OTP 18.3
541    Nanosecond = 3,
542}
543
544// ---------------------------------------------------------------------------
545// Unique integer flags
546// ---------------------------------------------------------------------------
547
548/// Flags shaping the result of [`make_unique_integer`](crate::make_unique_integer). Combine with `|`.
549///
550/// The same options as `erlang:unique_integer/1`. With no flags the integer is
551/// merely unique and may be negative; the flags constrain it to be positive
552/// and/or strictly monotonic.
553///
554/// [`ErlNifUniqueInteger`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifUniqueInteger) — NIF 2.11 — OTP 19
555#[repr(transparent)]
556#[derive(Clone, Copy, PartialEq, Eq)]
557pub struct UniqueInteger(pub c_int);
558
559impl UniqueInteger {
560    /// Return a positive integer only.
561    ///
562    /// [`ERL_NIF_UNIQUE_POSITIVE`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_UNIQUE_POSITIVE) — NIF 2.11 — OTP 19
563    pub const POSITIVE: Self = Self(1 << 0);
564    /// Return a strictly monotonic integer.
565    ///
566    /// [`ERL_NIF_UNIQUE_MONOTONIC`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_UNIQUE_MONOTONIC) — NIF 2.11 — OTP 19
567    pub const MONOTONIC: Self = Self(1 << 1);
568}
569
570impl BitOr for UniqueInteger {
571    type Output = Self;
572    fn bitor(self, rhs: Self) -> Self {
573        Self(self.0 | rhs.0)
574    }
575}
576
577// ---------------------------------------------------------------------------
578// Hash
579// ---------------------------------------------------------------------------
580
581/// The hash algorithm selector for [`hash`](crate::hash).
582///
583/// Chooses between a fast non-portable internal hash and the portable `phash2`
584/// that matches `erlang:phash2/1`.
585///
586/// [`ErlNifHash`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifHash) — NIF 2.12 — OTP 20
587#[repr(i32)]
588#[derive(Clone, Copy, PartialEq, Eq, Debug)]
589pub enum Hash {
590    /// Non-portable internal hash; fast, but may change between ERTS versions.
591    ///
592    /// [`ERL_NIF_INTERNAL_HASH`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_INTERNAL_HASH) — NIF 2.12 — OTP 20
593    InternalHash = 1,
594    /// Portable `phash2` hash, matching `erlang:phash2/1`.
595    ///
596    /// [`ERL_NIF_PHASH2`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_PHASH2) — NIF 2.12 — OTP 20
597    Phash2 = 2,
598}
599
600// ---------------------------------------------------------------------------
601// Select (I/O event multiplexing)
602// ---------------------------------------------------------------------------
603
604/// Mode flags for [`select`](crate::select). Combine with `|`.
605///
606/// For example `SelectFlags::READ | SelectFlags::CUSTOM_MSG`. Defined in
607/// `erl_drv_nif.h`; each flag carries its own introduction version, as the
608/// cancel, custom-message, and error modes were added after the base ones.
609///
610/// [`ErlNifSelectFlags`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifSelectFlags) — NIF 2.12 — OTP 20
611#[repr(transparent)]
612#[derive(Clone, Copy, PartialEq, Eq)]
613pub struct SelectFlags(pub c_int);
614
615impl SelectFlags {
616    /// Select for read readiness.
617    ///
618    /// [`ERL_NIF_SELECT_READ`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_READ) — NIF 2.12 — OTP 20
619    pub const READ: Self = Self(1 << 0);
620    /// Select for write readiness.
621    ///
622    /// [`ERL_NIF_SELECT_WRITE`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_WRITE) — NIF 2.12 — OTP 20
623    pub const WRITE: Self = Self(1 << 1);
624    /// Stop selecting on the event and trigger the resource stop callback.
625    ///
626    /// The safe way to retire an OS event before closing it: any active read/write
627    /// selections are cancelled first, then the resource's stop callback is called
628    /// — directly or scheduled — once no notification can still be in flight. The
629    /// event must not be closed until that callback has run. `pid` and `ref` are
630    /// ignored.
631    ///
632    /// [`ERL_NIF_SELECT_STOP`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_STOP) — NIF 2.12 — OTP 20
633    pub const STOP: Self = Self(1 << 2);
634    /// Cancel a pending read or write select without stopping.
635    ///
636    /// Combine with [`SelectFlags::READ`] and/or [`SelectFlags::WRITE`] to choose
637    /// which selections to cancel; `pid` and `ref` are ignored. The return
638    /// value's `*_CANCELLED` bits report whether each was actually removed or
639    /// whether a notification may already have been sent.
640    ///
641    /// [`ERL_NIF_SELECT_CANCEL`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_CANCEL) — NIF 2.15 — OTP 22
642    pub const CANCEL: Self = Self(1 << 3);
643    /// Deliver `msg` as a custom message instead of the default select message.
644    ///
645    /// [`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
646    pub const CUSTOM_MSG: Self = Self(1 << 4);
647    /// Select for error conditions on the event.
648    ///
649    /// [`ERL_NIF_SELECT_ERROR`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_ERROR) — NIF 2.16 — OTP 24
650    #[cfg(feature = "nif_2_16")]
651    pub const ERROR: Self = Self(1 << 5);
652}
653
654impl BitOr for SelectFlags {
655    type Output = Self;
656    fn bitor(self, rhs: Self) -> Self {
657        Self(self.0 | rhs.0)
658    }
659}
660
661/// `select`'s stop callback ran on the calling thread.
662///
663/// A success bit in the value returned by [`select`](crate::select) /
664/// [`select_x`](crate::select_x): the resource's stop callback was invoked
665/// directly, so the event is fully retired on return. Test it with bitwise AND.
666///
667/// [`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
668pub const SELECT_STOP_CALLED: c_int = 1 << 0;
669/// `select`'s stop callback was scheduled to run later.
670///
671/// A success bit: the stop callback could not run synchronously and was scheduled
672/// to run later, on this or another thread, so the event is not yet retired when
673/// [`select`](crate::select) returns.
674///
675/// [`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
676pub const SELECT_STOP_SCHEDULED: c_int = 1 << 1;
677/// `select` was given an invalid event object.
678///
679/// A failure bit — the [`select`](crate::select) return value is negative —
680/// meaning `event` was not a valid OS event object.
681///
682/// [`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
683pub const SELECT_INVALID_EVENT: c_int = 1 << 2;
684/// `select` failed to add the event to the poll set.
685///
686/// A failure bit (negative return): the underlying system call could not add the
687/// event object to the poll set.
688///
689/// [`ERL_NIF_SELECT_FAILED`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_FAILED) — NIF 2.12 — OTP 20
690pub const SELECT_FAILED: c_int = 1 << 3;
691/// A pending read `select` was cancelled.
692///
693/// A success bit: a read selection was removed by [`SelectFlags::CANCEL`] or
694/// [`SelectFlags::STOP`] and is guaranteed not to produce a further `ready_input`
695/// message.
696///
697/// [`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
698pub const SELECT_READ_CANCELLED: c_int = 1 << 4;
699/// A pending write `select` was cancelled.
700///
701/// A success bit: a write selection was removed by [`SelectFlags::CANCEL`] or
702/// [`SelectFlags::STOP`] and is guaranteed not to produce a further
703/// `ready_output` message.
704///
705/// [`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
706pub const SELECT_WRITE_CANCELLED: c_int = 1 << 5;
707/// A pending error `select` was cancelled.
708///
709/// A success bit: an error selection (see [`SelectFlags::ERROR`]) was removed by
710/// [`SelectFlags::CANCEL`] or [`SelectFlags::STOP`].
711///
712/// [`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
713#[cfg(feature = "nif_2_16")]
714pub const SELECT_ERROR_CANCELLED: c_int = 1 << 6;
715/// The requested `select` mode is not supported for the event object.
716///
717/// A failure bit (negative return): the requested mode — typically
718/// [`SelectFlags::ERROR`] — is not supported for this event object on this
719/// platform.
720///
721/// [`ERL_NIF_SELECT_NOTSUP`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_SELECT_NOTSUP) — NIF 2.16 — OTP 24
722#[cfg(feature = "nif_2_16")]
723pub const SELECT_NOTSUP: c_int = 1 << 7;
724
725// ---------------------------------------------------------------------------
726// binary_to_term options
727// ---------------------------------------------------------------------------
728
729/// Safe decoding for `binary_to_term`: reject encoded atoms that don't already
730/// exist.
731///
732/// [`ERL_NIF_BIN2TERM_SAFE`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_BIN2TERM_SAFE) — NIF 2.11 — OTP 19
733pub const BIN2TERM_SAFE: c_uint = 0x2000_0000;
734
735// ---------------------------------------------------------------------------
736// System info
737// ---------------------------------------------------------------------------
738
739/// A snapshot of BEAM runtime information.
740///
741/// Filled by [`system_info`](crate::system_info) (the C type is also `ErlDrvSysInfo`): ERTS and OTP
742/// version strings, the NIF and driver version numbers, scheduler counts, and the
743/// SMP, thread, and dirty-scheduler support flags.
744///
745/// [`ErlNifSysInfo`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifSysInfo) — NIF 1.0 — OTP R13B04
746#[repr(C)]
747pub struct SysInfo {
748    pub driver_major_version: c_int,
749    pub driver_minor_version: c_int,
750    pub erts_version: *mut c_char,
751    pub otp_release: *mut c_char,
752    pub thread_support: c_int,
753    pub smp_support: c_int,
754    pub async_threads: c_int,
755    pub scheduler_threads: c_int,
756    pub nif_major_version: c_int,
757    pub nif_minor_version: c_int,
758    pub dirty_scheduler_support: c_int,
759}
760
761// ---------------------------------------------------------------------------
762// NIF options (enif_set_option) — NIF 2.17 (OTP 26.0)
763// ---------------------------------------------------------------------------
764
765/// The key selecting which runtime option `set_option` sets.
766///
767/// Used by the [`set_option_delay_halt`](crate::set_option_delay_halt), [`set_option_on_halt`](crate::set_option_on_halt), and
768/// [`set_option_on_unload_thread`](crate::set_option_on_unload_thread) wrappers. The trailing underscore avoids
769/// shadowing the `std` prelude `Option`.
770///
771/// [`ErlNifOption`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifOption) — NIF 2.17 — OTP 26
772#[cfg(feature = "nif_2_17")]
773#[repr(i32)]
774#[derive(Clone, Copy, PartialEq, Eq, Debug)]
775pub enum Option_ {
776    /// Delay runtime-system halt until running NIF calls have returned.
777    ///
778    /// [`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
779    DelayHalt = 1,
780    /// Register an on-halt callback, run when the runtime system halts.
781    ///
782    /// [`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
783    OnHalt = 2,
784    /// Register an on-unload-thread callback. Added within the 2.17 line, so
785    /// passing it to an OTP-26 runtime is a caller error.
786    ///
787    /// [`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
788    OnUnloadThread = 3,
789}
790
791// ---------------------------------------------------------------------------
792// Thread type (return values from enif_thread_type)
793// ---------------------------------------------------------------------------
794
795/// Not a scheduler thread.
796///
797/// [`ERL_NIF_THR_UNDEFINED`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_THR_UNDEFINED) — NIF 2.11 — OTP 19
798pub const THR_UNDEFINED: c_int = 0;
799/// Normal BEAM scheduler thread.
800///
801/// [`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
802pub const THR_NORMAL_SCHEDULER: c_int = 1;
803/// Dirty CPU scheduler thread.
804///
805/// [`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
806pub const THR_DIRTY_CPU_SCHEDULER: c_int = 2;
807/// Dirty I/O scheduler thread.
808///
809/// [`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
810pub const THR_DIRTY_IO_SCHEDULER: c_int = 3;
811
812// ---------------------------------------------------------------------------
813// Dirty scheduler flags
814// ---------------------------------------------------------------------------
815// The two `ERL_NIF_DIRTY_JOB_*` constants. They apply to both the
816// `enif_schedule_nif` `flags` argument and the [`Func::flags`] field (the
817// latter is `c_uint`, so cast there); a regular NIF is just `0`.
818
819/// Run on a dirty CPU scheduler.
820///
821/// [`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
822pub const DIRTY_JOB_CPU_BOUND: c_int = 1;
823/// Run on a dirty I/O scheduler.
824///
825/// [`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
826pub const DIRTY_JOB_IO_BOUND: c_int = 2;
827
828// ---------------------------------------------------------------------------
829// I/O queue and iovec
830// ---------------------------------------------------------------------------
831
832/// An opaque I/O queue handle.
833///
834/// A FIFO of binary data used to stage output without copying. Created with
835/// [`ioq_create`](crate::ioq_create) and destroyed with [`ioq_destroy`](crate::ioq_destroy); always handled as
836/// `*mut IOQueue`.
837///
838/// [`ErlNifIOQueue`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifIOQueue) — NIF 2.12 — OTP 20.1
839#[repr(C)]
840pub struct IOQueue {
841    _opaque: [u8; 0],
842    _marker: PhantomData<(*mut u8, PhantomPinned)>,
843}
844
845/// Creation mode for an I/O queue.
846///
847/// The `opts` argument to [`ioq_create`](crate::ioq_create); the only defined value is
848/// [`IOQ_NORMAL`].
849///
850/// [`ErlNifIOQueueOpts`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifIOQueueOpts) — NIF 2.12 — OTP 20.1
851pub type IOQueueOpts = c_int;
852
853/// Normal I/O queue mode.
854///
855/// [`ERL_NIF_IOQ_NORMAL`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ERL_NIF_IOQ_NORMAL) — NIF 2.12 — OTP 20.1
856pub const IOQ_NORMAL: IOQueueOpts = 1;
857
858/// A scatter/gather I/O vector.
859///
860/// `iovcnt` [`SysIOVec`] segments at `iov` spanning `size` total bytes; the
861/// remaining fields are BEAM-internal. Produced from an iolist by
862/// [`inspect_iovec`](crate::inspect_iovec) and consumed by [`ioq_enqv`](crate::ioq_enqv).
863///
864/// [`ErlNifIOVec`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifIOVec) — NIF 2.12 — OTP 20.1
865#[repr(C)]
866pub struct IOVec {
867    pub iovcnt: c_int,
868    pub size: usize,
869    pub iov: *mut SysIOVec,
870    ref_bins: *mut *mut c_void,
871    flags: c_int,
872    small_iov: [SysIOVec; 16],
873    small_ref_bin: [*mut c_void; 16],
874}
875
876// ---------------------------------------------------------------------------
877// Opaque thread-primitive handles
878// ---------------------------------------------------------------------------
879
880/// An opaque mutex handle.
881///
882/// Created with [`mutex_create`](crate::mutex_create) and destroyed with [`mutex_destroy`](crate::mutex_destroy); always
883/// handled as `*mut Mutex`.
884///
885/// [`ErlNifMutex`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifMutex) — NIF 1.0 — OTP R13B04
886#[repr(C)]
887pub struct Mutex {
888    _opaque: [u8; 0],
889    _marker: PhantomData<(*mut u8, PhantomPinned)>,
890}
891
892/// An opaque condition variable handle.
893///
894/// Created with [`cond_create`](crate::cond_create) and destroyed with [`cond_destroy`](crate::cond_destroy); waited on
895/// with [`cond_wait`](crate::cond_wait). Always handled as `*mut Cond`.
896///
897/// [`ErlNifCond`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifCond) — NIF 1.0 — OTP R13B04
898#[repr(C)]
899pub struct Cond {
900    _opaque: [u8; 0],
901    _marker: PhantomData<(*mut u8, PhantomPinned)>,
902}
903
904/// An opaque read/write lock handle.
905///
906/// Created with [`rwlock_create`](crate::rwlock_create) and destroyed with [`rwlock_destroy`](crate::rwlock_destroy); always
907/// handled as `*mut RWLock`.
908///
909/// [`ErlNifRWLock`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifRWLock) — NIF 1.0 — OTP R13B04
910#[repr(C)]
911pub struct RWLock {
912    _opaque: [u8; 0],
913    _marker: PhantomData<(*mut u8, PhantomPinned)>,
914}
915
916/// A thread identifier.
917///
918/// Returned by [`thread_self`](crate::thread_self), written by [`thread_create`](crate::thread_create), and compared with
919/// [`equal_tids`](crate::equal_tids). An opaque pointer (in C, `struct ErlDrvTid_ *`).
920///
921/// [`ErlNifTid`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifTid) — NIF 1.0 — OTP R13B04
922pub type Tid = *mut c_void;
923
924/// A thread-specific data key.
925///
926/// Created with [`tsd_key_create`](crate::tsd_key_create); each thread stores and reads its own pointer
927/// for the key with [`tsd_set`](crate::tsd_set) and [`tsd_get`](crate::tsd_get).
928///
929/// [`ErlNifTSDKey`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifTSDKey) — NIF 1.0 — OTP R13B04
930pub type TSDKey = c_int;
931
932/// Options for creating a thread.
933///
934/// Allocated with [`thread_opts_create`](crate::thread_opts_create) and passed to [`thread_create`](crate::thread_create). The
935/// single field `suggested_stack_size` is a stack-size suggestion in kilowords;
936/// a value below zero requests the default size.
937///
938/// [`ErlNifThreadOpts`](https://www.erlang.org/doc/apps/erts/erl_nif.html#ErlNifThreadOpts) — NIF 1.0 — OTP R13B04
939#[repr(C)]
940pub struct ThreadOpts {
941    pub suggested_stack_size: c_int,
942}