1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#[macro_export]
macro_rules! nif_collection {
(
$moniker:ident,
init = $init_fn:ident,
nifs = [ $( ($name:literal, $arity:literal, $func:path) ),* $(,)? ]
) => {
::paste::paste! {
// ── init & resolver ───────────────────────────────────────────────
#[no_mangle]
pub extern "C" fn [<$moniker _nif_init>](ctx: *mut $crate::Context) {
unsafe { $init_fn(&mut *ctx) }
}
#[no_mangle]
pub extern "C" fn [<$moniker _get_nif>](name: *const u8)
-> *const core::ffi::c_void
{
let cstr = unsafe { core::ffi::CStr::from_ptr(name as *const _) };
match cstr.to_str().unwrap_or("") {
$(
$name => $func as *const () as *const core::ffi::c_void,
)*
_ => core::ptr::null(),
}
}
// ── registration blob ────────────────────────────────────────────
#[used]
#[cfg_attr(
any(target_os = "macos", target_os = "ios"),
link_section = "__DATA,.nif_collection"
)]
#[cfg_attr(
not(any(target_os = "macos", target_os = "ios")),
link_section = ".nif_collection"
)]
static _REGISTER: extern "C" fn() = {
extern "C" fn register() {
// skip during `cargo test` so the host linker
// doesn’t look for AtomVM’s C symbol
#[cfg(not(test))]
unsafe {
extern "C" {
fn REGISTER_NIF_COLLECTION(
name: *const u8,
init: *const core::ffi::c_void,
destroy: *const core::ffi::c_void,
resolver: *const core::ffi::c_void,
);
}
REGISTER_NIF_COLLECTION(
concat!(stringify!($moniker), "\0").as_ptr(),
[<$moniker _nif_init>] as *const _,
core::ptr::null(),
[<$moniker _get_nif>] as *const _,
);
}
}
register
};
}
};
}