use core::fmt;
#[cfg(feature = "std")]
use std::sync::OnceLock;
#[cfg(not(feature = "std"))]
use once_cell::race::OnceBox;
pub struct OnceLockCompat<T> {
#[cfg(feature = "std")]
inner: OnceLock<T>,
#[cfg(not(feature = "std"))]
inner: OnceBox<T>,
}
impl<T> OnceLockCompat<T> {
pub const fn new() -> Self {
#[cfg(feature = "std")]
{
Self { inner: OnceLock::new() }
}
#[cfg(not(feature = "std"))]
{
Self { inner: OnceBox::new() }
}
}
pub fn get(&self) -> Option<&T> {
#[cfg(feature = "std")]
{
self.inner.get()
}
#[cfg(not(feature = "std"))]
{
self.inner.get().map(|b| -> &T { b })
}
}
pub fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
{
#[cfg(feature = "std")]
{
self.inner.get_or_init(f)
}
#[cfg(not(feature = "std"))]
{
let b: &T = self.inner.get_or_init(|| alloc::boxed::Box::new(f()));
b
}
}
pub fn reset(&mut self) {
#[cfg(feature = "std")]
{
self.inner = OnceLock::new();
}
#[cfg(not(feature = "std"))]
{
self.inner = OnceBox::new();
}
}
}
impl<T> Default for OnceLockCompat<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: fmt::Debug> fmt::Debug for OnceLockCompat<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_is_empty() {
let lock: OnceLockCompat<u32> = OnceLockCompat::new();
assert!(lock.get().is_none());
}
#[test]
fn get_or_init_initializes() {
let lock: OnceLockCompat<u32> = OnceLockCompat::new();
let val = lock.get_or_init(|| 42);
assert_eq!(*val, 42);
assert_eq!(*lock.get().unwrap(), 42);
}
#[test]
fn reset_clears_value() {
let mut lock: OnceLockCompat<u32> = OnceLockCompat::new();
lock.get_or_init(|| 42);
assert!(lock.get().is_some());
lock.reset();
assert!(lock.get().is_none());
}
#[test]
fn get_or_init_after_reset() {
let mut lock: OnceLockCompat<u32> = OnceLockCompat::new();
lock.get_or_init(|| 1);
lock.reset();
let val = lock.get_or_init(|| 2);
assert_eq!(*val, 2);
}
}