/rust/registry/src/index.crates.io-6f17d22bba15001f/getrandom-0.2.16/src/lazy.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; |
2 | | |
3 | | // This structure represents a lazily initialized static usize value. Useful |
4 | | // when it is preferable to just rerun initialization instead of locking. |
5 | | // unsync_init will invoke an init() function until it succeeds, then return the |
6 | | // cached value for future calls. |
7 | | // |
8 | | // unsync_init supports init() "failing". If the init() method returns UNINIT, |
9 | | // that value will be returned as normal, but will not be cached. |
10 | | // |
11 | | // Users should only depend on the _value_ returned by init() functions. |
12 | | // Specifically, for the following init() function: |
13 | | // fn init() -> usize { |
14 | | // a(); |
15 | | // let v = b(); |
16 | | // c(); |
17 | | // v |
18 | | // } |
19 | | // the effects of c() or writes to shared memory will not necessarily be |
20 | | // observed and additional synchronization methods may be needed. |
21 | | pub(crate) struct LazyUsize(AtomicUsize); |
22 | | |
23 | | impl LazyUsize { |
24 | 0 | pub const fn new() -> Self { |
25 | 0 | Self(AtomicUsize::new(Self::UNINIT)) |
26 | 0 | } |
27 | | |
28 | | // The initialization is not completed. |
29 | | pub const UNINIT: usize = usize::max_value(); |
30 | | |
31 | | // Runs the init() function at most once, returning the value of some run of |
32 | | // init(). Multiple callers can run their init() functions in parallel. |
33 | | // init() should always return the same value, if it succeeds. |
34 | 0 | pub fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize { |
35 | 0 | // Relaxed ordering is fine, as we only have a single atomic variable. |
36 | 0 | let mut val = self.0.load(Relaxed); |
37 | 0 | if val == Self::UNINIT { |
38 | 0 | val = init(); |
39 | 0 | self.0.store(val, Relaxed); |
40 | 0 | } |
41 | 0 | val |
42 | 0 | } |
43 | | } |
44 | | |
45 | | // Identical to LazyUsize except with bool instead of usize. |
46 | | pub(crate) struct LazyBool(LazyUsize); |
47 | | |
48 | | impl LazyBool { |
49 | 0 | pub const fn new() -> Self { |
50 | 0 | Self(LazyUsize::new()) |
51 | 0 | } |
52 | | |
53 | 0 | pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { |
54 | 0 | self.0.unsync_init(|| init() as usize) != 0 |
55 | 0 | } |
56 | | } |