concolor/color/
lazy.rs

1use std::sync::atomic::{AtomicUsize, Ordering};
2
3/// Specialized once_cell::race::OnceNonZeroUsize
4///
5/// Use MAX instead of MIN for uninit case to make it easier to work with for bitflags
6#[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}