ach-lazy 0.2.5

Atomic Channel
Documentation
#![no_std]
use ach_once::Once;
use core::mem::MaybeUninit;
use core::ops::Deref;
use core::ptr;
use core::sync::atomic::{AtomicBool, Ordering::SeqCst};

pub struct Lazy<T, F = fn() -> T> {
    val: Once<T>,
    has_val: AtomicBool,
    init: MaybeUninit<F>,
}
impl<T, F> Lazy<T, F> {
    pub const fn new(f: F) -> Lazy<T, F> {
        Lazy {
            val: Once::new(),
            has_val: AtomicBool::new(true),
            init: MaybeUninit::new(f),
        }
    }
}
impl<T, F: FnOnce() -> T> Lazy<T, F> {
    /// Notice: `Spin`
    pub fn force(this: &Lazy<T, F>) -> &T {
        if this
            .has_val
            .compare_exchange(true, false, SeqCst, SeqCst)
            .is_ok()
        {
            let val = unsafe { ptr::read(this.init.as_ptr()) };
            let value = val();
            this.val.get_or_init(value)
        } else {
            this.val
                .get()
                .expect("Lazy instance has previously been poisoned")
        }
    }
}
impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        Self::force(self)
    }
}
impl<T, F> Drop for Lazy<T, F> {
    fn drop(&mut self) {
        if self
            .has_val
            .compare_exchange(true, false, SeqCst, SeqCst)
            .is_ok()
        {
            unsafe { ptr::drop_in_place(self.init.as_mut_ptr()) };
        }
    }
}