diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:43 +0000 |
commit | 3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245 (patch) | |
tree | daf049b282ab10e8c3d03e409b3cd84ff3f7690c /vendor/once_cell/src/race.rs | |
parent | Adding debian version 1.68.2+dfsg1-1. (diff) | |
download | rustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.tar.xz rustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.zip |
Merging upstream version 1.69.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/once_cell/src/race.rs')
-rw-r--r-- | vendor/once_cell/src/race.rs | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/vendor/once_cell/src/race.rs b/vendor/once_cell/src/race.rs index fd255c4c7..dff5847c8 100644 --- a/vendor/once_cell/src/race.rs +++ b/vendor/once_cell/src/race.rs @@ -25,6 +25,8 @@ use atomic_polyfill as atomic; use core::sync::atomic; use atomic::{AtomicUsize, Ordering}; +use core::cell::UnsafeCell; +use core::marker::PhantomData; use core::num::NonZeroUsize; /// A thread-safe cell which can be written to only once. @@ -172,6 +174,96 @@ impl OnceBool { } } +/// A thread-safe cell which can be written to only once. +pub struct OnceRef<'a, T> { + inner: OnceNonZeroUsize, + ghost: PhantomData<UnsafeCell<&'a T>>, +} + +// TODO: Replace UnsafeCell with SyncUnsafeCell once stabilized +unsafe impl<'a, T: Sync> Sync for OnceRef<'a, T> {} + +impl<'a, T> core::fmt::Debug for OnceRef<'a, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "OnceRef({:?})", self.inner) + } +} + +impl<'a, T> Default for OnceRef<'a, T> { + fn default() -> Self { + Self::new() + } +} + +impl<'a, T> OnceRef<'a, T> { + /// Creates a new empty cell. + pub const fn new() -> OnceRef<'a, T> { + OnceRef { inner: OnceNonZeroUsize::new(), ghost: PhantomData } + } + + /// Gets a reference to the underlying value. + pub fn get(&self) -> Option<&'a T> { + self.inner.get().map(|ptr| unsafe { &*(ptr.get() as *const T) }) + } + + /// Sets the contents of this cell to `value`. + /// + /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was + /// full. + pub fn set(&self, value: &'a T) -> Result<(), ()> { + let ptr = NonZeroUsize::new(value as *const T as usize).unwrap(); + self.inner.set(ptr) + } + + /// Gets the contents of the cell, initializing it with `f` if the cell was + /// empty. + /// + /// If several threads concurrently run `get_or_init`, more than one `f` can + /// be called. However, all threads will return the same value, produced by + /// some `f`. + pub fn get_or_init<F>(&self, f: F) -> &'a T + where + F: FnOnce() -> &'a T, + { + let f = || NonZeroUsize::new(f() as *const T as usize).unwrap(); + let ptr = self.inner.get_or_init(f); + unsafe { &*(ptr.get() as *const T) } + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// If several threads concurrently run `get_or_init`, more than one `f` can + /// be called. However, all threads will return the same value, produced by + /// some `f`. + pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&'a T, E> + where + F: FnOnce() -> Result<&'a T, E>, + { + let f = || f().map(|value| NonZeroUsize::new(value as *const T as usize).unwrap()); + let ptr = self.inner.get_or_try_init(f)?; + unsafe { Ok(&*(ptr.get() as *const T)) } + } + + /// ```compile_fail + /// use once_cell::race::OnceRef; + /// + /// let mut l = OnceRef::new(); + /// + /// { + /// let y = 2; + /// let mut r = OnceRef::new(); + /// r.set(&y).unwrap(); + /// core::mem::swap(&mut l, &mut r); + /// } + /// + /// // l now contains a dangling reference to y + /// eprintln!("uaf: {}", l.get().unwrap()); + /// ``` + fn _dummy() {} +} + #[cfg(feature = "alloc")] pub use self::once_box::OnceBox; |