summaryrefslogtreecommitdiffstats
path: root/vendor/once_cell/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/once_cell/src')
-rw-r--r--vendor/once_cell/src/lib.rs14
-rw-r--r--vendor/once_cell/src/race.rs92
2 files changed, 102 insertions, 4 deletions
diff --git a/vendor/once_cell/src/lib.rs b/vendor/once_cell/src/lib.rs
index 41313f736..83149ac4f 100644
--- a/vendor/once_cell/src/lib.rs
+++ b/vendor/once_cell/src/lib.rs
@@ -208,7 +208,6 @@
//! ```
//! use once_cell::sync::OnceCell;
//!
-//! #[derive(Debug)]
//! pub struct LateInit<T> { cell: OnceCell<T> }
//!
//! impl<T> LateInit<T> {
@@ -228,22 +227,24 @@
//! }
//! }
//!
-//! #[derive(Default, Debug)]
+//! #[derive(Default)]
//! struct A<'a> {
//! b: LateInit<&'a B<'a>>,
//! }
//!
-//! #[derive(Default, Debug)]
+//! #[derive(Default)]
//! struct B<'a> {
//! a: LateInit<&'a A<'a>>
//! }
//!
+//!
//! fn build_cycle() {
//! let a = A::default();
//! let b = B::default();
//! a.b.init(&b);
//! b.a.init(&a);
-//! println!("{:?}", a.b.a.b.a);
+//!
+//! let _a = &a.b.a.b.a;
//! }
//! ```
//!
@@ -315,6 +316,10 @@
//!
//! No, but you can use [`async_once_cell`](https://crates.io/crates/async_once_cell) instead.
//!
+//! **Can I bring my own mutex?**
+//!
+//! There is [generic_once_cell](https://crates.io/crates/generic_once_cell) to allow just that.
+//!
//! # Related crates
//!
//! * [double-checked-cell](https://github.com/niklasf/double-checked-cell)
@@ -323,6 +328,7 @@
//! * [mitochondria](https://crates.io/crates/mitochondria)
//! * [lazy_static](https://crates.io/crates/lazy_static)
//! * [async_once_cell](https://crates.io/crates/async_once_cell)
+//! * [generic_once_cell](https://crates.io/crates/generic_once_cell) (bring your own mutex)
//!
//! Most of this crate's functionality is available in `std` in nightly Rust.
//! See the [tracking issue](https://github.com/rust-lang/rust/issues/74465).
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;