once/
lib.rs

1#![no_std]
2
3#[cfg(test)]
4extern crate std;
5
6// Re-export libcore using an alias so that the macros can work in no_std
7// crates while remaining compatible with normal crates.
8#[doc(hidden)]
9pub extern crate core as __core;
10
11/** This macro can be used to ensure that a function is called only once. It panics if the function
12is called a second time.
13
14# Example
15
16Using the macro:
17
18```rust
19#[macro_use]
20extern crate once;
21
22fn init() {
23    assert_has_not_been_called!();
24
25    // code that should only run once
26}
27
28fn main() {
29    init();
30    // init(); // "assertion failed: called == false"
31}
32```
33
34Custom error message:
35
36```rust
37#[macro_use]
38extern crate once;
39
40fn init() {
41    assert_has_not_been_called!("the init function must only be called {}", "once");
42}
43
44fn main() {
45    init();
46    // init(); // "the init function must only be called once"
47}
48```
49**/
50#[macro_export]
51macro_rules! assert_has_not_been_called {
52    () => {
53        assert_has_not_been_called!("assertion failed: has_run == false");
54    };
55    ($($arg:tt)+) => {{
56        fn assert_has_not_been_called() {
57            use $crate::__core::sync::atomic::{AtomicBool, Ordering};
58            static CALLED: AtomicBool = AtomicBool::new(false);
59            let called = CALLED.swap(true, Ordering::Relaxed);
60            assert!(called == false, $($arg)+);
61        }
62        assert_has_not_been_called();
63    }};
64}
65
66#[test]
67fn test_run_once() {
68    fn init() {
69        assert_has_not_been_called!();
70    }
71    init();
72}
73
74#[test]
75fn test_run_once_different_fns() {
76    fn init1() {
77        assert_has_not_been_called!();
78    }
79    fn init2() {
80        assert_has_not_been_called!();
81    }
82    init1();
83    init2();
84}
85
86#[test]
87#[should_panic]
88fn test_run_twice() {
89    fn init() {
90        assert_has_not_been_called!();
91    }
92    init();
93    init();
94}
95
96#[test]
97fn test_hygiene1() {
98    fn init() {
99        assert_has_not_been_called!();
100
101        #[allow(dead_code)]
102        fn assert_has_not_been_called() {}
103    }
104    init();
105}
106
107#[test]
108fn test_hygiene2() {
109    fn init() {
110        assert_has_not_been_called!();
111
112        #[allow(dead_code)]
113        static CALLED: i32 = 42;
114    }
115    init();
116}