global_static/
lib.rs

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]
20/// Generate a static with a ctor procedure.
21/// 
22///```rust
23///# use global_static::ctor_static;
24///fn spit_a_number() -> i32 { 42 }
25///
26///ctor_static! {
27///    pub MY_NUM: i32 = { 5 };
28///    MY_OTHER_NUM: i32 = spit_a_number;
29///    pub default DEFAULT_NUM: i32;
30///};
31///```
32///This code will expand to the following:
33///```rust
34///# use global_static::*;
35///# fn spit_a_number() -> i32 { 42 }
36///pub static MY_NUM: Global<i32> = Global::new(|| { 5 });
37///static MY_OTHER_NUM: Global<i32> = Global::new(spit_a_number);
38///pub static DEFAULT_NUM: Global<i32> = Global::default();
39///
40///#[global_static::ctor::ctor]
41///fn _global_init() {
42///    MY_NUM.init();
43///    MY_OTHER_NUM.init();
44///    DEFAULT_NUM.init();
45///}
46///```
47macro_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///Internal macro. Do not use.
59#[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///Internal macro. Do not use.
94#[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
127///Lazily evaluated static allocation.
128pub 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    ///Constructs a new global.
148    ///Rather than a value, this function takes a closure that produces a value.
149    ///```rust
150    ///# use global_static::Global;
151    ///
152    ///static MY_TABLE: Global<Vec<&str>> = Global::new(|| vec!["a", "b", "c"]);
153    pub const fn new(f: fn() -> T) -> Self {
154        Self { f, data: OnceLock::new() }
155    }
156
157    ///Initializes the contents of a global. Does nothing if already initialized.
158    pub fn init(&self) {
159        if let None = self.data.get() { 
160            let _ = unsafe { self.alloc() }; 
161        }
162    }
163
164    ///Retrieves a reference to the value inside the global without allocating.
165    ///This function will return `None` if the global has not been allocated.
166    pub fn get(&self) -> Option<&T> {
167        self.data.get().map(|ptr| {unsafe { &***ptr }})
168    }
169
170    ///Retrieves a reference to the value inside the global without allocating. Calling this function on
171    ///an unallocated global is undefined behavior.
172    pub unsafe fn get_unchecked(&self) -> &T {
173        //lol
174        &***self.data.get().unwrap_unchecked()
175    } 
176    
177    ///Caller must ensure cell has not been already allocated
178    unsafe fn alloc(&self) -> *const T {
179        //box will panic if it cannot allocate
180        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    ///Constructs a new global, using the [`Default`] implementation for `T` as the initializer.
190    //cant use trait cus not const
191    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}