fast_able/
static_type.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use std::{
    cell::UnsafeCell,
    fmt::{Debug, Display},
    ops::{Deref, DerefMut},
};

pub struct StaticType<T> {
    val: UnsafeCell<Option<T>>,
    init_lock: spin::Mutex<bool>,
}

impl<T> StaticType<T> {
    #[must_use]
    pub const fn new() -> Self {
        Self {
            val: UnsafeCell::new(None),
            init_lock: spin::Mutex::new(false),
        }
    }
    #[must_use]
    pub fn is_init(&self) -> bool {
        *self.init_lock.lock()
    }

    // plase use `init_call` or `get_or_init`
    // this is not thread safe
    // this fn not public
    #[inline(always)]
    fn init(&self, val: T) {
        *self.get_mut() = Some(val);
    }

    #[inline(always)]
    pub fn init_call<F: FnOnce() -> T>(&self, call: F) {
        let mut lock = self.init_lock.lock();
        if !*lock {
            *lock = true;
            self.init(call());
        }
    }

    #[inline(always)]
    pub fn get_or_init<F: FnOnce() -> T>(&self, call: F) -> &T {
        self.init_call(call);
        self.get_unchecked()
    }

    /// this fn not safed; please before use this fn must use `init_call` or `get_or_init`
    #[inline(always)]
    pub fn get(&self) -> Option<&T> {
        unsafe { &*self.val.get() }.as_ref()
    }

    /// this fn not safed; please before use this fn must use `init_call` or `get_or_init`
    #[inline(always)]
    pub fn get_unchecked(&self) -> &T {
        unsafe { &*self.val.get() }
            .as_ref()
            .unwrap_or_else(|| unreachable!("get_unchecked StaticType not set"))
    }

    /// this fn not safed; please before use this fn must use `init_call` or `get_or_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.init_lock.lock() {
            return None;
        }
        unsafe { &*self.val.get() }.as_ref()
    }

    // 强制drop内存, 请确保在此时没有使用此内存
    // force drop memory, please ensure that the memory is not used before this
    pub fn force_drop(&self) -> Option<T> {
        *self.init_lock.lock() = false;
        self.get_mut().take()
    }
}

impl<T> Deref for StaticType<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        self.get()
            .unwrap_or_else(|| unreachable!("StaticType not set"))
    }
}

// impl derefmut
impl<T> DerefMut for StaticType<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.get_mut()
            .as_mut()
            .unwrap_or_else(|| unreachable!("StaticType not set"))
    }
}

impl<T> AsRef<T> for StaticType<T> {
    fn as_ref(&self) -> &T {
        self.get_unchecked()
    }
}

// impl send and sync
// focer thread safe
unsafe impl<T> Send for StaticType<T> {}
unsafe impl<T> Sync for StaticType<T> {}

impl<T: Default> Default for StaticType<T> {
    fn default() -> Self {
        Self {
            val: Default::default(),
            init_lock: Default::default(),
        }
    }
}

impl<T: Debug> Debug for StaticType<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let val = self.get();
        f.write_fmt(format_args!("{val:?}"))
    }
}

impl<T: Display> Display for StaticType<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let val = self.get().map(|x| format!("{x}"));
        let val = val.unwrap_or_else(|| format!("None"));
        f.write_str(&val)
    }
}

#[test]
fn test_static_type() {
    //定义静态变量
    static STATIC_TYPE: StaticType<i32> = StaticType::new();

    // 没有初始化之前
    assert_eq!(format!("{}", STATIC_TYPE), "None");

    // 初始化数据
    STATIC_TYPE.init_call(|| 22);

    // 第二次初始化数据, 预期不执行
    STATIC_TYPE.init_call(|| 33);

    // 控制台输出相应的数据
    assert_eq!(format!("{}", STATIC_TYPE), "22");

    // 获取数据,数据相同
    assert_eq!(*STATIC_TYPE, 22);
}