init_hook/
lib.rs

1#![no_std]
2extern crate self as init_hook;
3
4#[doc(hidden)]
5#[path = "private.rs"]
6pub mod __private;
7
8pub use init_hook_macros::call_on_init;
9
10#[doc(hidden)]
11pub use linkme;
12
13/// Call all functions registered by [call_on_init]
14///
15/// # Example
16///
17/// ```
18/// use std::sync::atomic::{AtomicUsize, Ordering};
19/// static COUNTER: AtomicUsize = AtomicUsize::new(0);
20///
21/// #[init_hook::call_on_init]
22/// unsafe fn init_once_unchecked() {
23///     COUNTER.fetch_add(1, Ordering::Release);
24/// }
25///
26/// #[init_hook::call_on_init]
27/// fn init_once() {
28///     COUNTER.fetch_add(1, Ordering::Release);
29/// }
30///
31/// fn main() {
32///    init_hook::init!();
33///    assert_eq!(COUNTER.load(Ordering::Acquire), 2);
34/// }
35/// ```
36///
37/// # Panic
38///
39/// If init isn't used in main exactly once, `init_hook` will detect this and panic pre-main
40///
41/// ```should_panic
42/// use std::sync::atomic::{AtomicBool, Ordering};
43/// static INIT_CALLED: AtomicBool = AtomicBool::new(false);
44///
45/// #[init_hook::call_on_init]
46/// fn init() {
47///     INIT_CALLED.store(true, Ordering::Release);
48/// }
49///
50/// // This will panic with "`init_hook::init` must be used within the root main function"
51/// fn main() {
52///    let _init_called = INIT_CALLED.load(Ordering::Acquire);
53/// }
54/// ```
55#[macro_export]
56macro_rules! init {
57    () => {
58        #[cfg(not(test))]
59        {
60            if module_path!().contains("::") {
61                panic!("#[init_hook::init] can only be used in the crate root");
62            }
63        }
64
65        #[init_hook::linkme::distributed_slice(init_hook::__private::INIT)]
66        #[linkme(crate = init_hook::linkme)]
67        static INIT_CONFIGURED: bool = true;
68
69        unsafe {
70            init_hook::__private::call_init_fns();
71        }
72    };
73}