use std::{
cell::UnsafeCell,
fmt::{Debug, Display},
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
pub struct StaticTypeForStd<T, F = fn() -> T> {
val: UnsafeCell<Option<T>>,
is_init_lock: spin::Mutex<bool>,
call_fun: UnsafeCell<ManuallyDrop<F>>,
}
impl<T, F: FnOnce() -> T> StaticTypeForStd<T, F> {
pub const fn new(init_fun: F) -> StaticTypeForStd<T, F> {
Self {
val: UnsafeCell::new(None),
is_init_lock: spin::Mutex::new(false),
call_fun: UnsafeCell::new(ManuallyDrop::new(init_fun)),
}
}
pub fn init_static(&self) {
let mut lock = self.is_init_lock.lock();
if !*lock {
unsafe {
let f = ManuallyDrop::take(&mut *self.call_fun.get());
*self.val.get() = Some(f());
}
*lock = true;
} else {
}
}
}
impl<T, F> StaticTypeForStd<T, F> {
#[must_use]
pub fn is_init(&self) -> bool {
*self.is_init_lock.lock()
}
#[inline(always)]
pub fn get_static(&self) -> Option<&T> {
unsafe { &*self.val.get() }.as_ref()
}
#[inline(always)]
pub fn get_static_unchecked(&self) -> &T {
self.get_static().unwrap_or_else(|| {
unreachable!("StaticType not set value, Please is use static_val.init()")
})
}
#[inline(always)]
pub fn get_mut(&self) -> &mut Option<T> {
unsafe { &mut *self.val.get() }
}
#[inline(always)]
pub fn get_safe(&self) -> Option<&T> {
if !*self.is_init_lock.lock() {
return None;
}
unsafe { &*self.val.get() }.as_ref()
}
pub fn force_drop(&self) -> Option<T> {
*self.is_init_lock.lock() = false;
self.get_mut().take()
}
}
impl<T, F> Deref for StaticTypeForStd<T, F> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.get_static_unchecked()
}
}
impl<T, F: FnOnce() -> T> DerefMut for StaticTypeForStd<T, F> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.get_mut()
.as_mut()
.unwrap_or_else(|| unreachable!("StaticType not set"))
}
}
impl<T, F> AsRef<T> for StaticTypeForStd<T, F> {
fn as_ref(&self) -> &T {
self.get_static_unchecked()
}
}
unsafe impl<T, F> Send for StaticTypeForStd<T, F> {}
unsafe impl<T, F> Sync for StaticTypeForStd<T, F> {}
impl<T: Debug, F: FnOnce() -> T> Debug for StaticTypeForStd<T, F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let val = self.get_static_unchecked();
f.write_fmt(format_args!("{val:?}"))
}
}
impl<T: Display, F> Display for StaticTypeForStd<T, F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let val = self.get_static().map(|x| format!("{x}"));
let val = val.unwrap_or_else(|| "None".to_string());
f.write_str(&val)
}
}
#[test]
fn test_static_type() {
static STATIC_TYPE: StaticTypeForStd<i32> = StaticTypeForStd::new(|| {
let r = 11 + 11;
println!("init_fun: {}", r);
r
});
assert_eq!(format!("{}", STATIC_TYPE), "None");
assert_eq!(STATIC_TYPE.is_init(), false);
STATIC_TYPE.init_static();
STATIC_TYPE.init_static();
assert_eq!(format!("{}", STATIC_TYPE), "22");
assert_eq!(*STATIC_TYPE, 22);
}