Skip to main content

naga/
racy_lock.rs

1#[cfg(no_std)]
2use alloc::boxed::Box;
3#[cfg(no_std)]
4use once_cell::race::OnceBox;
5#[cfg(std)]
6use std::sync::LazyLock;
7
8#[cfg(std)]
9// Suppress cargo::unused_dependencies lint (since we can’t express “depend on once_cell
10// only if not(std)”).
11use once_cell as _;
12
13#[cfg(std)]
14type Inner<T> = LazyLock<T, fn() -> T>;
15#[cfg(no_std)]
16type Inner<T> = OnceBox<T>;
17
18/// Lazy static helper that uses [`LazyLock`] with `std` and [`OnceBox`] otherwise.
19///
20/// [`LazyLock`]: https://doc.rust-lang.org/stable/std/sync/struct.LazyLock.html
21/// [`OnceBox`]: https://docs.rs/once_cell/latest/once_cell/race/struct.OnceBox.html
22#[derive(Debug)]
23pub struct RacyLock<T: 'static> {
24    inner: Inner<T>,
25    #[cfg(no_std)]
26    init: fn() -> T,
27}
28
29impl<T: 'static> RacyLock<T> {
30    #[cfg(std)]
31    /// Creates a new [`RacyLock`], which will initialize using the provided `init` function.
32    pub const fn new(init: fn() -> T) -> Self {
33        Self {
34            inner: LazyLock::new(init),
35        }
36    }
37
38    #[cfg(no_std)]
39    /// Creates a new [`RacyLock`], which will initialize using the provided `init` function.
40    pub const fn new(init: fn() -> T) -> Self {
41        Self {
42            inner: OnceBox::new(),
43            init,
44        }
45    }
46}
47
48#[cfg(std)]
49impl<T: 'static> core::ops::Deref for RacyLock<T> {
50    type Target = T;
51
52    /// Loads the internal value, initializing it if required.
53    fn deref(&self) -> &Self::Target {
54        &self.inner
55    }
56}
57
58#[cfg(no_std)]
59impl<T: 'static> core::ops::Deref for RacyLock<T> {
60    type Target = T;
61
62    /// Loads the internal value, initializing it if required.
63    fn deref(&self) -> &Self::Target {
64        self.inner.get_or_init(|| Box::new((self.init)()))
65    }
66}