use core::mem::ManuallyDrop;
use core::ops::Deref;
use core::ptr;
use crate::once::OnceLock;
pub struct LazyLock<T, F = fn() -> T> {
once: OnceLock<T>,
init: ManuallyDrop<F>,
}
impl<T, F> LazyLock<T, F>
where
F: FnOnce() -> T,
{
#[inline]
pub const fn new(init: F) -> Self {
Self {
once: OnceLock::new(),
init: ManuallyDrop::new(init),
}
}
pub fn get(&self) -> &T {
let Self { once, init } = self;
once.get_or_init(|| {
unsafe {
let init: F = ptr::read(init.deref());
init()
}
})
}
#[inline]
pub fn try_get(&self) -> Option<&T> {
self.once.get()
}
}
impl<T> Deref for LazyLock<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.get()
}
}
unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {}
#[cfg(test)]
mod test {
extern crate std;
use std::collections::HashMap;
use std::vec::Vec;
use super::*;
static MAP: LazyLock<HashMap<i32, i32>> = LazyLock::new(|| {
let mut map = HashMap::new();
map.insert(12, 12);
map.insert(13, 13);
map.insert(14, 14);
map
});
#[test]
fn test() {
let handles = (0..10).map(|_| {
std::thread::spawn(|| {
for (k, v) in MAP.get() {
assert_eq!(k, v);
}
})
}).collect::<Vec<_>>();
for h in handles { h.join().unwrap() }
}
}