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
65
66
67
68
69
70
71
72
73
74
//! # INIT GUARD
//!
//! The Init_Guard Crate provides a Synchronization Primitive, that can be used to guard against double initialization.
//!
//! For this, the init_guard macro is exported.
//! The init_guard macro creates a new module that contains everything needed for the init_guard.
//!
//! The Module contains two public Methods, init() and has_init().
//!
//! ## has_init()
//!
//! The has_init function has the following definition:
//!
//! ```
//! fn has_init() -> bool
//! ```
//!
//! The has_init function returns true, if the init_guard was already initialized.
//!
//! ## init()
//!
//! The init function has the following definition:
//!
//! ```
//! fn init() -> Result<(),()>
//! ```
//!
//! The init function returns Ok, if the init_guard was succesfully initialized and Err, if it was already initialized before
//!
//! ## Usage Example
//!
//! ```
//! init_guard!(HAS_LOGGER_INIT); // Create the init_guard
//!
//! fn init_logger() -> Result<(),String> {
//!     match HAS_LOGGER_INIT::init() {
//!         Ok(_) => {},
//!         Err(_) => {return Err("Logger is already initialized!".to_string())}
//!     }
//!     // Everything after this is now safe from double initialization
//!
//!     // Do your actual logger initialization here
//! }
//! ```

#[allow(unused_imports)]
#[macro_use]
extern crate lazy_static;
use lazy_static::lazy_static;

#[macro_export]
macro_rules! init_guard {
    ($global_vis:vis $global_name:ident) => {
        $global_vis mod $global_name {
            use std::sync::{Mutex, Once};
            lazy_static! {
                static ref MUTEX_ONCE: Mutex<Once> = Mutex::<Once>::new(Once::new());
            }

            pub fn has_init() -> bool {
                let once = MUTEX_ONCE.lock().unwrap();
                return once.is_completed();
            }

            pub fn init() -> Result<(),()> {
                let once = MUTEX_ONCE.lock().unwrap();
                if once.is_completed() {return Err(()); }

                once.call_once(|| {});
                Ok(())
            }
        }
    }
}