diff options
| author | Mara Bos <m-ou.se@m-ou.se> | 2022-03-29 19:30:55 +0200 |
|---|---|---|
| committer | Mara Bos <m-ou.se@m-ou.se> | 2022-03-29 19:48:39 +0200 |
| commit | 750ab0370e4e52b6c22181e1187f463ffce0a230 (patch) | |
| tree | 988debbb88ae5f1686e1ac7edc02e40675f9fbb6 | |
| parent | 11909e3588319235e28e99294e17cca11db1d7e2 (diff) | |
| download | rust-750ab0370e4e52b6c22181e1187f463ffce0a230.tar.gz rust-750ab0370e4e52b6c22181e1187f463ffce0a230.zip | |
Add SyncUnsafeCell.
| -rw-r--r-- | library/core/src/cell.rs | 103 | ||||
| -rw-r--r-- | library/core/src/fmt/mod.rs | 9 | ||||
| -rw-r--r-- | library/core/src/lib.rs | 1 |
3 files changed, 109 insertions, 4 deletions
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 9dbb5eecd46..8f283a7f43a 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1990,9 +1990,106 @@ impl<T> const From<T> for UnsafeCell<T> { #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {} +/// [`UnsafeCell`], but [`Sync`]. +/// +/// This is just an `UnsafeCell`, except it implements `Sync` +/// if `T` implements `Sync`. +/// +/// `UnsafeCell` doesn't implement `Sync`, to prevent accidental mis-use. +/// You can use `SyncUnsafeCell` instead of `UnsafeCell` to allow it to be +/// shared between threads, if that's intentional. +/// Providing proper synchronization is still the task of the user, +/// making this type just as unsafe to use. +/// +/// See [`UnsafeCell`] for details. +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +#[repr(transparent)] +pub struct SyncUnsafeCell<T: ?Sized> { + value: UnsafeCell<T>, +} + +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +unsafe impl<T: ?Sized + Sync> Sync for SyncUnsafeCell<T> {} + +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +impl<T> SyncUnsafeCell<T> { + /// Constructs a new instance of `SyncUnsafeCell` which will wrap the specified value. + #[inline] + pub const fn new(value: T) -> Self { + Self { value: UnsafeCell { value } } + } + + /// Unwraps the value. + #[inline] + pub const fn into_inner(self) -> T { + self.value.into_inner() + } +} + +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +impl<T: ?Sized> SyncUnsafeCell<T> { + /// Gets a mutable pointer to the wrapped value. + /// + /// This can be cast to a pointer of any kind. + /// Ensure that the access is unique (no active references, mutable or not) + /// when casting to `&mut T`, and ensure that there are no mutations + /// or mutable aliases going on when casting to `&T` + #[inline] + pub const fn get(&self) -> *mut T { + self.value.get() + } + + /// Returns a mutable reference to the underlying data. + /// + /// This call borrows the `SyncUnsafeCell` mutably (at compile-time) which + /// guarantees that we possess the only reference. + #[inline] + pub const fn get_mut(&mut self) -> &mut T { + self.value.get_mut() + } + + /// Gets a mutable pointer to the wrapped value. + /// + /// See [`UnsafeCell::get`] for details. + #[inline] + pub const fn raw_get(this: *const Self) -> *mut T { + // We can just cast the pointer from `SyncUnsafeCell<T>` to `T` because + // of #[repr(transparent)] on both SyncUnsafeCell and UnsafeCell. + // See UnsafeCell::raw_get. + this as *const T as *mut T + } +} + +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +impl<T: Default> Default for SyncUnsafeCell<T> { + /// Creates an `SyncUnsafeCell`, with the `Default` value for T. + fn default() -> SyncUnsafeCell<T> { + SyncUnsafeCell::new(Default::default()) + } +} + +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +#[rustc_const_unstable(feature = "const_convert", issue = "88674")] +impl<T> const From<T> for SyncUnsafeCell<T> { + /// Creates a new `SyncUnsafeCell<T>` containing the given value. + fn from(t: T) -> SyncUnsafeCell<T> { + SyncUnsafeCell::new(t) + } +} + +#[unstable(feature = "coerce_unsized", issue = "27732")] +//#[unstable(feature = "sync_unsafe_cell", issue = "none")] +impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {} + #[allow(unused)] -fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) { +fn assert_coerce_unsized( + a: UnsafeCell<&i32>, + b: SyncUnsafeCell<&i32>, + c: Cell<&i32>, + d: RefCell<&i32>, +) { let _: UnsafeCell<&dyn Send> = a; - let _: Cell<&dyn Send> = b; - let _: RefCell<&dyn Send> = c; + let _: SyncUnsafeCell<&dyn Send> = b; + let _: Cell<&dyn Send> = c; + let _: RefCell<&dyn Send> = d; } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 84cf1753f86..19a2140abe8 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -2,7 +2,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; +use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell}; use crate::char::EscapeDebugExtArgs; use crate::marker::PhantomData; use crate::mem; @@ -2396,6 +2396,13 @@ impl<T: ?Sized> Debug for UnsafeCell<T> { } } +#[unstable(feature = "sync_unsafe_cell", issue = "none")] +impl<T: ?Sized> Debug for SyncUnsafeCell<T> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.debug_struct("SyncUnsafeCell").finish_non_exhaustive() + } +} + // If you expected tests to be here, look instead at the core/tests/fmt.rs file, // it's a lot easier than creating all of the rt::Piece structures here. // There are also tests in the alloc crate, for those that need allocations. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 5c16346cbd1..d18df506d2b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -139,6 +139,7 @@ #![feature(const_type_id)] #![feature(const_type_name)] #![feature(const_default_impls)] +#![feature(const_unsafecell_get_mut)] #![feature(core_panic)] #![feature(duration_consts_float)] #![feature(maybe_uninit_uninit_array)] |
