oncelock 0.1.0-alpha.0

A fast and simple implementation of OnceLock
Documentation
#[cfg(not(has_once_is_completed))]
use core::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once as RawOnce;

#[rustversion::before(1.51)]
pub const LEGACY_POISON_BEHAVIOR: bool = true;
#[rustversion::since(1.51)]
pub const LEGACY_POISON_BEHAVIOR: bool = false;

pub struct Once {
    raw: RawOnce,
    #[cfg(not(has_once_is_completed))]
    completed: AtomicBool,
}
impl Once {
    #[inline]
    pub const fn new() -> Once {
        #[allow(deprecated)] // needed to support rust 1.31 (Once::new const since 1.32)
        Once {
            raw: std::sync::ONCE_INIT,
            #[cfg(not(has_once_is_completed))]
            completed: AtomicBool::new(false),
        }
    }

    #[inline]
    #[cfg_attr(has_once_is_completed, clippy::msrv = "1.43")]
    pub fn is_completed(&self) -> bool {
        #[cfg(has_once_is_completed)]
        {
            self.raw.is_completed()
        }
        #[cfg(not(has_once_is_completed))]
        {
            // this is what the stdlib does
            // it synchronize with the release load in call_once
            self.completed.load(Ordering::Acquire)
        }
    }

    #[inline]
    pub fn call_once(&self, func: impl FnOnce()) {
        self.raw.call_once(func);
    }

    #[inline]
    pub fn call_once_force(&self, func: impl FnOnce()) {
        raw_call_once_force(&self.raw, || {
            func();
            #[cfg(not(has_once_is_completed))]
            {
                self.completed.store(true, Ordering::Release);
            }
        });
    }
}

#[inline]
#[rustversion::before(1.51)]
pub fn raw_call_once_force(once: &RawOnce, inner: impl FnOnce()) {
    assert!(LEGACY_POISON_BEHAVIOR);
    // cannot use call_once_force
    once.call_once(inner)
}

#[inline]
#[rustversion::since(1.51)]
pub fn raw_call_once_force(once: &RawOnce, inner: impl FnOnce()) {
    assert!(!LEGACY_POISON_BEHAVIOR);
    once.call_once_force(|_| inner());
}