diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 7f0dae4175..ac331e0ed3 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -41,7 +41,11 @@ where #[doc(hidden)] pub mod cast { - use core::{marker::PhantomData, mem}; + use core::{ + marker::PhantomData, + mem::{self, MaybeUninit}, + num::Wrapping, + }; use crate::{ layout::{SizeInfo, TrailingSliceLayout}, @@ -290,6 +294,73 @@ pub mod cast { } } + /// TODO + /// + /// # Safety + /// + /// TODO + pub unsafe trait Wrapped { + type Unwrapped: ?Sized; + type CastToUnwrapped: CastExact; + type CastFromUnwrapped: CastExact; + } + + /// TODO + /// + /// # Safety + /// + /// TODO + pub unsafe trait HasWrappedField: Wrapped { + type WrappedField: ?Sized + Wrapped; + } + + // SAFETY: TODO + unsafe impl Wrapped for MaybeUninit { + type Unwrapped = T; + type CastToUnwrapped = CastSizedExact; + type CastFromUnwrapped = CastSizedExact; + } + + // SAFETY: TODO + unsafe impl HasWrappedField for MaybeUninit { + type WrappedField = MaybeUninit; + } + + // SAFETY: TODO + unsafe impl Wrapped for Wrapping { + type Unwrapped = T; + type CastToUnwrapped = CastSizedExact; + type CastFromUnwrapped = CastSizedExact; + } + + // SAFETY: TODO + unsafe impl HasWrappedField for Wrapping { + type WrappedField = Wrapping; + } + + #[allow(missing_debug_implementations, missing_copy_implementations)] + pub struct WrappedProjection { + _never: core::convert::Infallible, + _phantom: PhantomData<(F, W)>, + } + + // SAFETY: TODO + unsafe impl + Project for WrappedProjection + where + W: Wrapped + + HasWrappedField<<::Unwrapped as HasField>::Type>, + W::Unwrapped: HasField, + { + #[inline(always)] + fn project_inner(src: PtrInner<'_, W>) -> *mut W::WrappedField { + src.project::<_, W::CastToUnwrapped>() + .project::<_, Projection>() + .project::<_, ::CastFromUnwrapped>() + .as_ptr() + } + } + /// A transitive sequence of projections. /// /// Given `TU: Project` and `UV: Project`, `TransitiveProject<_, TU, UV>` is diff --git a/src/wrappers.rs b/src/wrappers.rs index 1267888d0d..af22e493e8 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -9,6 +9,7 @@ use core::{fmt, hash::Hash}; use super::*; +use crate::pointer::{invariant::Valid, SizeEq, TransmuteFrom}; /// A type with no alignment requirement. /// @@ -594,6 +595,162 @@ impl fmt::Debug for MaybeUninit { } } +pub use read_only_def::*; +mod read_only_def { + use super::*; + + /// A read-only wrapper. + /// + /// A `ReadOnly` disables any interior mutability in `T`, ensuring that + /// a `&ReadOnly` is genuinely read-only. Thus, `ReadOnly` is + /// [`Immutable`][immutable] regardless of whether `T` is. + /// + /// Note that `&mut ReadOnly` still permits mutation – the read-only + /// property only applies to shared references. + /// + /// [immutable]: crate::Immutable + #[cfg_attr(any(feature = "derive", test), derive(FromBytes, IntoBytes, Unaligned))] + #[repr(transparent)] + pub struct ReadOnly { + // INVARIANT: `inner` is never mutated through a `&ReadOnly` + // reference. + inner: T, + } + + impl ReadOnly { + /// Creates a new `ReadOnly`. + #[inline(always)] + pub const fn new(t: T) -> ReadOnly { + ReadOnly { inner: t } + } + } + + impl ReadOnly { + #[inline(always)] + pub(crate) const fn as_mut(r: &mut ReadOnly) -> &mut T { + // SAFETY: `r: &mut ReadOnly`, so this doesn't violate the invariant + // that `inner` is never mutated through a `&ReadOnly` reference. + &mut r.inner + } + + /// # Safety + /// + /// The caller promises not to mutate the referent (i.e., via interior + /// mutation). + pub(crate) const unsafe fn as_ref_unchecked(r: &ReadOnly) -> &T { + // SAFETY: The caller promises not to mutate the referent. + &r.inner + } + } +} + +// SAFETY: `ReadOnly` is a `#[repr(transparent)` wrapper around `T`. +const _: () = unsafe { + unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ReadOnly); +}; + +// Unused when `feature = "derive"`. +#[allow(unused_unsafe)] +// SAFETY: +// - `ReadOnly` has the same alignment as `T`, and so it is `Unaligned` +// exactly when `T` is as well. +// - `ReadOnly` has the same bit validity as `T`, and so it is `FromZeros`, +// `FromBytes`, or `IntoBytes` exactly when `T` is as well. +// - `TryFromBytes`: `ReadOnly` has the same the same bit validity as `T`, so +// `T::is_bit_valid` is a sound implementation of `is_bit_valid`. +const _: () = unsafe { + impl_or_verify!(T: ?Sized + Unaligned => Unaligned for ReadOnly); + impl_or_verify!( + T: ?Sized + TryFromBytes => TryFromBytes for ReadOnly; + |c| T::is_bit_valid(c.transmute::<_, _, BecauseImmutable>()) + ); + impl_or_verify!(T: ?Sized + FromZeros => FromZeros for ReadOnly); + impl_or_verify!(T: ?Sized + FromBytes => FromBytes for ReadOnly); + impl_or_verify!(T: ?Sized + IntoBytes => IntoBytes for ReadOnly); +}; + +// SAFETY: By invariant, `inner` is never mutated through a `&ReadOnly` +// reference. +const _: () = unsafe { + unsafe_impl!(T: ?Sized => Immutable for ReadOnly); +}; + +const _: () = { + use crate::pointer::cast::CastExact; + + // SAFETY: `ReadOnly` has the same layout as `T`. + define_cast!(unsafe { pub CastFromReadOnly = ReadOnly => T}); + // SAFETY: `ReadOnly` has the same layout as `T`. + unsafe impl CastExact, T> for CastFromReadOnly {} + // SAFETY: `ReadOnly` has the same layout as `T`. + define_cast!(unsafe { pub CastToReadOnly = T => ReadOnly}); + // SAFETY: `ReadOnly` has the same layout as `T`. + unsafe impl CastExact> for CastToReadOnly {} + + impl SizeEq> for T { + type CastFrom = CastFromReadOnly; + } + + impl SizeEq for ReadOnly { + type CastFrom = CastToReadOnly; + } + + // SAFETY: TODO + unsafe impl crate::pointer::cast::Wrapped for ReadOnly { + type Unwrapped = T; + type CastToUnwrapped = CastFromReadOnly; + type CastFromUnwrapped = CastToReadOnly; + } + + // SAFETY: TODO + unsafe impl crate::pointer::cast::HasWrappedField for ReadOnly { + type WrappedField = ReadOnly; + } +}; + +// SAFETY: `ReadOnly` is a `#[repr(transparent)]` wrapper around `T`, and so +// it has the same bit validity as `T`. +unsafe impl TransmuteFrom for ReadOnly {} + +// SAFETY: `ReadOnly` is a `#[repr(transparent)]` wrapper around `T`, and so +// it has the same bit validity as `T`. +unsafe impl TransmuteFrom, Valid, Valid> for T {} + +impl<'a, T: ?Sized + Immutable> From<&'a T> for &'a ReadOnly { + #[inline(always)] + fn from(t: &'a T) -> &'a ReadOnly { + let ro = Ptr::from_ref(t).transmute::<_, _, (_, _)>(); + // SAFETY: `ReadOnly` has the same alignment as `T`, and + // `Ptr::from_ref` produces an aligned `Ptr`. + let ro = unsafe { ro.assume_alignment() }; + ro.as_ref() + } +} + +impl Deref for ReadOnly { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + // SAFETY: By `T: Immutable`, `&T` doesn't permit interior mutation. + unsafe { ReadOnly::as_ref_unchecked(self) } + } +} + +impl DerefMut for ReadOnly { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + ReadOnly::as_mut(self) + } +} + +impl Debug for ReadOnly { + #[inline(always)] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.deref().fmt(f) + } +} + #[cfg(test)] mod tests { use core::panic::AssertUnwindSafe;