1use core::cell::UnsafeCell;
2use core::sync::atomic::{AtomicUsize, Ordering, spin_loop_hint as cpu_relax};
3use core::fmt;
4
5pub struct Once<T> {
22 state: AtomicUsize,
23 data: UnsafeCell<Option<T>>, }
25
26impl<T: fmt::Debug> fmt::Debug for Once<T> {
27 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28 match self.try() {
29 Some(s) => write!(f, "Once {{ data: ")
30 .and_then(|()| s.fmt(f))
31 .and_then(|()| write!(f, "}}")),
32 None => write!(f, "Once {{ <uninitialized> }}")
33 }
34 }
35}
36
37unsafe impl<T: Send + Sync> Sync for Once<T> {}
40unsafe impl<T: Send> Send for Once<T> {}
41
42const INCOMPLETE: usize = 0x0;
45const RUNNING: usize = 0x1;
46const COMPLETE: usize = 0x2;
47const PANICKED: usize = 0x3;
48
49use core::hint::unreachable_unchecked as unreachable;
50
51impl<T> Once<T> {
52 pub const INIT: Self = Once {
54 state: AtomicUsize::new(INCOMPLETE),
55 data: UnsafeCell::new(None),
56 };
57
58 pub const fn new() -> Once<T> {
60 Self::INIT
61 }
62
63 fn force_get<'a>(&'a self) -> &'a T {
64 match unsafe { &*self.data.get() }.as_ref() {
65 None => unsafe { unreachable() },
66 Some(p) => p,
67 }
68 }
69
70 pub fn call_once<'a, F>(&'a self, builder: F) -> &'a T
99 where F: FnOnce() -> T
100 {
101 let mut status = self.state.load(Ordering::SeqCst);
102
103 if status == INCOMPLETE {
104 status = self.state.compare_and_swap(INCOMPLETE,
105 RUNNING,
106 Ordering::SeqCst);
107 if status == INCOMPLETE { let mut finish = Finish { state: &self.state, panicked: true };
110 unsafe { *self.data.get() = Some(builder()) };
111 finish.panicked = false;
112
113 status = COMPLETE;
114 self.state.store(status, Ordering::SeqCst);
115
116 return self.force_get();
118 }
119 }
120
121 loop {
122 match status {
123 INCOMPLETE => unreachable!(),
124 RUNNING => { cpu_relax();
126 status = self.state.load(Ordering::SeqCst)
127 },
128 PANICKED => panic!("Once has panicked"),
129 COMPLETE => return self.force_get(),
130 _ => unsafe { unreachable() },
131 }
132 }
133 }
134
135 pub fn try<'a>(&'a self) -> Option<&'a T> {
137 match self.state.load(Ordering::SeqCst) {
138 COMPLETE => Some(self.force_get()),
139 _ => None,
140 }
141 }
142
143 pub fn wait<'a>(&'a self) -> Option<&'a T> {
146 loop {
147 match self.state.load(Ordering::SeqCst) {
148 INCOMPLETE => return None,
149 RUNNING => cpu_relax(), COMPLETE => return Some(self.force_get()),
151 PANICKED => panic!("Once has panicked"),
152 _ => unsafe { unreachable() },
153 }
154 }
155 }
156}
157
158struct Finish<'a> {
159 state: &'a AtomicUsize,
160 panicked: bool,
161}
162
163impl<'a> Drop for Finish<'a> {
164 fn drop(&mut self) {
165 if self.panicked {
166 self.state.store(PANICKED, Ordering::SeqCst);
167 }
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use std::prelude::v1::*;
174
175 use std::sync::mpsc::channel;
176 use std::thread;
177 use super::Once;
178
179 #[test]
180 fn smoke_once() {
181 static O: Once<()> = Once::new();
182 let mut a = 0;
183 O.call_once(|| a += 1);
184 assert_eq!(a, 1);
185 O.call_once(|| a += 1);
186 assert_eq!(a, 1);
187 }
188
189 #[test]
190 fn smoke_once_value() {
191 static O: Once<usize> = Once::new();
192 let a = O.call_once(|| 1);
193 assert_eq!(*a, 1);
194 let b = O.call_once(|| 2);
195 assert_eq!(*b, 1);
196 }
197
198 #[test]
199 fn stampede_once() {
200 static O: Once<()> = Once::new();
201 static mut RUN: bool = false;
202
203 let (tx, rx) = channel();
204 for _ in 0..10 {
205 let tx = tx.clone();
206 thread::spawn(move|| {
207 for _ in 0..4 { thread::yield_now() }
208 unsafe {
209 O.call_once(|| {
210 assert!(!RUN);
211 RUN = true;
212 });
213 assert!(RUN);
214 }
215 tx.send(()).unwrap();
216 });
217 }
218
219 unsafe {
220 O.call_once(|| {
221 assert!(!RUN);
222 RUN = true;
223 });
224 assert!(RUN);
225 }
226
227 for _ in 0..10 {
228 rx.recv().unwrap();
229 }
230 }
231
232 #[test]
233 fn try() {
234 static INIT: Once<usize> = Once::new();
235
236 assert!(INIT.try().is_none());
237 INIT.call_once(|| 2);
238 assert_eq!(INIT.try().map(|r| *r), Some(2));
239 }
240
241 #[test]
242 fn try_no_wait() {
243 static INIT: Once<usize> = Once::new();
244
245 assert!(INIT.try().is_none());
246 thread::spawn(move|| {
247 INIT.call_once(|| loop { });
248 });
249 assert!(INIT.try().is_none());
250 }
251
252
253 #[test]
254 fn wait() {
255 static INIT: Once<usize> = Once::new();
256
257 assert!(INIT.wait().is_none());
258 INIT.call_once(|| 3);
259 assert_eq!(INIT.wait().map(|r| *r), Some(3));
260 }
261
262 #[test]
263 fn panic() {
264 use ::std::panic;
265
266 static INIT: Once<()> = Once::new();
267
268 let t = panic::catch_unwind(|| {
270 INIT.call_once(|| panic!());
271 });
272 assert!(t.is_err());
273
274 let t = panic::catch_unwind(|| {
276 INIT.call_once(|| {});
277 });
278 assert!(t.is_err());
279 }
280
281 #[test]
282 fn init_constant() {
283 static O: Once<()> = Once::INIT;
284 let mut a = 0;
285 O.call_once(|| a += 1);
286 assert_eq!(a, 1);
287 O.call_once(|| a += 1);
288 assert_eq!(a, 1);
289 }
290}