1#![cfg_attr(not(test), no_std)]
21
22use core::cell::UnsafeCell;
23
24pub struct LateStatic<T> {
26 val: UnsafeCell<Option<T>>,
27}
28
29unsafe impl<T: Send> core::marker::Send for LateStatic<T> {}
30unsafe impl<T: Sync> core::marker::Sync for LateStatic<T> {}
31
32impl<T> LateStatic<T> {
33 pub const fn new() -> Self {
35 LateStatic {
36 val: UnsafeCell::new(None),
37 }
38 }
39
40 pub unsafe fn assign(instance: &LateStatic<T>, val: T) {
49 let option: &mut Option<T> = &mut *instance.val.get();
50 if option.is_some() {
51 panic!("Second assignment to late static");
52 } else {
53 *option = Some(val);
54 }
55 }
56
57 pub unsafe fn clear(instance: &LateStatic<T>) {
64 if !Self::has_value(instance) {
65 panic!("Tried to clear a late static without a value");
66 }
67 let option: &mut Option<T> = &mut *instance.val.get();
68 *option = None;
69 }
70
71 pub unsafe fn has_value(instance: &LateStatic<T>) -> bool {
78 let option: &Option<T> = &*instance.val.get();
79 option.is_some()
80 }
81}
82
83impl<T> core::ops::Deref for LateStatic<T> {
84 type Target = T;
85
86 fn deref(&self) -> &T {
87 unsafe {
88 let option: &Option<T> = &*self.val.get();
89 match option {
90 Some(ref val) => val,
91 None => panic!("Dereference of late static before a value was assigned"),
92 }
93 }
94 }
95}
96
97impl<T> core::ops::DerefMut for LateStatic<T> {
98 fn deref_mut(&mut self) -> &mut T {
99 unsafe {
100 let option: &mut Option<T> = &mut *self.val.get();
101 match option {
102 Some(ref mut val) => val,
103 None => panic!("Dereference of late static before a value was assigned"),
104 }
105 }
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 static ASSIGN_ONCE_TEST: LateStatic<u32> = LateStatic::new();
114 #[test]
115 fn assign_once() {
116 unsafe {
117 assert!(!LateStatic::has_value(&ASSIGN_ONCE_TEST));
118 LateStatic::assign(&ASSIGN_ONCE_TEST, 42);
119 assert!(LateStatic::has_value(&ASSIGN_ONCE_TEST));
120 }
121 }
122
123 static ASSIGN_TWICE_TEST: LateStatic<u32> = LateStatic::new();
124 #[test]
125 #[should_panic]
126 fn assign_twice() {
127 unsafe {
128 LateStatic::assign(&ASSIGN_TWICE_TEST, 42);
129 LateStatic::assign(&ASSIGN_TWICE_TEST, 37);
130 }
131 }
132
133 struct Foo {
134 pub value: u32,
135 }
136
137 static DEREF_CONST_TEST: LateStatic<Foo> = LateStatic::new();
138 #[test]
139 fn deref_const() {
140 unsafe {
141 LateStatic::assign(&DEREF_CONST_TEST, Foo { value: 42 });
142 }
143 assert_eq!(DEREF_CONST_TEST.value, 42);
144 }
145
146 static mut DEREF_MUT_TEST: LateStatic<Foo> = LateStatic::new();
147 #[test]
148 fn deref_mut() {
149 unsafe {
150 LateStatic::assign(&DEREF_MUT_TEST, Foo { value: 42 });
151 assert_eq!(DEREF_MUT_TEST.value, 42);
152 DEREF_MUT_TEST.value = 37;
153 assert_eq!(DEREF_MUT_TEST.value, 37);
154 }
155 }
156
157 static mut DEREF_WITHOUT_VALUE: LateStatic<Foo> = LateStatic::new();
158 #[test]
159 #[should_panic]
160 fn deref_without_value() {
161 unsafe {
162 #[allow(clippy::no_effect)]
163 DEREF_WITHOUT_VALUE.value;
164 }
165 }
166
167 static mut CLEAR_TEST: LateStatic<Foo> = LateStatic::new();
168 #[test]
169 fn clear() {
170 unsafe {
171 LateStatic::assign(&CLEAR_TEST, Foo { value: 42 });
172 assert_eq!(CLEAR_TEST.value, 42);
173 LateStatic::clear(&CLEAR_TEST);
174 assert!(!LateStatic::has_value(&CLEAR_TEST));
175 }
176 }
177
178 static mut CLEAR_WITHOUT_VALUE: LateStatic<Foo> = LateStatic::new();
179 #[test]
180 #[should_panic]
181 fn clear_without_value() {
182 unsafe {
183 LateStatic::clear(&CLEAR_WITHOUT_VALUE);
184 }
185 }
186}