static_init/
raw_static.rs

1pub use static_impl::{ConstStatic, Static, __set_init_prio};
2
3#[cfg(debug_mode)]
4mod static_impl {
5
6    use crate::{FinalyMode, InitMode, StaticInfo};
7
8    use core::cmp::Ordering::*;
9    use core::mem::MaybeUninit;
10    use core::ops::{Deref, DerefMut};
11    use core::sync::atomic::{AtomicI32, Ordering};
12
13    /// The actual type of mutable *dynamic statics*.
14    ///
15    /// It implements `Deref<Target=T>` and `DerefMut`.
16    ///
17    /// All associated functions are only usefull for the implementation of
18    /// the `dynamic` proc macro attribute
19    pub struct Static<T>(MaybeUninit<T>, StaticInfo, AtomicI32);
20
21    /// The actual type of non mutable *dynamic statics*.
22    ///
23    /// It implements `Deref<Target=T>`.
24    ///
25    /// All associated functions are only usefull for the implementation of
26    /// the `dynamic` proc macro attribute
27    pub struct ConstStatic<T>(Static<T>);
28
29    static CUR_INIT_PRIO: AtomicI32 = AtomicI32::new(i32::MIN);
30
31    static CUR_DROP_PRIO: AtomicI32 = AtomicI32::new(i32::MIN);
32
33    #[doc(hidden)]
34    #[inline]
35    pub fn __set_init_prio(v: i32) {
36        CUR_INIT_PRIO.store(v, Ordering::Relaxed);
37    }
38
39    impl<T> Static<T> {
40        #[inline]
41        /// Build an uninitialized Static
42        ///
43        /// # Safety
44        ///
45        /// The target object should be a mutable statics to ensure
46        /// that all accesses to this object are unsafe.
47        pub const unsafe fn uninit(info: StaticInfo) -> Self {
48            Self(MaybeUninit::uninit(), info, AtomicI32::new(0))
49        }
50        #[inline]
51        pub const fn from(v: T, info: StaticInfo) -> Self {
52            Static(MaybeUninit::new(v), info, AtomicI32::new(1))
53        }
54
55        #[inline]
56        pub fn set_to(this: &'static mut Self, v: T) {
57            this.0 = MaybeUninit::new(v);
58            this.2.store(1, Ordering::Relaxed);
59        }
60
61        #[inline]
62        /// # Safety
63        ///
64        /// The objet should not be accessed after this call
65        pub unsafe fn drop(this: &'static mut Self) {
66            if let FinalyMode::ProgramDestructor(prio) = &this.1.drop_mode {
67                CUR_DROP_PRIO.store(*prio as i32, Ordering::Relaxed);
68                this.0.as_mut_ptr().drop_in_place();
69                CUR_DROP_PRIO.store(i32::MIN, Ordering::Relaxed);
70            } else {
71                this.0.as_mut_ptr().drop_in_place();
72            };
73            this.2.store(2, Ordering::Relaxed);
74        }
75    }
76
77    #[inline]
78    fn check_access(info: &StaticInfo, status: i32) {
79        if status == 0 {
80            core::panic!(
81                "Attempt to access variable {:#?} before it is initialized during initialization \
82                 priority {}. Tip: increase init priority of this static to a value larger than \
83                 {prio} (attribute syntax: `#[dynamic(init=<prio>)]`)",
84                info,
85                prio = CUR_INIT_PRIO.load(Ordering::Relaxed)
86            )
87        }
88        if status == 2 {
89            core::panic!(
90                "Attempt to access variable {:#?} after it was destroyed during destruction \
91                 priority {prio}. Tip increase drop priority of this static to a value larger \
92                 than {prio} (attribute syntax: `#[dynamic(drop=<prio>)]`)",
93                info,
94                prio = CUR_DROP_PRIO.load(Ordering::Relaxed)
95            )
96        }
97        let init_prio = CUR_INIT_PRIO.load(Ordering::Relaxed);
98        let drop_prio = CUR_DROP_PRIO.load(Ordering::Relaxed);
99
100        if let FinalyMode::ProgramDestructor(prio) = &info.drop_mode {
101            match drop_prio.cmp(&(*prio as i32)) {
102                Equal => core::panic!(
103                    "This access to variable {:#?} is not sequenced before to its drop. Tip \
104                     increase drop priority of this static to a value larger than {prio} \
105                     (attribute syntax: `#[dynamic(drop=<prio>)]`)",
106                    info,
107                    prio = drop_prio
108                ),
109                Greater => core::panic!(
110                    "Unexpected initialization order while accessing {:#?} from drop priority {}. \
111                     This is a bug of `static_init` library, please report \"
112             the issue inside `static_init` repository.",
113                    info,
114                    drop_prio
115                ),
116                Less => (),
117            }
118        }
119
120        if let InitMode::ProgramConstructor(prio) = &info.init_mode {
121            match init_prio.cmp(&(*prio as i32)) {
122                Equal => core::panic!(
123                    "This access to variable {:#?} is not sequenced after construction of this \
124                     static. Tip increase init priority of this static to a value larger than \
125                     {prio} (attribute syntax: `#[dynamic(init=<prio>)]`)",
126                    info,
127                    prio = init_prio
128                ),
129                Greater => core::panic!(
130                    "Unexpected initialization order while accessing {:#?} from init priority {}. \
131                     This is a bug of `static_init` library, please report \"
132             the issue inside `static_init` repository.",
133                    info,
134                    init_prio,
135                ),
136                Less => (),
137            }
138        }
139    }
140
141    impl<T> Deref for Static<T> {
142        type Target = T;
143        #[inline(always)]
144        fn deref(&self) -> &T {
145            check_access(&self.1, self.2.load(Ordering::Relaxed));
146            // SAFETY: The object is either
147            //  - built with `uninit`, in which case it is a mutable static
148            //    so all access path to it are unsafe
149            //  - or built with `from` in which case it is necessarily initialized
150            unsafe { &*self.0.as_ptr() }
151        }
152    }
153    impl<T> DerefMut for Static<T> {
154        #[inline(always)]
155        fn deref_mut(&mut self) -> &mut T {
156            check_access(&self.1, self.2.load(Ordering::Relaxed));
157            // SAFETY: The object is either
158            //  - built with `uninit`, in which case it is a mutable static
159            //    so all access path to it are unsafe
160            //  - or built with `from` in which case it is necessarily initialized
161            unsafe { &mut *self.0.as_mut_ptr() }
162        }
163    }
164
165    impl<T> ConstStatic<T> {
166        #[inline]
167        /// Build an uninitialized ConstStatic
168        ///
169        /// # Safety
170        ///
171        /// The target object should be a mutable static to
172        /// ensure that all accesses to the object are unsafe.
173        pub const unsafe fn uninit(info: StaticInfo) -> Self {
174            Self(Static::uninit(info))
175        }
176        #[inline]
177        pub const fn from(v: T, info: StaticInfo) -> Self {
178            Self(Static::from(v, info))
179        }
180        #[inline]
181        /// # Safety
182        ///
183        /// The reference to self should be unique.
184        pub fn set_to(this: &'static mut Self, v: T) {
185            Static::set_to(&mut this.0, v)
186        }
187        #[inline]
188        /// # Safety
189        ///
190        /// The objet should not be accessed after this call
191        pub unsafe fn drop(this: &'static mut Self) {
192            Static::drop(&mut this.0);
193        }
194    }
195
196    impl<T> Deref for ConstStatic<T> {
197        type Target = T;
198        #[inline(always)]
199        fn deref(&self) -> &T {
200            // SAFETY: The object is either
201            //  - built with `uninit`, in which case it is a mutable static
202            //    so all access path to it are unsafe
203            //  - or built with `from` in which case it is necessarily initialized
204            &*self.0
205        }
206    }
207}
208
209#[cfg(not(debug_mode))]
210mod static_impl {
211    use core::mem::MaybeUninit;
212    use core::ops::{Deref, DerefMut};
213
214    /// The actual type of mutable *dynamic statics*.
215    ///
216    /// It implements `Deref<Target=T>` and `DerefMut`.
217    ///
218    /// All associated functions are only usefull for the implementation of
219    /// the `dynamic` proc macro attribute
220    pub struct Static<T>(MaybeUninit<T>);
221
222    /// The actual type of non mutable *dynamic statics*.
223    ///
224    /// It implements `Deref<Target=T>`.
225    ///
226    /// All associated functions are only usefull for the implementation of
227    /// the `dynamic` proc macro attribute
228    pub struct ConstStatic<T>(Static<T>);
229
230    #[doc(hidden)]
231    #[inline(always)]
232    pub fn __set_init_prio(_: i32) {}
233
234    //As a trait in order to avoid noise;
235    impl<T> Static<T> {
236        #[inline]
237        /// Build a new static.
238        ///
239        /// # Safety
240        ///
241        /// The target object must be a mutable static
242        pub const unsafe fn uninit() -> Self {
243            Self(MaybeUninit::uninit())
244        }
245        #[inline]
246        pub const fn from(v: T) -> Self {
247            Self(MaybeUninit::new(v))
248        }
249
250        #[inline]
251        pub fn set_to(this: &'static mut Self, v: T) {
252            this.0 = MaybeUninit::new(v);
253        }
254
255        #[inline]
256        /// Drop the inner object
257        ///
258        /// # Safety
259        ///
260        /// The object should have been previously initialized
261        pub unsafe fn drop(this: &'static mut Self) {
262            this.0.as_mut_ptr().drop_in_place();
263        }
264    }
265
266    impl<T> Deref for Static<T> {
267        type Target = T;
268        #[inline(always)]
269        fn deref(&self) -> &T {
270            // SAFETY: The object is either
271            //  - built with `uninit`, in which case it is a mutable static
272            //    so all access path to it are unsafe
273            //  - or built with `from` in which case it is necessarily initialized
274            unsafe { &*self.0.as_ptr() }
275        }
276    }
277    impl<T> DerefMut for Static<T> {
278        #[inline(always)]
279        fn deref_mut(&mut self) -> &mut T {
280            // SAFETY: The object is either
281            //  - built with `uninit`, in which case it is a mutable static
282            //    so all access path to it are unsafe
283            //  - or built with `from` in which case it is necessarily initialized
284            unsafe { &mut *self.0.as_mut_ptr() }
285        }
286    }
287
288    impl<T> ConstStatic<T> {
289        #[inline]
290        /// Build a new ConstStatic
291        ///
292        /// # Safety
293        ///
294        /// The target object must be a mutable static
295        pub const unsafe fn uninit() -> Self {
296            Self(Static::uninit())
297        }
298        #[inline]
299        pub const fn from(v: T) -> Self {
300            Self(Static::from(v))
301        }
302        #[inline]
303        pub fn set_to(this: &'static mut Self, v: T) {
304            Static::set_to(&mut this.0, v)
305        }
306        #[inline]
307        /// # Safety
308        ///
309        /// The object should have been previously initialized
310        pub unsafe fn drop(this: &'static mut Self) {
311            Static::drop(&mut this.0);
312        }
313    }
314
315    impl<T> Deref for ConstStatic<T> {
316        type Target = T;
317        #[inline(always)]
318        fn deref(&self) -> &T {
319            // SAFETY: The object is either
320            //  - built with `uninit`, in which case it is a mutable static
321            //    so all access path to it are unsafe
322            //  - or built with `from` in which case it is necessarily initialized
323            &*self.0
324        }
325    }
326}