1#![doc = include_str!("../README.md")]
2
3#![cfg_attr(docsrs, feature(doc_cfg))]
4use std::{ops::Deref, sync::OnceLock, fmt::{Debug, Display}};
5
6
7#[cfg_attr(docsrs, doc(cfg(feature = "ctor")))]
8#[cfg(feature = "ctor")]
9pub use ctor;
10
11
12#[cfg_attr(docsrs, doc(cfg(feature = "singleton")))]
13#[cfg(feature = "singleton")]
14pub use singleton::{singleton, singleton_fn};
15
16
17#[cfg_attr(docsrs, doc(cfg(feature = "ctor")))]
18#[cfg(feature = "ctor")]
19#[macro_export]
20macro_rules! ctor_static {
48 () => {};
49 ($($body:tt)*) => {
50 $crate::ctor_gen_defs!($($body)*);
51 #[$crate::ctor::ctor]
52 fn _global_init() {
53 $crate::ctor_gen_inits!($($body)*);
54 }
55 };
56}
57
58#[macro_export]
60#[doc(hidden)]
61macro_rules! ctor_gen_defs {
62 () => {};
63
64 ($name:ident: $type: ty = $init:block; $($tail:tt)*) => {
65 static $name: $crate::Global<$type> = $crate::Global::new(|| $init);
66 $crate::ctor_gen_defs!($($tail)*);
67 };
68 (pub $name:ident: $type: ty = $init:block; $($tail:tt)*) => {
69 pub static $name: $crate::Global<$type> = $crate::Global::new(|| $init);
70 $crate::ctor_gen_defs!($($tail)*);
71 };
72
73 ($name:ident: $type: ty = $init:expr; $($tail:tt)*) => {
74 static $name: $crate::Global<$type> = $crate::Global::new($init);
75 $crate::ctor_gen_defs!($($tail)*);
76 };
77 (pub $name:ident: $type: ty = $init:expr; $($tail:tt)*) => {
78 pub static $name: $crate::Global<$type> = $crate::Global::new($init);
79 $crate::ctor_gen_defs!($($tail)*);
80 };
81
82 (default $name:ident: $type: ty; $($tail:tt)*) => {
83 static $name: $crate::Global<$type> = $crate::Global::default();
84 $crate::ctor_gen_defs!($($tail)*);
85 };
86 (pub default $name:ident: $type: ty; $($tail:tt)*) => {
87 pub static $name: $crate::Global<$type> = $crate::Global::default();
88 $crate::ctor_gen_defs!($($tail)*);
89 };
90
91}
92
93#[macro_export]
95#[doc(hidden)]
96macro_rules! ctor_gen_inits {
97 () => {};
98 ($name:ident: $type: ty = $init:block; $($tail:tt)*) => {
99 $name.init();
100 $crate::ctor_gen_inits!($($tail)*);
101 };
102 (pub $name:ident: $type: ty = $init:block; $($tail:tt)*) => {
103 $name.init();
104 $crate::ctor_gen_inits!($($tail)*);
105 };
106
107 ($name:ident: $type: ty = $init:expr; $($tail:tt)*) => {
108 $name.init();
109 $crate::ctor_gen_inits!($($tail)*);
110 };
111 (pub $name:ident: $type: ty = $init:expr; $($tail:tt)*) => {
112 $name.init();
113 $crate::ctor_gen_inits!($($tail)*);
114 };
115
116 (default $name:ident: $type: ty; $($tail:tt)*) => {
117 $name.init();
118 $crate::ctor_gen_inits!($($tail)*);
119 };
120 (pub default $name:ident: $type: ty; $($tail:tt)*) => {
121 $name.init();
122 $crate::ctor_gen_inits!($($tail)*);
123 };
124}
125
126
127pub struct Global<T> {
129 f: fn() -> T,
130 data: OnceLock<SendPtr<T>>
131}
132
133struct SendPtr<T>(pub *const T);
134unsafe impl<T> Send for SendPtr<T> {}
135unsafe impl<T> Sync for SendPtr<T> {}
136
137impl<T> Deref for SendPtr<T> {
138 type Target = *const T;
139
140 fn deref(&self) -> &Self::Target {
141 &self.0
142 }
143}
144
145
146impl<T> Global<T> {
147 pub const fn new(f: fn() -> T) -> Self {
154 Self { f, data: OnceLock::new() }
155 }
156
157 pub fn init(&self) {
159 if let None = self.data.get() {
160 let _ = unsafe { self.alloc() };
161 }
162 }
163
164 pub fn get(&self) -> Option<&T> {
167 self.data.get().map(|ptr| {unsafe { &***ptr }})
168 }
169
170 pub unsafe fn get_unchecked(&self) -> &T {
173 &***self.data.get().unwrap_unchecked()
175 }
176
177 unsafe fn alloc(&self) -> *const T {
179 let ptr = Box::leak(
181 Box::new((self.f)())
182 ) as *const T;
183 self.data.set(SendPtr(ptr)).unwrap_unchecked();
184 **self.data.get().unwrap_unchecked()
185 }
186}
187
188impl<T: Default> Global<T> {
189 pub const fn default() -> Self {
192 Self::new(T::default)
193 }
194}
195
196impl<T> Deref for Global<T> {
197 type Target = T;
198
199 fn deref(&self) -> &Self::Target {
200 match self.data.get() {
201 Some(v) => unsafe { &***v },
202 None => unsafe { &*self.alloc() },
203 }
204 }
205}
206
207impl<T: Debug> Debug for Global<T> {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 write!(f, "{:?}", self.deref())
210 }
211}
212impl<T: Display> Display for Global<T> {
213 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214 write!(f, "{}", self.deref())
215 }
216}
217
218
219#[cfg(test)]
220mod tests {
221 use std::ops::Add;
222
223 use super::*;
224 static TEST: super::Global<u8> = super::Global::new(|| 5);
225
226 #[test]
227 fn it_works() {
228 assert_eq!(TEST.add(1), 6);
229 assert_eq!(*TEST, 5);
230 }
231
232 #[test]
233 #[cfg(feature = "ctor")]
234 fn ctor_test() {
235 ctor_static! {
236 THING: u32 = { 5 };
237 pub THING2: u32 = { 5 };
238 };
239
240 assert_eq!(THING.add(1), 6);
241 assert_eq!(*THING, 5);
242 }
243
244 #[test]
245 #[cfg(feature = "singleton")]
246 fn singleton_attr() {
247 use crate as global_static;
248 #[singleton(|| Thing::new("hai!"))]
249 struct Thing {
250 data: String,
251 }
252 impl Thing {
253 pub fn new(str: &str) -> Self {
254 Self { data: str.to_owned() }
255 }
256 }
257
258 assert!(THING.get().is_some());
259
260 #[singleton_fn]
261 #[singleton_fn(MY_THING)]
262 fn make_thing() -> Thing {
263 Thing::new("haaai")
264 }
265
266 assert!(MAKE_THING.get().is_some());
267 assert!(MY_THING.get().is_some());
268 }
269}