|
| 1 | +use crate::cell::UnsafeCell; |
| 2 | +use crate::fmt; |
| 3 | +use crate::ops::CoerceUnsized; |
| 4 | +use crate::ptr::{self, NonNull}; |
| 5 | + |
| 6 | +/// **Co**variant version of [`UnsafeCell`]. |
| 7 | +#[unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 8 | +#[repr(transparent)] |
| 9 | +#[rustc_pub_transparent] |
| 10 | +// Implementation note: |
| 11 | +// |
| 12 | +// We could make `CovariantUnsafeCell` be the canonical lang item and make `UnsafeCell` a wrapper |
| 13 | +// over it, with `PhantomData<*mut T>`. That would however be a huge compiler change, without clear |
| 14 | +// benefit. |
| 15 | +// |
| 16 | +// As such, `CovariantUnsafeCell` is wrapping `UnsafeCell` instead. It is a lang-item only to |
| 17 | +// hardcode its variance to be **co**variant in `T`, even though it is wrapping `UnsafeCell` which |
| 18 | +// is **in**variant in `T`. |
| 19 | +#[lang = "covariant_unsafe_cell"] |
| 20 | +pub struct CovariantUnsafeCell<T: ?Sized>(UnsafeCell<T>); |
| 21 | + |
| 22 | +#[unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 23 | +impl<T: ?Sized> !Sync for CovariantUnsafeCell<T> {} |
| 24 | + |
| 25 | +impl<T> CovariantUnsafeCell<T> { |
| 26 | + /// Constructs a new instance of `CovariantUnsafeCell` which will wrap the specified value. |
| 27 | + /// |
| 28 | + /// All access to the inner value through `&CovariantUnsafeCell<T>` requires `unsafe` code. |
| 29 | + /// |
| 30 | + /// # Examples |
| 31 | + /// |
| 32 | + /// ``` |
| 33 | + /// #![feature(covariant_unsafe_cell)] |
| 34 | + /// use std::cell::CovariantUnsafeCell; |
| 35 | + /// |
| 36 | + /// let uc = CovariantUnsafeCell::new(5); |
| 37 | + /// ``` |
| 38 | + #[unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 39 | + #[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 40 | + #[inline(always)] |
| 41 | + pub const fn new(value: T) -> CovariantUnsafeCell<T> { |
| 42 | + CovariantUnsafeCell(UnsafeCell::new(value)) |
| 43 | + } |
| 44 | + |
| 45 | + /// Unwraps the value, consuming the cell. |
| 46 | + /// |
| 47 | + /// # Examples |
| 48 | + /// |
| 49 | + /// ``` |
| 50 | + /// #![feature(covariant_unsafe_cell)] |
| 51 | + /// use std::cell::CovariantUnsafeCell; |
| 52 | + /// |
| 53 | + /// let uc = CovariantUnsafeCell::new(5); |
| 54 | + /// |
| 55 | + /// let five = uc.into_inner(); |
| 56 | + /// ``` |
| 57 | + #[inline(always)] |
| 58 | + #[unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 59 | + #[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 60 | + pub const fn into_inner(self) -> T { |
| 61 | + self.0.into_inner() |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +impl<T: ?Sized> CovariantUnsafeCell<T> { |
| 66 | + /// Gets a mutable non-null pointer to the wrapped value. |
| 67 | + /// |
| 68 | + /// This can be cast to a pointer of any kind. When creating (shared or mutable) references, you |
| 69 | + /// must uphold the aliasing rules; see [the `UnsafeCell` type-level docs] for more discussion |
| 70 | + /// and caveats. |
| 71 | + /// |
| 72 | + /// [the `UnsafeCell` type-level docs]: super::UnsafeCell#aliasing-rules |
| 73 | + /// |
| 74 | + /// # Examples |
| 75 | + /// |
| 76 | + /// ``` |
| 77 | + /// #![feature(covariant_unsafe_cell)] |
| 78 | + /// use std::cell::CovariantUnsafeCell; |
| 79 | + /// use std::ptr::NonNull; |
| 80 | + /// |
| 81 | + /// let uc = CovariantUnsafeCell::new(5); |
| 82 | + /// |
| 83 | + /// let ptr: NonNull<i32> = uc.get(); |
| 84 | + /// ``` |
| 85 | + #[inline(always)] |
| 86 | + #[rustc_as_ptr] |
| 87 | + #[rustc_should_not_be_called_on_const_items] |
| 88 | + #[unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 89 | + #[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 90 | + pub const fn get(&self) -> NonNull<T> { |
| 91 | + // We can just cast the pointer from `CovariantUnsafeCell<T>` to `T` because of |
| 92 | + // #[repr(transparent)]. |
| 93 | + // |
| 94 | + // Note that this is also known to be allowed for user code as per |
| 95 | + // `#[rustc_pub_transparent]`. |
| 96 | + // SAFETY: the pointer is not null, as it comes from a reference |
| 97 | + unsafe { NonNull::new_unchecked(ptr::from_ref(self).cast_mut() as *mut T) } |
| 98 | + } |
| 99 | + |
| 100 | + /// Returns a mutable reference to the underlying data. |
| 101 | + /// |
| 102 | + /// This call borrows the `CovariantUnsafeCell` mutably (at compile-time) which guarantees that |
| 103 | + /// we possess the only reference. |
| 104 | + /// |
| 105 | + /// # Examples |
| 106 | + /// |
| 107 | + /// ``` |
| 108 | + /// #![feature(covariant_unsafe_cell)] |
| 109 | + /// use std::cell::CovariantUnsafeCell; |
| 110 | + /// |
| 111 | + /// let mut c = CovariantUnsafeCell::new(5); |
| 112 | + /// *c.get_mut() += 1; |
| 113 | + /// |
| 114 | + /// assert_eq!(*c.get_mut(), 6); |
| 115 | + /// ``` |
| 116 | + #[inline(always)] |
| 117 | + #[unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 118 | + #[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 119 | + pub const fn get_mut(&mut self) -> &mut T { |
| 120 | + self.0.get_mut() |
| 121 | + } |
| 122 | + |
| 123 | + /// Gets a mutable pointer to the wrapped value. |
| 124 | + /// The difference from [`get`] is that this function accepts a raw pointer, |
| 125 | + /// which is useful to avoid the creation of temporary references. |
| 126 | + /// |
| 127 | + /// This can be cast to a pointer of any kind. When creating (shared or mutable) references, you |
| 128 | + /// must uphold the aliasing rules; see [the `UnsafeCell` type-level docs] for more discussion |
| 129 | + /// and caveats. |
| 130 | + /// |
| 131 | + /// [`get`]: CovariantUnsafeCell::get() |
| 132 | + /// |
| 133 | + /// # Examples |
| 134 | + /// |
| 135 | + /// Gradual initialization of an `CovariantUnsafeCell` requires `raw_get`, as |
| 136 | + /// calling `get` would require creating a reference to uninitialized data: |
| 137 | + /// |
| 138 | + /// ``` |
| 139 | + /// #![feature(covariant_unsafe_cell)] |
| 140 | + /// use std::cell::CovariantUnsafeCell; |
| 141 | + /// use std::mem::MaybeUninit; |
| 142 | + /// |
| 143 | + /// let m = MaybeUninit::<CovariantUnsafeCell<i32>>::uninit(); |
| 144 | + /// unsafe { CovariantUnsafeCell::raw_get(m.as_ptr()).write(5); } |
| 145 | + /// // avoid below which references to uninitialized data |
| 146 | + /// // unsafe { CovariantUnsafeCell::get(&*m.as_ptr()).write(5); } |
| 147 | + /// let uc = unsafe { m.assume_init() }; |
| 148 | + /// |
| 149 | + /// assert_eq!(uc.into_inner(), 5); |
| 150 | + /// ``` |
| 151 | + #[inline(always)] |
| 152 | + #[unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 153 | + #[rustc_const_unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 154 | + pub const fn raw_get(this: *const Self) -> *mut T { |
| 155 | + // We can just cast the pointer from `UnsafeCell<T>` to `T` because of |
| 156 | + // #[repr(transparent)]. |
| 157 | + // |
| 158 | + // Note that this is also known to be allowed for user code as per |
| 159 | + // `#[rustc_pub_transparent]`. |
| 160 | + this as *const T as *mut T |
| 161 | + } |
| 162 | +} |
| 163 | + |
| 164 | +#[unstable(feature = "coerce_unsized", issue = "18598")] |
| 165 | +impl<T: CoerceUnsized<U>, U> CoerceUnsized<CovariantUnsafeCell<U>> for CovariantUnsafeCell<T> {} |
| 166 | + |
| 167 | +#[unstable(feature = "covariant_unsafe_cell", issue = "159735")] |
| 168 | +impl<T: ?Sized> fmt::Debug for CovariantUnsafeCell<T> { |
| 169 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 170 | + f.debug_struct("CovariantUnsafeCell").finish_non_exhaustive() |
| 171 | + } |
| 172 | +} |
| 173 | + |
| 174 | +#[cfg(test)] |
| 175 | +mod tests { |
| 176 | + use super::*; |
| 177 | + |
| 178 | + fn _covarience<'short, 'long: 'short>( |
| 179 | + x: CovariantUnsafeCell<&'long ()>, |
| 180 | + ) -> CovariantUnsafeCell<&'short ()> { |
| 181 | + x |
| 182 | + } |
| 183 | +} |
0 commit comments