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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/// Demo of an advanced generic macro to generate lazy static variables.
/// See also `demo/macro_lazy_static_var_errs.rs` for a more meaningful usage example.
//# Purpose: Demonstrate a handy alternative to the `lazy_static` crate.
//# Categories: macros, technique
// A generic macro for lazily initializing a static variable using `OnceLock`.
//
// This macro provides a way to initialize static variables lazily. The initialization
// function is guaranteed to be called only once, even in concurrent contexts.
//
// # Parameters
//
// - `$type`: The type of the static variable. Ensure that the type matches the return type of the initialization expression.
// - `$init_fn`: The initialization function or expression, which is executed only once.
// - `$name` (optional): A debug name for the variable, used in logging (if provided).
// - `deref` (optional): If specified, the macro dereferences the initialized value. Useful for types that implement `Deref`.
//
// # Behavior
//
// - **Single Initialization**: Once initialized, subsequent accesses return the same value without re-running the initialization logic.
// - **Dereferencing**: For types that support `Deref`, the macro can return a dereferenced version of the value (e.g., tuples).
// - **Debug Logging**: If a `$name` is provided, the macro logs the initialization using `eprintln!`.
//
// # Examples
//
// ## Simple Initialization
// ```rust
// let my_lazy_var = lazy_static_var!(Vec<i32>, vec![1, 2, 3]);
// println!("Lazy value: {:?}", my_lazy_var);
// ```
//
// ## Initialization with Debug Logging
// ```rust
// let my_lazy_var = lazy_static_var!(Vec<i32>, vec![4, 5, 6], "MyLazyVec");
// println!("Lazy value: {:?}", my_lazy_var);
// ```
//
// ## Initialization with Dereferencing
// ```rust
// let my_lazy_var = lazy_static_var!((usize, usize, usize), (10, 11, 12), deref);
// println!("Dereferenced lazy value: {:?}", my_lazy_var);
// ```
//
// ## Advanced Example with Error Handling
// ```rust
// let my_lazy_var = lazy_static_var!(
// Result<usize, &'static str>,
// Err("Initialization failed"),
// "ErrorProneLazyVar"
// );
// match my_lazy_var {
// Ok(value) => println!("Initialized value: {}", value),
// Err(e) => eprintln!("Failed to initialize: {}", e),
// }
// ```
#[macro_export]
macro_rules! lazy_static_var {
// With error handling (returning a Result)
($type:ty, $init_fn:expr, $name:expr, result) => {{
use std::sync::OnceLock;
static GENERIC_LAZY: OnceLock<$type> = OnceLock::new();
GENERIC_LAZY.get_or_init(|| {
eprintln!("Initializing lazy static variable: {}", $name);
match $init_fn {
Ok(value) => value,
Err(e) => panic!("Lazy static initialization failed: {}", e),
}
})
}};
// With type, debug name, and dereference
($type:ty, $init_fn:expr , $name:expr, deref) => {{
use std::sync::OnceLock;
static GENERIC_LAZY: OnceLock<$type> = OnceLock::new();
*GENERIC_LAZY.get_or_init(|| {
eprintln!("Initializing lazy static variable: {}", $name);
$init_fn
})
}};
// With type and dereference (no debug name)
($type:ty, $init_fn:expr, deref) => {{
use std::sync::OnceLock;
static GENERIC_LAZY: OnceLock<$type> = OnceLock::new();
*GENERIC_LAZY.get_or_init(|| {
eprintln!("Initializing lazy static variable");
$init_fn
})
}};
// With type and debug name
($type:ty, $init_fn:expr, $name:expr) => {{
use std::sync::OnceLock;
static GENERIC_LAZY: OnceLock<$type> = OnceLock::new();
GENERIC_LAZY.get_or_init(|| {
eprintln!("Initializing lazy static variable: {}", $name);
$init_fn
})
}};
// With type only (no debug name or dereference)
($type:ty, $init_fn:expr) => {{
use std::sync::OnceLock;
static GENERIC_LAZY: OnceLock<$type> = OnceLock::new();
GENERIC_LAZY.get_or_init(|| {
eprintln!("Initializing lazy static variable");
$init_fn
})
}};
}
fn main() {
let my_lazy_var = lazy_static_var!(
Result<usize, &'static str>,
Err("Initialization failed"),
"ErrorProneLazyVar",
result
);
// The macro will panic if initialization fails.
println!("Lazy value: {:?}", my_lazy_var);
}