use core::{
convert::Infallible,
ptr::{self, NonNull},
sync::atomic::{AtomicPtr, Ordering::Relaxed},
};
pub(crate) struct LazyPtr<T>(AtomicPtr<T>);
impl<T> LazyPtr<T> {
pub const fn new() -> Self {
Self(AtomicPtr::new(ptr::null_mut()))
}
#[cold]
fn cold_init<E>(&self, init: impl FnOnce() -> Result<NonNull<T>, E>) -> Result<NonNull<T>, E> {
let val = init()?;
self.0.store(val.as_ptr(), Relaxed);
Ok(val)
}
#[inline]
pub fn try_unsync_init<E>(
&self,
init: impl FnOnce() -> Result<NonNull<T>, E>,
) -> Result<NonNull<T>, E> {
let p = self.0.load(Relaxed);
match NonNull::new(p) {
Some(val) => Ok(val),
None => self.cold_init(init),
}
}
#[inline]
#[allow(dead_code, reason = "Some modules use only `try_unsync_init`")]
pub fn unsync_init(&self, init: impl FnOnce() -> NonNull<T>) -> NonNull<T> {
let Ok(p): Result<_, Infallible> = self.try_unsync_init(|| Ok(init()));
p
}
}