Skip to content

Commit cacb96f

Browse files
committed
Implement NIF discovery using linkme to statically collect NIF implementations
1 parent 868c01b commit cacb96f

File tree

6 files changed

+50
-45
lines changed

6 files changed

+50
-45
lines changed

rustler/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ nif_version_2_17 = ["nif_version_2_16", "rustler_sys/nif_version_2_17"]
2222
serde = ["dep:serde"]
2323

2424
[dependencies]
25-
inventory = "0.3"
25+
linkme = "0.3"
2626
rustler_codegen = { path = "../rustler_codegen", version = "0.33.0", optional = true}
2727
rustler_sys = { path = "../rustler_sys", version = "~2.4.1" }
2828
num-bigint = { version = "0.4", optional = true }

rustler/src/codegen_runtime.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ use std::fmt;
55

66
use crate::{Encoder, Env, OwnedBinary, Term};
77

8-
// Re-export of inventory
9-
pub use inventory;
8+
// Re-export of linkme
9+
pub use crate::nif::RUSTLER_NIFS as NIFS;
10+
pub use linkme;
1011

1112
// Names used by the `rustler::init!` macro or other generated code.
1213
pub use crate::wrapper::exception::raise_exception;

rustler/src/nif.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::codegen_runtime::{c_char, c_int, c_uint, DEF_NIF_FUNC, NIF_ENV, NIF_TERM};
22

3+
#[repr(C)]
34
pub struct Nif {
45
pub name: *const c_char,
56
pub arity: c_uint,
@@ -22,4 +23,6 @@ impl Nif {
2223

2324
unsafe impl Sync for Nif {}
2425

25-
inventory::collect!(Nif);
26+
#[no_mangle]
27+
#[linkme::distributed_slice]
28+
pub static RUSTLER_NIFS: [Nif];

rustler_codegen/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ syn = { version = "2.0", features = ["full", "extra-traits"] }
1717
quote = "1.0"
1818
heck = "0.5"
1919
proc-macro2 = "1.0"
20-
inventory = "0.3"
2120

2221
[dev-dependencies]
2322
trybuild = "1.0"

rustler_codegen/src/init.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ impl From<InitMacroInput> for proc_macro2::TokenStream {
8686
let inner = quote! {
8787
static mut NIF_ENTRY: Option<rustler::codegen_runtime::DEF_NIF_ENTRY> = None;
8888
let nif_funcs: Box<[_]> =
89-
rustler::codegen_runtime::inventory::iter::<rustler::Nif>()
90-
.map(rustler::Nif::get_def)
89+
rustler::codegen_runtime::NIFS
90+
.iter()
91+
.map(|n| n.get_def())
9192
.collect();
9293

9394
let entry = rustler::codegen_runtime::DEF_NIF_ENTRY {

rustler_codegen/src/nif.rs

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -55,47 +55,48 @@ pub fn transcoder_decorator(nif_attributes: NifAttributes, fun: syn::ItemFn) ->
5555
}
5656

5757
quote! {
58-
rustler::codegen_runtime::inventory::submit!(
59-
rustler::Nif {
60-
name: concat!(#erl_func_name, "\0").as_ptr()
61-
as *const rustler::codegen_runtime::c_char,
62-
arity: #arity,
63-
flags: #flags as rustler::codegen_runtime::c_uint,
64-
raw_func: {
65-
unsafe extern "C" fn nif_func(
66-
nif_env: rustler::codegen_runtime::NIF_ENV,
67-
argc: rustler::codegen_runtime::c_int,
68-
argv: *const rustler::codegen_runtime::NIF_TERM
69-
) -> rustler::codegen_runtime::NIF_TERM {
70-
let lifetime = ();
71-
let env = rustler::Env::new(&lifetime, nif_env);
72-
73-
let terms = std::slice::from_raw_parts(argv, argc as usize)
74-
.iter()
75-
.map(|term| rustler::Term::new(env, *term))
76-
.collect::<Vec<rustler::Term>>();
77-
78-
fn wrapper<'a>(
79-
env: rustler::Env<'a>,
80-
args: &[rustler::Term<'a>]
81-
) -> rustler::codegen_runtime::NifReturned {
82-
let result: std::thread::Result<_> =
83-
std::panic::catch_unwind(move || {
84-
#decoded_terms
85-
#function
86-
Ok(#name(#argument_names))
87-
});
88-
89-
rustler::codegen_runtime::handle_nif_result(
90-
result, env
91-
)
92-
}
93-
wrapper(env, &terms).apply(env)
58+
#[allow(non_upper_case_globals)]
59+
#[rustler::codegen_runtime::linkme::distributed_slice(rustler::codegen_runtime::NIFS)]
60+
#[linkme(crate = rustler::codegen_runtime::linkme)]
61+
static #name: rustler::Nif = rustler::Nif {
62+
name: concat!(#erl_func_name, "\0").as_ptr()
63+
as *const rustler::codegen_runtime::c_char,
64+
arity: #arity,
65+
flags: #flags as rustler::codegen_runtime::c_uint,
66+
raw_func: {
67+
unsafe extern "C" fn nif_func(
68+
nif_env: rustler::codegen_runtime::NIF_ENV,
69+
argc: rustler::codegen_runtime::c_int,
70+
argv: *const rustler::codegen_runtime::NIF_TERM
71+
) -> rustler::codegen_runtime::NIF_TERM {
72+
let lifetime = ();
73+
let env = rustler::Env::new(&lifetime, nif_env);
74+
75+
let terms = std::slice::from_raw_parts(argv, argc as usize)
76+
.iter()
77+
.map(|term| rustler::Term::new(env, *term))
78+
.collect::<Vec<rustler::Term>>();
79+
80+
fn wrapper<'a>(
81+
env: rustler::Env<'a>,
82+
args: &[rustler::Term<'a>]
83+
) -> rustler::codegen_runtime::NifReturned {
84+
let result: std::thread::Result<_> =
85+
std::panic::catch_unwind(move || {
86+
#decoded_terms
87+
#function
88+
Ok(#name(#argument_names))
89+
});
90+
91+
rustler::codegen_runtime::handle_nif_result(
92+
result, env
93+
)
9494
}
95-
nif_func
95+
wrapper(env, &terms).apply(env)
9696
}
97+
nif_func
9798
}
98-
);
99+
};
99100
}
100101
}
101102

0 commit comments

Comments
 (0)