ach_lazy/
lib.rs

1#![no_std]
2use ach_once::Once;
3use core::mem::MaybeUninit;
4use core::ops::Deref;
5use core::ptr;
6use core::sync::atomic::{AtomicBool, Ordering::SeqCst};
7
8pub struct Lazy<T, F = fn() -> T> {
9    val: Once<T>,
10    has_val: AtomicBool,
11    init: MaybeUninit<F>,
12}
13impl<T, F> Lazy<T, F> {
14    pub const fn new(f: F) -> Lazy<T, F> {
15        Lazy {
16            val: Once::new(),
17            has_val: AtomicBool::new(true),
18            init: MaybeUninit::new(f),
19        }
20    }
21}
22impl<T, F: FnOnce() -> T> Lazy<T, F> {
23    /// Notice: `Spin`
24    pub fn force(this: &Lazy<T, F>) -> &T {
25        if this
26            .has_val
27            .compare_exchange(true, false, SeqCst, SeqCst)
28            .is_ok()
29        {
30            let val = unsafe { ptr::read(this.init.as_ptr()) };
31            let value = val();
32            this.val.get_or_init(value)
33        } else {
34            this.val
35                .get()
36                .expect("Lazy instance has previously been poisoned")
37        }
38    }
39}
40impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
41    type Target = T;
42    fn deref(&self) -> &Self::Target {
43        Self::force(self)
44    }
45}
46impl<T, F> Drop for Lazy<T, F> {
47    fn drop(&mut self) {
48        if self
49            .has_val
50            .compare_exchange(true, false, SeqCst, SeqCst)
51            .is_ok()
52        {
53            unsafe { ptr::drop_in_place(self.init.as_mut_ptr()) };
54        }
55    }
56}