1#![cfg_attr(not(test), no_std)]
2#![doc = include_str!("../README.md")]
3
4use core::cell::UnsafeCell;
5use core::fmt;
6use core::hint::spin_loop;
7use core::mem::MaybeUninit;
8use core::ops::{Deref, DerefMut};
9use core::sync::atomic::{AtomicU8, Ordering};
10
11const UNINIT: u8 = 0;
13const INITIALIZING: u8 = 1;
15const INITED: u8 = 2;
17
18pub struct LazyInit<T> {
23 inited: AtomicU8,
24 data: UnsafeCell<MaybeUninit<T>>,
25}
26
27unsafe impl<T: Send + Sync> Sync for LazyInit<T> {}
28unsafe impl<T: Send> Send for LazyInit<T> {}
29
30impl<T> LazyInit<T> {
31 pub const fn new() -> Self {
33 Self {
34 inited: AtomicU8::new(UNINIT),
35 data: UnsafeCell::new(MaybeUninit::uninit()),
36 }
37 }
38
39 pub fn init_once(&self, data: T) -> &T {
45 self.call_once(|| data).expect("Already initialized")
46 }
47
48 pub fn call_once<F>(&self, f: F) -> Option<&T>
53 where
54 F: FnOnce() -> T,
55 {
56 if self.is_inited() {
58 return None;
59 }
60 loop {
61 match self.inited.compare_exchange_weak(
62 UNINIT,
63 INITIALIZING,
64 Ordering::Acquire,
65 Ordering::Relaxed,
66 ) {
67 Ok(_) => {
68 let value = f();
69 unsafe { (*self.data.get()).as_mut_ptr().write(value) };
70 self.inited.store(INITED, Ordering::Release);
71 return Some(unsafe { self.force_get() });
72 }
73 Err(INITIALIZING) => {
74 while self.inited.load(Ordering::Acquire) == INITIALIZING {
75 spin_loop();
76 }
77 return None;
78 }
79 Err(INITED) => {
80 return None;
81 }
82 Err(UNINIT) => {
83 continue;
84 }
85 _ => unreachable!(),
86 }
87 }
88 }
89
90 #[inline]
92 pub fn is_inited(&self) -> bool {
93 self.inited.load(Ordering::Acquire) == INITED
94 }
95
96 pub fn get(&self) -> Option<&T> {
100 if self.is_inited() {
101 Some(unsafe { self.force_get() })
102 } else {
103 None
104 }
105 }
106
107 pub fn get_mut(&mut self) -> Option<&mut T> {
111 if self.is_inited() {
112 Some(unsafe { self.force_get_mut() })
113 } else {
114 None
115 }
116 }
117
118 #[inline]
124 pub unsafe fn get_unchecked(&self) -> &T {
125 debug_assert!(self.is_inited());
126 self.force_get()
127 }
128
129 #[inline]
135 pub unsafe fn get_mut_unchecked(&mut self) -> &mut T {
136 debug_assert!(self.is_inited());
137 self.force_get_mut()
138 }
139
140 #[inline]
141 unsafe fn force_get(&self) -> &T {
142 (*self.data.get()).assume_init_ref()
143 }
144
145 #[inline]
146 unsafe fn force_get_mut(&mut self) -> &mut T {
147 (*self.data.get()).assume_init_mut()
148 }
149
150 fn panic_message(&self) -> ! {
151 panic!(
152 "Use uninitialized value: {:?}",
153 core::any::type_name::<Self>()
154 )
155 }
156}
157
158impl<T: fmt::Debug> fmt::Debug for LazyInit<T> {
159 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160 match self.get() {
161 Some(s) => write!(f, "LazyInit {{ data: ")
162 .and_then(|()| s.fmt(f))
163 .and_then(|()| write!(f, "}}")),
164 None => write!(f, "LazyInit {{ <uninitialized> }}"),
165 }
166 }
167}
168
169impl<T> Default for LazyInit<T> {
170 fn default() -> Self {
171 Self::new()
172 }
173}
174
175impl<T> Deref for LazyInit<T> {
176 type Target = T;
177 #[inline]
178 fn deref(&self) -> &T {
179 if self.is_inited() {
180 unsafe { self.force_get() }
181 } else {
182 self.panic_message()
183 }
184 }
185}
186
187impl<T> DerefMut for LazyInit<T> {
188 #[inline]
189 fn deref_mut(&mut self) -> &mut T {
190 if self.is_inited() {
191 unsafe { self.force_get_mut() }
192 } else {
193 self.panic_message()
194 }
195 }
196}
197
198impl<T> Drop for LazyInit<T> {
199 fn drop(&mut self) {
200 if self.is_inited() {
201 unsafe { core::ptr::drop_in_place((*self.data.get()).as_mut_ptr()) };
202 }
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209 use std::thread;
210 use std::time::Duration;
211
212 #[test]
213 fn lazyinit_basic() {
214 static VALUE: LazyInit<u32> = LazyInit::new();
215 assert!(!VALUE.is_inited());
216 assert_eq!(VALUE.get(), None);
217
218 VALUE.init_once(233);
219 assert!(VALUE.is_inited());
220 assert_eq!(*VALUE, 233);
221 assert_eq!(VALUE.get(), Some(&233));
222 }
223
224 #[test]
225 #[should_panic]
226 fn panic_on_deref_before_init() {
227 static VALUE: LazyInit<u32> = LazyInit::new();
228 let _ = *VALUE;
229 }
230
231 #[test]
232 #[should_panic]
233 fn panic_on_double_init() {
234 static VALUE: LazyInit<u32> = LazyInit::new();
235 VALUE.init_once(1);
236 VALUE.init_once(2);
237 }
238
239 #[test]
240 fn lazyinit_concurrent() {
241 const N: usize = 16;
242 static VALUE: LazyInit<usize> = LazyInit::new();
243
244 let threads: Vec<_> = (0..N)
245 .map(|i| {
246 thread::spawn(move || {
247 thread::sleep(Duration::from_millis(10));
248 VALUE.call_once(|| i)
249 })
250 })
251 .collect();
252
253 let mut ok = 0;
254 for (i, thread) in threads.into_iter().enumerate() {
255 if thread.join().unwrap().is_some() {
256 ok += 1;
257 assert_eq!(*VALUE, i);
258 }
259 }
260 assert_eq!(ok, 1);
261 }
262 #[test]
263 fn lazyinit_get_unchecked() {
264 static VALUE: LazyInit<u32> = LazyInit::new();
265 VALUE.init_once(123);
266 let v = unsafe { VALUE.get_unchecked() };
267 assert_eq!(*v, 123);
268 }
269
270 #[test]
271 fn lazyinit_get_mut_unchecked() {
272 static mut VALUE: LazyInit<u32> = LazyInit::new();
273 unsafe {
274 VALUE.init_once(123);
275 }
276 let v = unsafe { VALUE.get_mut_unchecked() };
277 *v += 3;
278 assert_eq!(*v, 126);
279 }
280}