/rust/registry/src/index.crates.io-1949cf8c6b5b557f/getrandom-0.2.10/src/util.rs
Line | Count | Source |
1 | | // Copyright 2019 Developers of the Rand project. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
4 | | // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
5 | | // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
6 | | // option. This file may not be copied, modified, or distributed |
7 | | // except according to those terms. |
8 | | #![allow(dead_code)] |
9 | | use core::{ |
10 | | mem::MaybeUninit, |
11 | | ptr, |
12 | | sync::atomic::{AtomicUsize, Ordering::Relaxed}, |
13 | | }; |
14 | | |
15 | | // This structure represents a lazily initialized static usize value. Useful |
16 | | // when it is preferable to just rerun initialization instead of locking. |
17 | | // Both unsync_init and sync_init will invoke an init() function until it |
18 | | // succeeds, then return the cached value for future calls. |
19 | | // |
20 | | // Both methods support init() "failing". If the init() method returns UNINIT, |
21 | | // that value will be returned as normal, but will not be cached. |
22 | | // |
23 | | // Users should only depend on the _value_ returned by init() functions. |
24 | | // Specifically, for the following init() function: |
25 | | // fn init() -> usize { |
26 | | // a(); |
27 | | // let v = b(); |
28 | | // c(); |
29 | | // v |
30 | | // } |
31 | | // the effects of c() or writes to shared memory will not necessarily be |
32 | | // observed and additional synchronization methods with be needed. |
33 | | pub struct LazyUsize(AtomicUsize); |
34 | | |
35 | | impl LazyUsize { |
36 | 0 | pub const fn new() -> Self { |
37 | 0 | Self(AtomicUsize::new(Self::UNINIT)) |
38 | 0 | } |
39 | | |
40 | | // The initialization is not completed. |
41 | | pub const UNINIT: usize = usize::max_value(); |
42 | | |
43 | | // Runs the init() function at least once, returning the value of some run |
44 | | // of init(). Multiple callers can run their init() functions in parallel. |
45 | | // init() should always return the same value, if it succeeds. |
46 | 0 | pub fn unsync_init(&self, init: impl FnOnce() -> usize) -> usize { |
47 | | // Relaxed ordering is fine, as we only have a single atomic variable. |
48 | 0 | let mut val = self.0.load(Relaxed); |
49 | 0 | if val == Self::UNINIT { |
50 | 0 | val = init(); |
51 | 0 | self.0.store(val, Relaxed); |
52 | 0 | } |
53 | 0 | val |
54 | 0 | } |
55 | | } |
56 | | |
57 | | // Identical to LazyUsize except with bool instead of usize. |
58 | | pub struct LazyBool(LazyUsize); |
59 | | |
60 | | impl LazyBool { |
61 | 0 | pub const fn new() -> Self { |
62 | 0 | Self(LazyUsize::new()) |
63 | 0 | } |
64 | | |
65 | 0 | pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { |
66 | 0 | self.0.unsync_init(|| init() as usize) != 0 |
67 | 0 | } |
68 | | } |
69 | | |
70 | | /// Polyfill for `maybe_uninit_slice` feature's |
71 | | /// `MaybeUninit::slice_assume_init_mut`. Every element of `slice` must have |
72 | | /// been initialized. |
73 | | #[inline(always)] |
74 | 0 | pub unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] { |
75 | | // SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`. |
76 | 0 | &mut *(slice as *mut [MaybeUninit<T>] as *mut [T]) |
77 | 0 | } Unexecuted instantiation: getrandom::util::slice_assume_init_mut::<u8> Unexecuted instantiation: getrandom::util::slice_assume_init_mut::<_> |
78 | | |
79 | | #[inline] |
80 | 0 | pub fn uninit_slice_fill_zero(slice: &mut [MaybeUninit<u8>]) -> &mut [u8] { |
81 | 0 | unsafe { ptr::write_bytes(slice.as_mut_ptr(), 0, slice.len()) }; |
82 | 0 | unsafe { slice_assume_init_mut(slice) } |
83 | 0 | } |
84 | | |
85 | | #[inline(always)] |
86 | 0 | pub fn slice_as_uninit<T>(slice: &[T]) -> &[MaybeUninit<T>] { |
87 | | // SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`. |
88 | | // There is no risk of writing a `MaybeUninit<T>` into the result since |
89 | | // the result isn't mutable. |
90 | 0 | unsafe { &*(slice as *const [T] as *const [MaybeUninit<T>]) } |
91 | 0 | } |
92 | | |
93 | | /// View an mutable initialized array as potentially-uninitialized. |
94 | | /// |
95 | | /// This is unsafe because it allows assigning uninitialized values into |
96 | | /// `slice`, which would be undefined behavior. |
97 | | #[inline(always)] |
98 | 0 | pub unsafe fn slice_as_uninit_mut<T>(slice: &mut [T]) -> &mut [MaybeUninit<T>] { |
99 | | // SAFETY: `MaybeUninit<T>` is guaranteed to be layout-compatible with `T`. |
100 | 0 | &mut *(slice as *mut [T] as *mut [MaybeUninit<T>]) |
101 | 0 | } Unexecuted instantiation: getrandom::util::slice_as_uninit_mut::<u8> Unexecuted instantiation: getrandom::util::slice_as_uninit_mut::<_> |