1use std::sync::atomic::{AtomicUsize, Ordering};
2
3#[derive(Debug)]
7pub(crate) struct Lazy(AtomicUsize);
8
9impl Lazy {
10 const UNINIT: usize = usize::MAX;
11
12 pub(crate) const fn new() -> Self {
13 Self(AtomicUsize::new(Self::UNINIT))
14 }
15
16 pub(crate) fn get_or_init<F>(&self, f: F) -> usize
17 where
18 F: FnOnce() -> usize,
19 {
20 self.get().unwrap_or_else(|| {
21 let mut val = f();
22 assert_ne!(val, Self::UNINIT);
23 let exchange =
24 self.0
25 .compare_exchange(Self::UNINIT, val, Ordering::AcqRel, Ordering::Acquire);
26 if let Err(old) = exchange {
27 val = old;
28 }
29 debug_assert_ne!(val, Self::UNINIT);
30 val
31 })
32 }
33
34 fn get(&self) -> Option<usize> {
35 let val = self.0.load(Ordering::Acquire);
36 if val == Self::UNINIT {
37 None
38 } else {
39 Some(val)
40 }
41 }
42}
43
44impl Default for Lazy {
45 fn default() -> Self {
46 Lazy::new()
47 }
48}