fast_able/
static_type.rs

1use std::{
2    cell::UnsafeCell,
3    fmt::{Debug, Display},
4    ops::{Deref, DerefMut},
5};
6
7pub struct StaticType<T> {
8    val: UnsafeCell<Option<T>>,
9    init_lock: spin::Mutex<bool>,
10}
11
12impl<T> StaticType<T> {
13    #[must_use]
14    pub const fn new() -> Self {
15        Self {
16            val: UnsafeCell::new(None),
17            init_lock: spin::Mutex::new(false),
18        }
19    }
20    #[must_use]
21    pub fn is_init(&self) -> bool {
22        *self.init_lock.lock()
23    }
24
25    // plase use `init_call` or `get_or_init`
26    // this is not thread safe
27    // this fn not public
28    #[inline(always)]
29    fn init(&self, val: T) {
30        *self.get_mut() = Some(val);
31    }
32
33    #[inline(always)]
34    pub fn init_call<F: FnOnce() -> T>(&self, call: F) {
35        let mut lock = self.init_lock.lock();
36        if !*lock {
37            *lock = true;
38            self.init(call());
39        }
40    }
41
42    #[inline(always)]
43    pub fn get_or_init<F: FnOnce() -> T>(&self, call: F) -> &T {
44        self.init_call(call);
45        self.get_static_unchecked()
46    }
47
48    /// this fn not safed; please before use this fn must use `init_call` or `get_or_init`
49    #[inline(always)]
50    pub fn get_static(&self) -> Option<&T> {
51        unsafe { &*self.val.get() }.as_ref()
52    }
53
54    /// this fn not safed; please before use this fn must use `init_call` or `get_or_init`
55    #[inline(always)]
56    pub fn get_static_unchecked(&self) -> &T {
57        self.get_static()
58            .unwrap_or_else(|| unreachable!("StaticType not set value, Please is call static_val.init_call(|| you init code )"))
59    }
60
61    /// this fn not safed; please before use this fn must use `init_call` or `get_or_init`
62    #[inline(always)]
63    pub fn get_mut(&self) -> &mut Option<T> {
64        unsafe { &mut *self.val.get() }
65    }
66
67    #[inline(always)]
68    pub fn get_safe(&self) -> Option<&T> {
69        if !*self.init_lock.lock() {
70            return None;
71        }
72        unsafe { &*self.val.get() }.as_ref()
73    }
74
75    // 强制drop内存, 请确保在此时没有使用此内存
76    // force drop memory, please ensure that the memory is not used before this
77    pub fn force_drop(&self) -> Option<T> {
78        *self.init_lock.lock() = false;
79        self.get_mut().take()
80    }
81}
82
83impl<T> Deref for StaticType<T> {
84    type Target = T;
85    fn deref(&self) -> &Self::Target {
86        self.get_static_unchecked()
87    }
88}
89
90// impl derefmut
91impl<T> DerefMut for StaticType<T> {
92    fn deref_mut(&mut self) -> &mut Self::Target {
93        self.get_mut()
94            .as_mut()
95            .unwrap_or_else(|| unreachable!("StaticType not set"))
96    }
97}
98
99impl<T> AsRef<T> for StaticType<T> {
100    fn as_ref(&self) -> &T {
101        self.get_static_unchecked()
102    }
103}
104
105// impl send and sync
106// focer thread safe
107unsafe impl<T> Send for StaticType<T> {}
108unsafe impl<T> Sync for StaticType<T> {}
109
110impl<T: Default> Default for StaticType<T> {
111    fn default() -> Self {
112        Self {
113            val: Default::default(),
114            init_lock: Default::default(),
115        }
116    }
117}
118
119impl<T: Debug> Debug for StaticType<T> {
120    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121        let val = self.get_static_unchecked();
122        f.write_fmt(format_args!("{val:?}"))
123    }
124}
125
126impl<T: Display> Display for StaticType<T> {
127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        let val = self.get_static().map(|x| format!("{x}"));
129        let val = val.unwrap_or_else(|| "None".to_string());
130        f.write_str(&val)
131    }
132}
133
134#[test]
135fn test_static_type() {
136    //定义静态变量
137    static STATIC_TYPE: StaticType<i32> = StaticType::new();
138
139    // 没有初始化之前
140    assert_eq!(format!("{}", STATIC_TYPE), "None");
141
142    // 初始化数据
143    STATIC_TYPE.init_call(|| 22);
144
145    // 第二次初始化数据, 预期不执行
146    STATIC_TYPE.init_call(|| 33);
147
148    // 控制台输出相应的数据
149    assert_eq!(format!("{}", STATIC_TYPE), "22");
150
151    // 获取数据,数据相同
152    assert_eq!(*STATIC_TYPE, 22);
153}