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}