singlyton/lib.rs
1#![cfg_attr(not(test), no_std)]
2#![doc = include_str!("../README.md")]
3
4#[cfg(test)]
5mod tests;
6
7mod cell;
8use cell::*;
9pub use cell::{map_ref, map_ref_mut, SinglytonRef, SinglytonRefMut};
10
11#[cfg(debug_assertions)]
12use core::cell::UnsafeCell;
13use core::mem::MaybeUninit;
14
15/// A **thread-unsafe** global singleton.
16///
17/// Using this across threads is undefined behaviour.
18///
19/// # Panics
20///
21/// In debug builds, usage of this abstraction is checked for safety at runtime.
22///
23/// * Using this struct across threads will panic.
24/// * Mixing mutabilty of borrows will panic (this is bypassed if you are using the pointer getters)
25#[repr(transparent)]
26pub struct Singleton<T>(SinglytonCell<T>);
27unsafe impl<T> Sync for Singleton<T> {}
28
29impl<T> Singleton<T> {
30 #[inline]
31 pub const fn new(val: T) -> Self {
32 Self(SinglytonCell::new(val))
33 }
34
35 #[inline]
36 /// Acquires an **immutable reference** to the singleton.
37 ///
38 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
39 pub fn get(&'static self) -> SinglytonRef<T> {
40 self.0.get()
41 }
42
43 #[inline]
44 /// Acquires a **mutable reference** to the singleton.
45 ///
46 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
47 pub fn get_mut(&'static self) -> SinglytonRefMut<T> {
48 self.0.get_mut()
49 }
50
51 #[inline]
52 /// Acquires an **immutable pointer** to the singleton.
53 ///
54 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
55 ///
56 /// This is unsafe because the returned pointer bypasses any future borrow checking.
57 pub unsafe fn as_ptr(&'static self) -> *const T {
58 &*self.0.get() as *const T
59 }
60
61 #[inline]
62 /// Acquires a **mutable pointer** to the singleton.
63 ///
64 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
65 ///
66 /// This is unsafe because the returned pointer bypasses any future borrow checking.
67 pub unsafe fn as_mut_ptr(&'static self) -> *mut T {
68 &mut *self.0.get_mut() as *mut T
69 }
70
71 #[inline]
72 /// Replaces the value in the singleton with anew.
73 ///
74 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
75 pub fn replace(&'static self, val: T) {
76 *self.0.get_mut() = val;
77 }
78}
79
80/// A **thread-unsafe** global singleton which is initially uninitialized memory.
81///
82/// Using this across threads is undefined behaviour.
83///
84/// # Panics
85///
86/// In debug builds, usage of this abstraction is checked for safety at runtime.
87///
88/// * Using this struct across threads will panic.
89/// * Mixing mutabilty of borrows will panic (this is bypassed if you are using the pointer getters)
90/// * Using this struct before initializing it will panic.
91/// * Initializing the value more than once will panic. Use `replace`
92pub struct SingletonUninit<T> {
93 inner: SinglytonCell<MaybeUninit<T>>,
94
95 #[cfg(debug_assertions)]
96 initialized: UnsafeCell<bool>
97}
98unsafe impl<T> Sync for SingletonUninit<T> {}
99
100impl<T> SingletonUninit<T> {
101 #[inline]
102 pub const fn uninit() -> Self {
103 Self {
104 inner: SinglytonCell::new(MaybeUninit::uninit()),
105
106 #[cfg(debug_assertions)]
107 initialized: UnsafeCell::new(false)
108 }
109 }
110
111 #[inline]
112 pub const fn new(val: T) -> Self {
113 Self {
114 inner: SinglytonCell::new(MaybeUninit::new(val)),
115
116 #[cfg(debug_assertions)]
117 initialized: UnsafeCell::new(true)
118 }
119 }
120
121 #[cfg(debug_assertions)]
122 #[inline(never)]
123 fn uninit_check(&'static self) {
124 if !unsafe { *self.initialized.get() } {
125 panic!("This SingletonUninit has not been initialized yet");
126 }
127 }
128
129 #[cfg(not(debug_assertions))]
130 #[inline(always)]
131 fn uninit_check(&'static self) {}
132
133 #[inline]
134 /// Assumes the memory is **initialized** and acquires an **immutable reference** to the singleton.
135 ///
136 /// In debug builds, this will panic if the memory is not initialized, the singleton is mutably accessed from a different thread, or a mutable reference is currently held.
137 pub fn get(&'static self) -> SinglytonRef<T> {
138 self.uninit_check();
139 map_ref(self.inner.get(), |maybe_uninit| unsafe {
140 maybe_uninit.assume_init_ref()
141 })
142 }
143
144 #[inline]
145 /// Acquires a **mutable reference** to the singleton.
146 ///
147 /// In debug builds, this will panic if the memory is not initialized, the singleton is mutably accessed from a different thread, or an existing mutable or immutable reference is currently held.
148 pub fn get_mut(&'static self) -> SinglytonRefMut<T> {
149 self.uninit_check();
150 map_ref_mut(self.inner.get_mut(), |maybe_uninit| unsafe {
151 maybe_uninit.assume_init_mut()
152 })
153 }
154
155 #[inline]
156 /// Acquires an **immutable pointer** to the singleton.
157 ///
158 /// In debug builds, this will panic if the memory is not initialized, the singleton is mutably accessed from a different thread, or a mutable reference is currently held.
159 ///
160 /// This is unsafe because the returned pointer bypasses any future borrow checking.
161 pub unsafe fn as_ptr(&'static self) -> *const T {
162 self.uninit_check();
163 self.inner.get_mut().as_ptr()
164 }
165
166 #[inline]
167 /// Acquires a **mutable pointer** to the singleton.
168 ///
169 /// In debug builds, this will panic if the memory is not initialized, the singleton is mutably accessed from a different thread, or an existing mutable or immutable reference is currently held.
170 ///
171 /// This is unsafe because the returned pointer bypasses any future borrow checking.
172 pub unsafe fn as_mut_ptr(&'static self) -> *mut T {
173 self.uninit_check();
174 self.inner.get_mut().as_mut_ptr()
175 }
176
177 #[inline]
178 /// Replaces the value in the singleton with anew.
179 ///
180 /// In debug builds, this will panic if the memory is not initialized, the singleton is mutably accessed from a different thread, or an existing mutable or immutable reference is currently held.
181 pub fn replace(&'static self, val: T) {
182 self.uninit_check();
183 unsafe {
184 let mut maybe_uninit = self.inner.get_mut();
185
186 core::ptr::drop_in_place(maybe_uninit.as_mut_ptr());
187 maybe_uninit.write(val);
188 }
189 }
190
191 #[inline]
192 #[cfg(debug_assertions)]
193 /// Initializes the memory in the singleton.
194 ///
195 /// In debug builds, this will panic if the memory is **already initialized**, the singleton is mutably accessed from a different thread, or an existing mutable or immutable reference is currently held.
196 pub fn init(&'static self, val: T) {
197 unsafe {
198 let ref mut initialized = *self.initialized.get();
199 if *initialized {
200 panic!("This SingletonUninit has already been initialized");
201 }
202
203 self.inner.get_mut().write(val);
204
205 *initialized = true;
206 }
207 }
208
209 #[inline]
210 #[cfg(not(debug_assertions))]
211 /// Initializes the memory in the singleton.
212 ///
213 /// In debug builds, this will panic if the memory is **already initialized**, the singleton is mutably accessed from a different thread, or an existing mutable or immutable reference is currently held.
214 pub fn init(&'static self, val: T) {
215 self.inner.get_mut().write(val);
216 }
217}
218
219/// A **thread-unsafe** global singleton containg an `Option<T>`.
220///
221/// All operations (except `as_option` and `as_option_mut`) automatically unwrap and assume the `Option<T>` is `Some(T)` and will panic otherwise.
222///
223/// Using this across threads is undefined behaviour.
224///
225/// # Panics
226///
227/// In debug builds, usage of this abstraction is checked for safety at runtime.
228///
229/// * Using this struct across threads will panic.
230/// * Mixing mutabilty of borrows will panic (this is bypassed if you are using the pointer getters)
231#[repr(transparent)]
232pub struct SingletonOption<T>(SinglytonCell<Option<T>>);
233unsafe impl<T> Sync for SingletonOption<T> {}
234
235impl<T> SingletonOption<T> {
236 #[inline]
237 pub const fn new() -> Self {
238 Self(SinglytonCell::new(None))
239 }
240
241 #[inline]
242 pub const fn new_some(val: T) -> Self {
243 Self(SinglytonCell::new(Some(val)))
244 }
245
246 #[inline]
247 /// Acquires an **immutable reference** to the inner `Option<T>`.
248 ///
249 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
250 pub fn as_option(&'static self) -> SinglytonRef<Option<T>> {
251 self.0.get()
252 }
253
254 #[inline]
255 /// Acquires a **mutable reference** to the inner `Option<T>`.
256 ///
257 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
258 pub fn as_option_mut(&'static self) -> SinglytonRefMut<Option<T>> {
259 self.0.get_mut()
260 }
261
262 #[inline]
263 /// Acquires an **immutable pointer** to the inner Option<T>.
264 ///
265 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
266 ///
267 /// This is unsafe because the returned pointer bypasses any future borrow checking.
268 pub unsafe fn as_option_ptr(&'static self) -> *const Option<T> {
269 &*self.0.get_unchecked() as *const Option<T>
270 }
271
272 #[inline]
273 /// Acquires a **mutable pointer** to the inner Option<T>.
274 ///
275 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
276 ///
277 /// This is unsafe because the returned pointer bypasses any future borrow checking.
278 pub unsafe fn as_option_mut_ptr(&'static self) -> *mut Option<T> {
279 &mut *self.0.get_mut_unchecked() as *mut Option<T>
280 }
281
282 #[inline]
283 /// Acquires an **immutable reference** to the singleton.
284 ///
285 /// Panics if the singleton is `None`.
286 ///
287 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
288 pub fn get(&'static self) -> SinglytonRef<T> {
289 map_ref(self.0.get(), |opt| opt.as_ref().unwrap())
290 }
291
292 #[inline]
293 /// Acquires a **mutable reference** to the singleton.
294 ///
295 /// Panics if the singleton is `None`.
296 ///
297 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
298 pub fn get_mut(&'static self) -> SinglytonRefMut<T> {
299 map_ref_mut(self.0.get_mut(), |opt| opt.as_mut().unwrap())
300 }
301
302 #[inline]
303 /// Replaces the value in the singleton with anew.
304 ///
305 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
306 pub fn replace(&'static self, val: T) {
307 self.0.get_mut().replace(val);
308 }
309
310 #[inline]
311 /// Takes the value out of the singleton.
312 ///
313 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
314 pub fn take(&'static self) -> Option<T> {
315 self.0.get_mut().take()
316 }
317
318 #[inline]
319 /// Tests if the singleton is `Some(T)`.
320 ///
321 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
322 pub fn is_some(&'static self) -> bool {
323 self.0.get().is_some()
324 }
325
326 #[inline]
327 /// Tests if the singleton is `None`.
328 ///
329 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
330 pub fn is_none(&'static self) -> bool {
331 self.0.get().is_none()
332 }
333}
334
335/// A **thread-unsafe** global singleton containg an `Option<T>`.
336///
337/// All operations (except `as_option` and `as_option_mut`) automatically unwrap **without checking if the Option<T> is Some(T) in release builds** and will lead to undefined behaviour otherwise.
338///
339/// Using this across threads is undefined behaviour.
340///
341/// # Panics
342///
343/// In debug builds, usage of this abstraction is checked for safety at runtime.
344///
345/// * Using this struct across threads will panic.
346/// * Mixing mutabilty of borrows will panic (this is bypassed if you are using the pointer getters)
347#[repr(transparent)]
348pub struct SingletonOptionUnchecked<T>(SinglytonCell<Option<T>>);
349unsafe impl<T> Sync for SingletonOptionUnchecked<T> {}
350
351impl<T> SingletonOptionUnchecked<T> {
352 #[inline]
353 pub const fn new() -> Self {
354 Self(SinglytonCell::new(None))
355 }
356
357 #[inline]
358 pub const fn new_some(val: T) -> Self {
359 Self(SinglytonCell::new(Some(val)))
360 }
361
362 #[inline]
363 /// Acquires an **immutable reference** to the inner `Option<T>`.
364 ///
365 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
366 pub fn as_option(&'static self) -> SinglytonRef<Option<T>> {
367 self.0.get()
368 }
369
370 #[inline]
371 /// Acquires a **mutable reference** to the inner `Option<T>`.
372 ///
373 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
374 pub fn as_option_mut(&'static self) -> SinglytonRefMut<Option<T>> {
375 self.0.get_mut()
376 }
377
378 #[inline]
379 /// Acquires an **immutable pointer** to the inner Option<T>.
380 ///
381 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
382 ///
383 /// This is unsafe because the returned pointer bypasses any future borrow checking.
384 pub unsafe fn as_option_ptr(&'static self) -> *const Option<T> {
385 &*self.0.get_unchecked() as *const Option<T>
386 }
387
388 #[inline]
389 /// Acquires a **mutable pointer** to the inner Option<T>.
390 ///
391 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
392 ///
393 /// This is unsafe because the returned pointer bypasses any future borrow checking.
394 pub unsafe fn as_option_mut_ptr(&'static self) -> *mut Option<T> {
395 &mut *self.0.get_mut_unchecked() as *mut Option<T>
396 }
397
398 #[inline]
399 /// Acquires an **immutable reference** to the singleton.
400 ///
401 /// Panics if the singleton is `None`.
402 ///
403 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
404 pub unsafe fn get(&'static self) -> SinglytonRef<T> {
405 map_ref(self.0.get(), |opt| {
406 #[cfg(debug_assertions)] {
407 opt.as_ref().unwrap()
408 }
409 #[cfg(not(debug_assertions))] {
410 opt.as_ref().unwrap_unchecked()
411 }
412 })
413 }
414
415 #[inline]
416 /// Acquires a **mutable reference** to the singleton.
417 ///
418 /// Panics if the singleton is `None`.
419 ///
420 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
421 pub unsafe fn get_mut(&'static self) -> SinglytonRefMut<T> {
422 map_ref_mut(self.0.get_mut(), |opt| {
423 #[cfg(debug_assertions)] {
424 opt.as_mut().unwrap()
425 }
426 #[cfg(not(debug_assertions))] {
427 opt.as_mut().unwrap_unchecked()
428 }
429 })
430 }
431
432 #[inline]
433 /// Replaces the value in the singleton with anew.
434 ///
435 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
436 pub fn replace(&'static self, val: T) {
437 self.0.get_mut().replace(val);
438 }
439
440 #[inline]
441 /// Takes the value out of the singleton.
442 ///
443 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or an existing mutable or immutable reference is currently held.
444 pub fn take(&'static self) -> Option<T> {
445 self.0.get_mut().take()
446 }
447
448 #[inline]
449 /// Tests if the singleton is `Some(T)`.
450 ///
451 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
452 pub fn is_some(&'static self) -> bool {
453 self.0.get().is_some()
454 }
455
456 #[inline]
457 /// Tests if the singleton is `None`.
458 ///
459 /// In debug builds, this will panic if the singleton is mutably accessed from a different thread or if a mutable reference is currently held.
460 pub fn is_none(&'static self) -> bool {
461 self.0.get().is_none()
462 }
463}