#![no_std]
extern crate alloc;
use alloc::sync::Arc;
use core::cell::UnsafeCell;
use core::ops::Deref;
use core::sync::atomic::{AtomicBool, Ordering};
use alloc::boxed::Box;
pub struct Lazy<T> {
init: AtomicBool,
value: UnsafeCell<Option<T>>,
}
unsafe impl<T: Send + Sync> Sync for Lazy<T> {}
impl<T> Lazy<T> {
pub const INIT: Self = Lazy {
init: AtomicBool::new(false),
value: UnsafeCell::new(None),
};
#[inline(always)]
pub fn get<F>(&self, init: F) -> &T
where
F: FnOnce() -> T,
{
if !self.init.load(Ordering::Acquire) {
let value = init();
unsafe {
*self.value.get() = Some(value);
}
self.init.store(true, Ordering::Release);
}
unsafe { (*self.value.get()).as_ref().unwrap() }
}
#[inline(always)]
pub fn get_mut<F>(&self, init: F) -> &mut T
where
F: FnOnce() -> T,
{
if !self.init.load(Ordering::Acquire) {
let value = init();
unsafe {
*self.value.get() = Some(value);
}
self.init.store(true, Ordering::Release);
}
unsafe { (*self.value.get()).as_mut().unwrap() }
}
}
pub trait LazyStatic {
fn initialize(&self);
}
impl<T> LazyStatic for Lazy<T> {
fn initialize(&self) {
self.init.load(Ordering::Acquire);
}
}
pub fn initialize<T: LazyStatic>(lazy: &T) {
lazy.initialize();
}
#[macro_export]
macro_rules! lazy {
($(#[$attr:meta])* $vis:vis static ref $N:ident : $T:ty = $e:expr; $($rest:tt)*) => {
lazy!(@single, $(#[$attr])* $vis static ref $N : $T = $e);
lazy!($($rest)*);
};
(@single, $(#[$attr:meta])* $vis:vis static ref $N:ident : $T:ty = $e:expr) => {
#[allow(non_camel_case_types)]
$(#[$attr])*
$vis struct $N {
inner: $crate::Lazy<$T>,
}
impl core::ops::Deref for $N {
type Target = $T;
fn deref(&self) -> &$T {
self.inner.get(|| $e)
}
}
impl $N {
#[allow(dead_code)]
$vis fn get() -> &'static $T {
&*$N
}
#[allow(dead_code)]
$vis fn get_mut() -> &'static mut $T {
$N.inner.get_mut(|| $e)
}
}
$vis static $N: $N = $N { inner: $crate::Lazy::INIT };
};
() => ()
}
#[macro_export]
macro_rules! lazy_arc {
($(#[$attr:meta])* $vis:vis static ref $N:ident : Arc<$T:ty> = $e:expr; $($rest:tt)*) => {
lazy!(@arc, $(#[$attr])* $vis static ref $N : Arc<$T> = Arc::new($e));
lazy_arc!($($rest)*);
};
(@arc, $(#[$attr:meta])* $vis:vis static ref $N:ident : Arc<$T:ty> = $e:expr) => {
lazy!(@single, $(#[$attr])* $vis static ref $N : Arc<$T> = $e);
impl $N {
#[allow(dead_code)]
$vis fn get() -> Arc<$T> {
(*$N).clone()
}
#[allow(dead_code)]
$vis fn set(value: $T) {
*$N::get_mut() = Arc::new(value);
}
}
};
() => ()
}