From 92eb038cf6440b5b19b988f97ef7ec4ed54d92bd Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 12 Oct 2024 18:31:10 -0700 Subject: [PATCH] [WIP][pointer] Support generic TransmuteFrom Makes progress on #1122 --- src/impls.rs | 78 ++++---- src/lib.rs | 2 +- src/pointer/invariant.rs | 212 +++++++++++++++++--- src/pointer/ptr.rs | 43 +--- src/pointer/transmute.rs | 416 +++++++++++---------------------------- src/util/macros.rs | 293 ++++++++++++--------------- src/wrappers.rs | 8 +- 7 files changed, 480 insertions(+), 572 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index 0a552d5231..4cf7360852 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -443,13 +443,13 @@ mod atomics { use super::*; macro_rules! impl_traits_for_atomics { - ($($atomics:ident),* $(,)?) => { + ($($atomics:ident[$repr:ty]),* $(,)?) => { $( impl_known_layout!($atomics); - impl_for_transparent_wrapper!(=> TryFromBytes for $atomics); - impl_for_transparent_wrapper!(=> FromZeros for $atomics); - impl_for_transparent_wrapper!(=> FromBytes for $atomics); - impl_for_transparent_wrapper!(=> IntoBytes for $atomics); + impl_for_transmute_from!(=> TryFromBytes for $atomics[UnsafeCell<$repr>]); + impl_for_transmute_from!(=> FromZeros for $atomics[UnsafeCell<$repr>]); + impl_for_transmute_from!(=> FromBytes for $atomics[UnsafeCell<$repr>]); + impl_for_transmute_from!(=> IntoBytes for $atomics[UnsafeCell<$repr>]); )* }; } @@ -461,13 +461,13 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU8, AtomicI8); + impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]); impl_known_layout!(AtomicBool); - impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool); - impl_for_transparent_wrapper!(=> FromZeros for AtomicBool); - impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool); + impl_for_transmute_from!(=> TryFromBytes for AtomicBool[UnsafeCell]); + impl_for_transmute_from!(=> FromZeros for AtomicBool[UnsafeCell]); + impl_for_transmute_from!(=> IntoBytes for AtomicBool[UnsafeCell]); safety_comment! { /// SAFETY: @@ -497,7 +497,7 @@ mod atomics { /// SAFETY: /// All of these pass an atomic type and that type's native equivalent, as /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]); + unsafe_impl_transmute_from_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]); } } @@ -508,13 +508,13 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU16, AtomicI16); + impl_traits_for_atomics!(AtomicU16[u16], AtomicI16[i16]); safety_comment! { /// SAFETY: /// All of these pass an atomic type and that type's native equivalent, as /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]); + unsafe_impl_transmute_from_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]); } } @@ -525,13 +525,13 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU32, AtomicI32); + impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]); safety_comment! { /// SAFETY: /// All of these pass an atomic type and that type's native equivalent, as /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]); + unsafe_impl_transmute_from_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]); } } @@ -542,13 +542,13 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU64, AtomicI64); + impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]); safety_comment! { /// SAFETY: /// All of these pass an atomic type and that type's native equivalent, as /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]); + unsafe_impl_transmute_from_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]); } } @@ -559,21 +559,21 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicUsize, AtomicIsize); + impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]); impl_known_layout!(T => AtomicPtr); // TODO(#170): Implement `FromBytes` and `IntoBytes` once we implement // those traits for `*mut T`. - impl_for_transparent_wrapper!(T => TryFromBytes for AtomicPtr); - impl_for_transparent_wrapper!(T => FromZeros for AtomicPtr); + impl_for_transmute_from!(T => TryFromBytes for AtomicPtr[UnsafeCell<*mut T>]); + impl_for_transmute_from!(T => FromZeros for AtomicPtr[UnsafeCell<*mut T>]); safety_comment! { /// SAFETY: /// This passes an atomic type and that type's native equivalent, as /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]); - unsafe_impl_transparent_wrapper_for_atomic!(T => AtomicPtr [*mut T]); + unsafe_impl_transmute_from_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]); + unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr [*mut T]); } } } @@ -603,12 +603,12 @@ safety_comment! { assert_unaligned!(PhantomData<()>, PhantomData, PhantomData); } -impl_for_transparent_wrapper!(T: Immutable => Immutable for Wrapping); -impl_for_transparent_wrapper!(T: TryFromBytes => TryFromBytes for Wrapping); -impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping); -impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping); -impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping); -impl_for_transparent_wrapper!(T: Unaligned => Unaligned for Wrapping); +impl_for_transmute_from!(T: Immutable => Immutable for Wrapping[T]); +impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping[T]); +impl_for_transmute_from!(T: FromZeros => FromZeros for Wrapping[T]); +impl_for_transmute_from!(T: FromBytes => FromBytes for Wrapping[T]); +impl_for_transmute_from!(T: IntoBytes => IntoBytes for Wrapping[T]); +impl_for_transmute_from!(T: Unaligned => Unaligned for Wrapping[T]); assert_unaligned!(Wrapping<()>, Wrapping); safety_comment! { @@ -620,22 +620,22 @@ safety_comment! { unsafe_impl!(T => FromBytes for MaybeUninit); } -impl_for_transparent_wrapper!(T: Immutable => Immutable for MaybeUninit); -impl_for_transparent_wrapper!(T: Unaligned => Unaligned for MaybeUninit); +impl_for_transmute_from!(T: Immutable => Immutable for MaybeUninit[T]); +impl_for_transmute_from!(T: Unaligned => Unaligned for MaybeUninit[T]); assert_unaligned!(MaybeUninit<()>, MaybeUninit); -impl_for_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop); +impl_for_transmute_from!(T: ?Sized + Immutable => Immutable for ManuallyDrop[T]); +impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop[T]); +impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop[T]); +impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop[T]); +impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop[T]); +impl_for_transmute_from!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop[T]); assert_unaligned!(ManuallyDrop<()>, ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell); -impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell); -impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell); -impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for UnsafeCell); +impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for UnsafeCell[T]); +impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for UnsafeCell[T]); +impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell[T]); +impl_for_transmute_from!(T: ?Sized + Unaligned => Unaligned for UnsafeCell[T]); assert_unaligned!(UnsafeCell<()>, UnsafeCell); // SAFETY: See safety comment in `is_bit_valid` impl. diff --git a/src/lib.rs b/src/lib.rs index 2db7816c0e..ef2ac42781 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2718,7 +2718,7 @@ unsafe fn try_read_from( // We use `from_mut` despite not mutating via `c_ptr` so that we don't need // to add a `T: Immutable` bound. let c_ptr = Ptr::from_mut(&mut candidate); - let c_ptr = c_ptr.transparent_wrapper_into_inner(); + let c_ptr = c_ptr.transmute(); // SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from // `candidate`, which the caller promises is entirely initialized. let c_ptr = unsafe { c_ptr.assume_validity::() }; diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index c6543207dc..2056278b4c 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -13,6 +13,8 @@ //! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) //! triples implementing the [`Invariants`] trait. +use super::*; + /// The invariants of a [`Ptr`][super::Ptr]. pub trait Invariants: Sealed { type Aliasing: Aliasing; @@ -54,8 +56,17 @@ impl Invariants for (A, AA, V) { type WithValidity = (A, AA, VB); } +// NOTE: The `AliasingInner`/`Aliasing` distinction is required so that we can +// add a `MappedTo = Self` bound. For an explanation of the design +// space (and prior attempts), see: +// https://users.rust-lang.org/t/how-to-implement-a-type-level-map-with-an-identity-function/119745 +#[doc(hidden)] +pub trait AliasingInner: Sealed { + type MappedTo: Aliasing; +} + /// The aliasing invariant of a [`Ptr`][super::Ptr]. -pub trait Aliasing: Sealed { +pub trait Aliasing: AliasingInner = Self> + Sealed { /// Is `Self` [`Exclusive`]? #[doc(hidden)] const IS_EXCLUSIVE: bool; @@ -65,44 +76,57 @@ pub trait Aliasing: Sealed { /// Aliasing>::Variance<'a, T>` to inherit this variance. #[doc(hidden)] type Variance<'a, T: 'a + ?Sized>; - - #[doc(hidden)] - type MappedTo: Aliasing; } -/// The alignment invariant of a [`Ptr`][super::Ptr]. -pub trait Alignment: Sealed { - #[doc(hidden)] +#[doc(hidden)] +pub trait AlignmentInner: Sealed { type MappedTo: Alignment; } -/// The validity invariant of a [`Ptr`][super::Ptr]. -pub trait Validity: Sealed { - #[doc(hidden)] +/// The alignment invariant of a [`Ptr`][super::Ptr]. +pub trait Alignment: AlignmentInner = Self> + Sealed {} +impl = Self>> Alignment for V {} + +#[doc(hidden)] +pub trait ValidityInner: Sealed { type MappedTo: Validity; } +/// The validity invariant of a [`Ptr`][super::Ptr]. +pub trait Validity: ValidityInner = Self> + Sealed {} +impl = Self>> Validity for V {} + /// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. /// /// # Safety /// /// Given `A: Reference`, callers may assume that either `A = Shared` or `A = /// Exclusive`. -pub trait Reference: Aliasing + Sealed {} +pub trait Reference: Aliasing + Sealed { + fn with<'a, T, I, S, E, O>(ptr: Ptr<'a, T, I>, shared: S, exclusive: E) -> O + where + T: 'a + ?Sized, + I: Invariants, + S: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O, + E: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O; +} /// It is unknown whether any invariant holds. pub enum Unknown {} -impl Alignment for Unknown { +impl AlignmentInner for Unknown { type MappedTo = M::FromUnknown; } -impl Validity for Unknown { +impl ValidityInner for Unknown { type MappedTo = M::FromUnknown; } /// The `Ptr<'a, T>` does not permit any reads or writes from or to its referent. pub enum Inaccessible {} +impl AliasingInner for Inaccessible { + type MappedTo = M::FromInaccessible; +} impl Aliasing for Inaccessible { const IS_EXCLUSIVE: bool = false; @@ -113,7 +137,6 @@ impl Aliasing for Inaccessible { // // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance type Variance<'a, T: 'a + ?Sized> = &'a T; - type MappedTo = M::FromInaccessible; } /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. @@ -125,12 +148,25 @@ impl Aliasing for Inaccessible { /// /// [`UnsafeCell`]: core::cell::UnsafeCell pub enum Shared {} +impl AliasingInner for Shared { + type MappedTo = M::FromShared; +} impl Aliasing for Shared { const IS_EXCLUSIVE: bool = false; type Variance<'a, T: 'a + ?Sized> = &'a T; - type MappedTo = M::FromShared; } -impl Reference for Shared {} +impl Reference for Shared { + #[inline(always)] + fn with<'a, T, I, S, E, O>(ptr: Ptr<'a, T, I>, shared: S, _exclusive: E) -> O + where + T: 'a + ?Sized, + I: Invariants, + S: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O, + E: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O, + { + shared(ptr.unify_invariants()) + } +} /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`. /// @@ -138,17 +174,30 @@ impl Reference for Shared {} /// referenced by any other `Ptr`s or references, and may not be accessed (read /// or written) other than via this `Ptr`. pub enum Exclusive {} +impl AliasingInner for Exclusive { + type MappedTo = M::FromExclusive; +} impl Aliasing for Exclusive { const IS_EXCLUSIVE: bool = true; type Variance<'a, T: 'a + ?Sized> = &'a mut T; - type MappedTo = M::FromExclusive; } -impl Reference for Exclusive {} +impl Reference for Exclusive { + #[inline(always)] + fn with<'a, T, I, S, E, O>(ptr: Ptr<'a, T, I>, _shared: S, exclusive: E) -> O + where + T: 'a + ?Sized, + I: Invariants, + S: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O, + E: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O, + { + exclusive(ptr.unify_invariants()) + } +} -/// The referent is aligned: for `Ptr`, the referent's address is a -/// multiple of the `T`'s alignment. +/// The referent is aligned: for `Ptr`, the referent's address is a multiple +/// of the `T`'s alignment. pub enum Aligned {} -impl Alignment for Aligned { +impl AlignmentInner for Aligned { type MappedTo = M::FromAligned; } @@ -179,20 +228,20 @@ impl Alignment for Aligned { /// enum type, in which case the same rules apply depending on the state of /// its discriminant, and so on recursively). pub enum AsInitialized {} -impl Validity for AsInitialized { +impl ValidityInner for AsInitialized { type MappedTo = M::FromAsInitialized; } -/// The byte ranges in the referent are fully initialized. In other words, if -/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. +/// The byte ranges in the referent are fully initialized. In other words, +/// if the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. pub enum Initialized {} -impl Validity for Initialized { +impl ValidityInner for Initialized { type MappedTo = M::FromInitialized; } /// The referent is bit-valid for `T`. pub enum Valid {} -impl Validity for Valid { +impl ValidityInner for Valid { type MappedTo = M::FromValid; } @@ -260,6 +309,37 @@ pub use mapping::*; mod mapping { use super::*; + /// A mapping from one set of [`Invariants`] to another. + /// + /// A `Mapping` is a set of an [`AliasingMapping`], an [`AlignmentMapping`], + /// and a [`ValidityMapping`]. Given `I: Invariants` and `M: Mapping`, `M` + /// can be applied to `I` as [`Mapped`](Mapped). + pub trait Mapping { + type Aliasing: AliasingMapping; + type Alignment: AlignmentMapping; + type Validity: ValidityMapping; + } + + // TODO: How to make this less error prone? Right now, e.g., + // `(Preserved, Unknown, Preserved)` and `(Unknown, Preserved, Preserved)` both + // implement `Mapping`, and it's not clear from the definition which + // order the invariants come in. + // + // First attempt was to do `Mapping for ((Aliasing, A), (Alignment, AA), + // (Validity, V))`, but not all of `Aliasing`, `Alignment`, and + // `Validity` are object safe. + impl Mapping for (A, AA, V) { + type Aliasing = A; + type Alignment = AA; + type Validity = V; + } + + impl Mapping for Preserved { + type Aliasing = Preserved; + type Alignment = Preserved; + type Validity = Preserved; + } + /// A mapping from one [`Aliasing`] type to another. /// /// An `AliasingMapping` is a type-level map which maps one `Aliasing` type @@ -311,6 +391,20 @@ mod mapping { type FromValid: Validity; } + /// A mapping which preserves all invariants as-is. + /// + /// `Preserved` is a valid type for any mapping trait ([`Mapping`], + /// [`AliasingMapping`], [`AlignmentMapping`], and [`ValidityMapping`]). + pub enum Preserved {} + + /// The application of the [`Mapping`] `M` to the [`Invariants`] `I`. + #[allow(type_alias_bounds)] + pub type Mapped = ( + MappedAliasing, + MappedAlignment, + MappedValidity, + ); + /// The application of the [`AliasingMapping`] `M` to the [`Aliasing`] `A`. #[allow(type_alias_bounds)] pub type MappedAliasing = A::MappedTo; @@ -331,13 +425,42 @@ mod mapping { type FromExclusive = FromExclusive; } + pub enum UnsafeCellMismatch {} + + impl AliasingMapping for UnsafeCellMismatch { + type FromInaccessible = Inaccessible; + type FromShared = Inaccessible; + type FromExclusive = Exclusive; + } + + impl AliasingMapping for Preserved { + type FromInaccessible = Inaccessible; + type FromShared = Shared; + type FromExclusive = Exclusive; + } + impl AlignmentMapping - for ((Unknown, FromUnknown), (Shared, FromAligned)) + for ((Unknown, FromUnknown), (Aligned, FromAligned)) { type FromUnknown = FromUnknown; type FromAligned = FromAligned; } + impl AlignmentMapping for Unknown { + type FromUnknown = Unknown; + type FromAligned = Unknown; + } + + impl AlignmentMapping for Preserved { + type FromUnknown = Unknown; + type FromAligned = Aligned; + } + + impl AlignmentMapping for Aligned { + type FromUnknown = Aligned; + type FromAligned = Aligned; + } + impl< FromUnknown: Validity, FromAsInitialized: Validity, @@ -363,4 +486,39 @@ mod mapping { type FromInitialized = FromInitialized; type FromValid = Unknown; } + + impl ValidityMapping for Unknown { + type FromUnknown = Unknown; + type FromAsInitialized = Unknown; + type FromInitialized = Unknown; + type FromValid = Unknown; + } + + impl ValidityMapping for Preserved { + type FromUnknown = Unknown; + type FromAsInitialized = AsInitialized; + type FromInitialized = Initialized; + type FromValid = Valid; + } + + impl ValidityMapping for AsInitialized { + type FromUnknown = AsInitialized; + type FromAsInitialized = AsInitialized; + type FromInitialized = AsInitialized; + type FromValid = AsInitialized; + } + + impl ValidityMapping for Initialized { + type FromUnknown = Initialized; + type FromAsInitialized = Initialized; + type FromInitialized = Initialized; + type FromValid = Initialized; + } + + impl ValidityMapping for Valid { + type FromUnknown = Valid; + type FromAsInitialized = Valid; + type FromInitialized = Valid; + type FromValid = Valid; + } } diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 549f42dd48..536e2fcbd3 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -172,9 +172,7 @@ mod _external { /// Methods for converting to and from `Ptr` and Rust's safe reference types. mod _conversions { use super::*; - use crate::pointer::transmute::{ - AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance, - }; + use crate::pointer::transmute::{TransmuteFrom, TransmuteFromPtr}; /// `&'a T` → `Ptr<'a, T>` impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)> @@ -350,25 +348,16 @@ mod _conversions { } } - /// `Ptr<'a, T = Wrapper>` → `Ptr<'a, U>` + /// `Ptr<'a, T>` → `Ptr<'a, U>` impl<'a, T, I> Ptr<'a, T, I> where - T: 'a + TransparentWrapper + ?Sized, + T: 'a + ?Sized, I: Invariants, { - /// Converts `self` to a transparent wrapper type into a `Ptr` to the - /// wrapped inner type. - pub(crate) fn transparent_wrapper_into_inner( - self, - ) -> Ptr< - 'a, - T::Inner, - ( - I::Aliasing, - >::Applied, - >::Applied, - ), - > { + pub(crate) fn transmute(self) -> Ptr<'a, U, Mapped> + where + U: ?Sized + TransmuteFromPtr, + { // SAFETY: // - By invariant on `TransparentWrapper::cast_into_inner`: // - This cast preserves address and referent size, and thus the @@ -379,20 +368,8 @@ mod _conversions { // byte ranges. Since `p` and the returned pointer address the // same byte range, they refer to `UnsafeCell`s at the same byte // ranges. - let c = unsafe { self.cast_unsized_unchecked(|p| T::cast_into_inner(p)) }; - // SAFETY: By invariant on `TransparentWrapper`, since `self` - // satisfies the alignment invariant `I::Alignment`, `c` (of type - // `T::Inner`) satisfies the given "applied" alignment invariant. - let c = unsafe { - c.assume_alignment::<>::Applied>() - }; - // SAFETY: By invariant on `TransparentWrapper`, since `self` - // satisfies the validity invariant `I::Validity`, `c` (of type - // `T::Inner`) satisfies the given "applied" validity invariant. - let c = unsafe { - c.assume_validity::<>::Applied>() - }; - c + let ptr = unsafe { self.cast_unsized_unchecked(|p| U::cast_from(p)) }; + unsafe { ptr.assume_invariants() } } } @@ -478,7 +455,7 @@ mod _transitions { /// # Safety /// /// The caller promises that `self` satisfies the invariants `H`. - const unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { + pub(super) const unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { // SAFETY: The caller has promised to satisfy all parameterized // invariants of `Ptr`. `Ptr`'s other invariants are satisfied // by-contract by the source `Ptr`. diff --git a/src/pointer/transmute.rs b/src/pointer/transmute.rs index 113eb60ec3..8c954fbab4 100644 --- a/src/pointer/transmute.rs +++ b/src/pointer/transmute.rs @@ -12,348 +12,158 @@ use core::{ num::Wrapping, }; -use crate::{ - pointer::invariant::{self, Invariants}, - Unalign, -}; +use crate::{pointer::invariant::*, Unalign}; -/// A type which has the same layout as the type it wraps. -/// -/// # Safety -/// -/// `T: TransparentWrapper` implies that `T` has the same size as [`T::Inner`]. -/// Further, `T: TransparentWrapper` implies that: -/// - If `T::UnsafeCellVariance = Covariant`, then `T` has `UnsafeCell`s -/// covering the same byte ranges as `T::Inner`. -/// - If a `T` pointer satisfies the alignment invariant `I::Alignment`, then -/// that same pointer, cast to `T::Inner`, satisfies the alignment invariant -/// `>::Applied`. -/// - If a `T` pointer satisfies the validity invariant `I::Validity`, then that -/// same pointer, cast to `T::Inner`, satisfies the validity invariant -/// `>::Applied`. -/// -/// [`T::Inner`]: TransparentWrapper::Inner -/// [`UnsafeCell`]: core::cell::UnsafeCell -/// [`T::AlignmentVariance`]: TransparentWrapper::AlignmentVariance -/// [`T::ValidityVariance`]: TransparentWrapper::ValidityVariance -#[doc(hidden)] -pub unsafe trait TransparentWrapper { - type Inner: ?Sized; - - type UnsafeCellVariance; - type AlignmentVariance: AlignmentVariance; - type ValidityVariance: ValidityVariance; - - /// Casts a wrapper pointer to an inner pointer. - /// - /// # Safety - /// - /// The resulting pointer has the same address and provenance as `ptr`, and - /// addresses the same number of bytes. - fn cast_into_inner(ptr: *mut Self) -> *mut Self::Inner; +use super::{BecauseExclusive, BecauseImmutable, ReadReason}; + +trait NoWrite {} + +impl NoWrite for T {} +impl NoWrite for T {} + +pub unsafe trait TransmuteFromPtr: TransmuteFrom {} + +pub enum BecauseNoWrite {} +unsafe impl TransmuteFromPtr for U +where + A: Aliasing, + T: ?Sized, + U: ?Sized + TransmuteFrom + NoWrite, +{ +} + +pub enum BecauseBidirectional {} +unsafe impl TransmuteFromPtr for U +where + A: Aliasing, + T: ?Sized + TransmuteFrom, + U: ?Sized + TransmuteFrom, +{ +} - /// Casts an inner pointer to a wrapper pointer. +// U: TransmuteFrom +// +// T: Read +// +// A::MappedTo<>::Mapping::Aliasing> == A + +// unsafe impl TransmuteFromPtr for U +// where +// T: ?Sized + crate::Immutable, +// U: ?Sized + crate::Immutable + TransmuteFrom, +// { +// } + +// unsafe impl TransmuteFromPtr for U +// where +// T: ?Sized + TransmuteFrom, +// U: ?Sized + TransmuteFrom, +// { +// } + +// unsafe impl TransmuteFromPtr for U +// where +// T: ?Sized + TransmuteFrom, +// U: ?Sized + TransmuteFrom, +// { +// } + +pub unsafe trait TransmuteFrom { + type Mapping: Mapping; + + /// Casts a `*mut T` to a `*mut Self`. /// /// # Safety /// /// The resulting pointer has the same address and provenance as `ptr`, and /// addresses the same number of bytes. - fn cast_from_inner(ptr: *mut Self::Inner) -> *mut Self; + fn cast_from(ptr: *mut T) -> *mut Self; } -#[allow(unreachable_pub)] -#[doc(hidden)] -pub trait AlignmentVariance { - type Applied: invariant::Alignment; -} +unsafe impl TransmuteFrom for T { + type Mapping = Preserved; -#[allow(unreachable_pub)] -#[doc(hidden)] -pub trait ValidityVariance { - type Applied: invariant::Validity; + fn cast_from(ptr: *mut T) -> *mut T { + ptr + } } -#[doc(hidden)] -#[allow(missing_copy_implementations, missing_debug_implementations)] -pub enum Covariant {} +unsafe impl TransmuteFrom for MaybeUninit { + type Mapping = (Preserved, Preserved, Valid); -impl AlignmentVariance for Covariant { - type Applied = I; + fn cast_from(ptr: *mut T) -> *mut MaybeUninit { + ptr.cast() + } } -impl ValidityVariance for Covariant { - type Applied = I; +unsafe impl TransmuteFrom> for T { + type Mapping = (Preserved, Preserved, Unknown); + + fn cast_from(ptr: *mut MaybeUninit) -> *mut T { + ptr.cast() + } } -#[doc(hidden)] -#[allow(missing_copy_implementations, missing_debug_implementations)] -pub enum Invariant {} +unsafe impl TransmuteFrom for ManuallyDrop { + type Mapping = Preserved; -impl AlignmentVariance for Invariant { - type Applied = invariant::Unknown; + fn cast_from(ptr: *mut T) -> *mut ManuallyDrop { + ptr as *mut ManuallyDrop + } } -impl ValidityVariance for Invariant { - type Applied = invariant::Unknown; -} +unsafe impl TransmuteFrom> for T { + type Mapping = Preserved; -// SAFETY: -// - Per [1], `MaybeUninit` has the same size as `T`. -// - See inline comments for other safety justifications. -// -// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: -// -// `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as -// `T` -unsafe impl TransparentWrapper for MaybeUninit { - type Inner = T; - - // SAFETY: `MaybeUninit` has `UnsafeCell`s covering the same byte ranges - // as `Inner = T`. This is not explicitly documented, but it can be - // inferred. Per [1] in the preceding safety comment, `MaybeUninit` has - // the same size as `T`. Further, note the signature of - // `MaybeUninit::assume_init_ref` [2]: - // - // pub unsafe fn assume_init_ref(&self) -> &T - // - // If the argument `&MaybeUninit` and the returned `&T` had `UnsafeCell`s - // at different offsets, this would be unsound. Its existence is proof that - // this is not the case. - // - // [2] https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#method.assume_init_ref - type UnsafeCellVariance = Covariant; - // SAFETY: Per [1], `MaybeUninit` has the same layout as `T`, and thus - // has the same alignment as `T`. - // - // [1] Per https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#layout-1: - // - // `MaybeUninit` is guaranteed to have the same size, alignment, and - // ABI as `T`. - type AlignmentVariance = Covariant; - // SAFETY: `MaybeUninit` has no validity invariants. Thus, a valid - // `MaybeUninit` is not necessarily a valid `T`. - type ValidityVariance = Invariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut MaybeUninit) -> *mut T { - // SAFETY: Per [1] (from comment above), `MaybeUninit` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::() + fn cast_from(ptr: *mut ManuallyDrop) -> *mut T { + ptr as *mut T } +} - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut MaybeUninit { - // SAFETY: Per [1] (from comment above), `MaybeUninit` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() +unsafe impl TransmuteFrom for Wrapping { + type Mapping = Preserved; + + fn cast_from(ptr: *mut T) -> *mut Wrapping { + ptr.cast() } } -// SAFETY: -// - Per [1], `ManuallyDrop` has the same size as `T`. -// - See inline comments for other safety justifications. -// -// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: -// -// `ManuallyDrop` is guaranteed to have the same layout and bit validity as -// `T` -unsafe impl TransparentWrapper for ManuallyDrop { - type Inner = T; - - // SAFETY: Per [1], `ManuallyDrop` has `UnsafeCell`s covering the same - // byte ranges as `Inner = T`. - // - // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: - // - // `ManuallyDrop` is guaranteed to have the same layout and bit - // validity as `T`, and is subject to the same layout optimizations as - // `T`. As a consequence, it has no effect on the assumptions that the - // compiler makes about its contents. - type UnsafeCellVariance = Covariant; - // SAFETY: Per [1], `ManuallyDrop` has the same layout as `T`, and thus - // has the same alignment as `T`. - // - // [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: - // - // `ManuallyDrop` is guaranteed to have the same layout and bit - // validity as `T` - type AlignmentVariance = Covariant; - - // SAFETY: Per [1] (from comment above), `ManuallyDrop` has the same bit - // validity as `T`. - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut ManuallyDrop) -> *mut T { - // SAFETY: Per [1] (from comment above), `ManuallyDrop` has the same - // layout as `T`. Thus, this cast preserves size even if `T` is unsized. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut T; - } +unsafe impl TransmuteFrom> for T { + type Mapping = Preserved; - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut ManuallyDrop { - // SAFETY: Per [1] (from comment above), `ManuallyDrop` has the same - // layout as `T`. Thus, this cast preserves size even if `T` is unsized. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut ManuallyDrop; + fn cast_from(ptr: *mut Wrapping) -> *mut T { + ptr.cast() } } -// SAFETY: -// - Per [1], `Wrapping` has the same size as `T`. -// - See inline comments for other safety justifications. -// -// [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: -// -// `Wrapping` is guaranteed to have the same layout and ABI as `T`. -unsafe impl TransparentWrapper for Wrapping { - type Inner = T; - - // SAFETY: Per [1], `Wrapping` has the same layout as `T`. Since its - // single field (of type `T`) is public, it would be a breaking change to - // add or remove fields. Thus, we know that `Wrapping` contains a `T` (as - // opposed to just having the same size and alignment as `T`) with no pre- - // or post-padding. Thus, `Wrapping` must have `UnsafeCell`s covering the - // same byte ranges as `Inner = T`. - // - // [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: - // - // `Wrapping` is guaranteed to have the same layout and ABI as `T`. - type UnsafeCellVariance = Covariant; - // SAFETY: Per [1], `Wrapping` has the same layout as `T`, and thus has - // the same alignment as `T`. - // - // [1] Per https://doc.rust-lang.org/core/num/struct.Wrapping.html#layout-1: - // - // `Wrapping` is guaranteed to have the same layout and ABI as `T`. - type AlignmentVariance = Covariant; - - // SAFETY: `Wrapping` has only one field, which is `pub` [2]. We are also - // guaranteed per [1] (from the comment above) that `Wrapping` has the - // same layout as `T`. The only way for both of these to be true - // simultaneously is for `Wrapping` to have the same bit validity as `T`. - // In particular, in order to change the bit validity, one of the following - // would need to happen: - // - `Wrapping` could change its `repr`, but this would violate the layout - // guarantee. - // - `Wrapping` could add or change its fields, but this would be a - // stability-breaking change. - // - // [2] https://doc.rust-lang.org/core/num/struct.Wrapping.html - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut Wrapping) -> *mut T { - // SAFETY: Per [1] (from comment above), `Wrapping` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::() - } +unsafe impl TransmuteFrom for UnsafeCell { + type Mapping = (UnsafeCellMismatch, Preserved, Preserved); - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut Wrapping { - // SAFETY: Per [1] (from comment above), `Wrapping` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() + fn cast_from(ptr: *mut T) -> *mut UnsafeCell { + ptr as *mut UnsafeCell } } -// SAFETY: -// - Per [1], `UnsafeCell` has the same size as `T`. -// - See inline comments for other safety justifications. -// -// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: -// -// `UnsafeCell` has the same in-memory representation as its inner type -// `T`. -unsafe impl TransparentWrapper for UnsafeCell { - type Inner = T; - - // SAFETY: Since we set this to `Invariant`, we make no safety claims. - type UnsafeCellVariance = Invariant; - - // SAFETY: Per [1] (from comment on impl), `Unalign` has the same - // representation as `T`, and thus has the same alignment as `T`. - type AlignmentVariance = Covariant; - - // SAFETY: Per [1], `Unalign` has the same bit validity as `T`. - // Technically the term "representation" doesn't guarantee this, but the - // subsequent sentence in the documentation makes it clear that this is the - // intention. - // - // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: - // - // `UnsafeCell` has the same in-memory representation as its inner type - // `T`. A consequence of this guarantee is that it is possible to convert - // between `T` and `UnsafeCell`. - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut UnsafeCell) -> *mut T { - // SAFETY: Per [1] (from comment above), `UnsafeCell` has the same - // representation as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut T; - } +unsafe impl TransmuteFrom> for T { + type Mapping = (UnsafeCellMismatch, Preserved, Preserved); - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut UnsafeCell { - // SAFETY: Per [1] (from comment above), `UnsafeCell` has the same - // representation as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut UnsafeCell; + fn cast_from(ptr: *mut UnsafeCell) -> *mut T { + ptr as *mut T } } -// SAFETY: `Unalign` promises to have the same size as `T`. -// -// See inline comments for other safety justifications. -unsafe impl TransparentWrapper for Unalign { - type Inner = T; - - // SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same - // byte ranges as `Inner = T`. - type UnsafeCellVariance = Covariant; - - // SAFETY: Since `Unalign` promises to have alignment 1 regardless of - // `T`'s alignment. Thus, an aligned pointer to `Unalign` is not - // necessarily an aligned pointer to `T`. - type AlignmentVariance = Invariant; - - // SAFETY: `Unalign` promises to have the same validity as `T`. - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut Unalign) -> *mut T { - // SAFETY: Per the safety comment on the impl block, `Unalign` has - // the size as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::() +unsafe impl TransmuteFrom for Unalign { + type Mapping = (Preserved, Aligned, Preserved); + + fn cast_from(ptr: *mut T) -> *mut Unalign { + ptr.cast() } +} + +unsafe impl TransmuteFrom> for T { + type Mapping = (Preserved, Unknown, Preserved); - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut Unalign { - // SAFETY: Per the safety comment on the impl block, `Unalign` has - // the size as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() + fn cast_from(ptr: *mut Unalign) -> *mut T { + ptr.cast() } } diff --git a/src/util/macros.rs b/src/util/macros.rs index af9f35bdb9..6e7960b198 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -190,160 +190,152 @@ macro_rules! unsafe_impl { }; } -/// Implements `$trait` for a type which implements `TransparentWrapper`. +/// Implements `$trait` for a type which is `TransmuteFrom<$repr>` where `$repr: +/// $trait`. /// /// Calling this macro is safe; the internals of the macro emit appropriate /// trait bounds which ensure that the given impl is sound. -macro_rules! impl_for_transparent_wrapper { +macro_rules! impl_for_transmute_from { ( $(#[$attr:meta])* $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)? - => $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? + => $trait:ident for $ty:ty[$repr:ty] $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? ) => { $(#[$attr])* #[allow(non_local_definitions)] // This block implements `$trait` for `$ty` under the following // conditions: - // - `$ty: TransparentWrapper` - // - `$ty::Inner: $trait` - // - For some `Xxx`, `$ty::XxxVariance = Covariant` (`Xxx` is determined - // by the `@define_is_transparent_wrapper` macro arms). This bound - // ensures that some layout property is the same between `$ty` and - // `$ty::Inner`. Which layout property this is depends on the trait - // being implemented (for example, `FromBytes` is not concerned with - // alignment, but is concerned with bit validity). + // - `$ty: TransmuteFrom<$repr>` + // - `$repr: $trait` + // - For some invariant `Xxx`, `$ty::Mapping: Mapping` + // (`Xxx` is determined by the `@define_is_transmute_from` macro + // arms). This bound ensures that some layout property is the same + // between `$ty` and `$repr`. Which layout property this is depends on + // the trait being implemented (for example, `FromBytes` is not + // concerned with alignment, but is concerned with bit validity). // // In other words, `$ty` is guaranteed to soundly implement `$trait` - // because some property of its layout is the same as `$ty::Inner`, - // which implements `$trait`. Most of the complexity in this macro is to + // because some property of its layout is the same as `$repr`, which + // implements `$trait`. Most of the complexity in this macro is to // ensure that the above-mentioned conditions are actually met, and that - // the proper variance (ie, the proper layout property) is chosen. + // the proper invariant (ie, the proper layout property) is chosen. // SAFETY: - // - `is_transparent_wrapper` requires: - // - `W: TransparentWrapper` - // - `W::Inner: $trait` - // - `f` is generic over `I: Invariants`, and in its body, calls - // `is_transparent_wrapper::()`. Thus, this code will only - // compile if, for all `I: Invariants`: - // - `$ty: TransparentWrapper` - // - `$ty::Inner: $trait` + // - `is_transmute_from` requires: + // - `R: $trait` + // - `T: TransmuteFrom` + // - `T::Mapping: Mapping<$invariant = Preserved>` + // - `is_transmute_from<$repr, $ty>` is called in the body // - // These two facts - that `$ty: TransparentWrapper` and that - // `$ty::Inner: $trait` - are the preconditions to the full safety - // proofs, which are completed below in the - // `@define_is_transparent_wrapper` macro arms. The safety proof is + // This enforces that `$repr: $trait`, `$ty: TransmuteFrom<$repr>`, and + // `$trait::Mapping: Mapping<$invariant = Preserved>`. `$invariant` is + // chosen below in the `@define_is_transmute_from` macro arms, which + // contain the full safety proofs. They use the facts in this safety + // comment as preconditions for their proofs. The safety proof is // slightly different for each trait. unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?> $trait for $ty { #[allow(dead_code, clippy::missing_inline_in_public_items)] #[cfg_attr(coverage_nightly, coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() { - use crate::pointer::{invariant::Invariants, transmute::*}; - - impl_for_transparent_wrapper!(@define_is_transparent_wrapper $trait); + use crate::pointer::transmute::*; - #[cfg_attr(coverage_nightly, coverage(off))] - const fn f() { - is_transparent_wrapper::(); - } + impl_for_transmute_from!(@define_is_transmute_from $trait); + is_transmute_from::<$repr, $ty>(); } - impl_for_transparent_wrapper!( + impl_for_transmute_from!( @is_bit_valid $(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)? - $trait for $ty + $trait for $ty[$repr] ); } }; - (@define_is_transparent_wrapper Immutable) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has `UnsafeCell`s at the same byte offsets as - // `W::Inner`. `W::Inner: Immutable` implies that `W::Inner` does not - // contain any `UnsafeCell`s, and so `W` does not contain any - // `UnsafeCell`s. Since `W = $ty`, `$ty` can soundly implement - // `Immutable`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper Immutable, UnsafeCellVariance) - }; - (@define_is_transparent_wrapper FromZeros) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // FromZeros` implies that the all-zeros bit pattern is a bit-valid - // instance of `W::Inner`, and so the all-zeros bit pattern is a - // bit-valid instance of `W`. Since `W = $ty`, `$ty` can soundly - // implement `FromZeros`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper FromZeros, ValidityVariance) - }; - (@define_is_transparent_wrapper FromBytes) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // FromBytes` implies that any initialized bit pattern is a bit-valid - // instance of `W::Inner`, and so any initialized bit pattern is a - // bit-valid instance of `W`. Since `W = $ty`, `$ty` can soundly - // implement `FromBytes`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper FromBytes, ValidityVariance) - }; - (@define_is_transparent_wrapper IntoBytes) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // IntoBytes` implies that no bit-valid instance of `W::Inner` contains - // uninitialized bytes, and so no bit-valid instance of `W` contains - // uninitialized bytes. Since `W = $ty`, `$ty` can soundly implement - // `IntoBytes`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper IntoBytes, ValidityVariance) - }; - (@define_is_transparent_wrapper Unaligned) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same alignment as `W::Inner`. `W::Inner: - // Unaligned` implies `W::Inner`'s alignment is 1, and so `W`'s - // alignment is 1. Since `W = $ty`, `W` can soundly implement - // `Unaligned`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper Unaligned, AlignmentVariance) - }; - (@define_is_transparent_wrapper TryFromBytes) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // TryFromBytes` implies that ` { + // SAFETY: `T::Mapping: Mapping` ensures that `T` + // and `R` have `UnsafeCell`s at the same byte offsets. If this weren't + // the case, then it would be unsound to map `Shared` to `Shared` when + // transmuting from `R` to `T`. `R: Immutable` implies that `R` has no + // `UnsafeCell`s, and so `T` doesn't either. Since `T = $ty`, `$ty` can + // soundly implement `Immutable`. + impl_for_transmute_from!(@define_is_transmute_from Immutable, Aliasing) + }; + (@define_is_transmute_from FromZeros) => { + // SAFETY: `T::Mapping: Mapping` requires that `T` + // has the same bit validity as `R`. `R: FromZeros` implies that the + // all-zeros bit pattern is a bit-valid instance of `R`, and so the + // all-zeros bit pattern is a bit-valid instance of `T`. Since `T = + // $ty`, `$ty` can soundly implement `FromZeros`. + impl_for_transmute_from!(@define_is_transmute_from FromZeros, Validity) + }; + (@define_is_transmute_from FromBytes) => { + // SAFETY: `T::Mapping: Mapping` requires that `T` + // has the same bit validity as `R`. `R: FromBytes` implies that any + // initialized bit pattern is a bit-valid instance of `R`, and so the + // any initialized bit pattern is a bit-valid instance of `T`. Since `T + // = $ty`, `$ty` can soundly implement `FromBytes`. + impl_for_transmute_from!(@define_is_transmute_from FromBytes, Validity) + }; + (@define_is_transmute_from IntoBytes) => { + // SAFETY: `T::Mapping: Mapping` requires that `T` + // has the same bit validity as `R`. `R: IntoBytes` implies that no + // bit-valid instance of `R` contains uninitialized bytes, and so no + // bit-valid instance of `T` does either. Since `T = $ty`, `$ty` can + // soundly implement `IntoBytes`. + impl_for_transmute_from!(@define_is_transmute_from IntoBytes, Validity) + }; + (@define_is_transmute_from Unaligned) => { + // SAFETY: `T::Mapping: Mapping` requires that + // `T` has the same alignment as `R`. `R: Unaligned` implies that + // `align_of::() == 1`, and so `align_of::() == 1`. Since `T = + // $ty`, `$ty` can soundly implement `Unaligned`. + impl_for_transmute_from!(@define_is_transmute_from Unaligned, Alignment) + }; + (@define_is_transmute_from TryFromBytes) => { + // SAFETY: `T::Mapping: Mapping` requires that `T` + // has the same bit validity as `R`. `R: TryFromBytes` implies that `::is_bit_valid(c)` only returns `true` if `c` + // references a bit-valid instance of `R`. Thus, `::is_bit_valid(c)` only returns `true` if `c` references - // a bit-valid instance of `W::Inner`. Thus, `::is_bit_valid(c)` only returns `true` if `c` references - // a bit-valid instance of `W`. Below, we implement `::is_bit_valid` by deferring to `::is_bit_valid`. Since `W = $ty`, it is sound for `$ty` - // to implement `TryFromBytes` with this implementation of - // `is_bit_valid`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper TryFromBytes, ValidityVariance) - }; - (@define_is_transparent_wrapper $trait:ident, $variance:ident) => { + // a bit-valid instance of `T`. Below, we implement `::is_bit_valid` by deferring to `::is_bit_valid`. Since `T = $ty`, it is sound for `$ty` + // to implement `TryFromBytes` with this `is_bit_valid` implementation. + impl_for_transmute_from!(@define_is_transmute_from TryFromBytes, Validity) + }; + (@define_is_transmute_from $trait:ident, $invariant:ident) => { #[cfg_attr(coverage_nightly, coverage(off))] - const fn is_transparent_wrapper + ?Sized>() + const fn is_transmute_from + ?Sized>() where - W::Inner: $trait, + R: ?Sized + $trait, + T::Mapping: crate::pointer::invariant::Mapping<$invariant = crate::pointer::invariant::Preserved> {} }; ( @is_bit_valid $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? - TryFromBytes for $ty:ty + TryFromBytes for $ty:ty[$repr:ty] ) => { - // SAFETY: See safety comment in `(@define_is_transparent_wrapper + // SAFETY: See safety comment in `(@define_is_transmute_from // TryFromBytes)` macro arm for an explanation of why this is a sound // implementation of `is_bit_valid`. #[inline] fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { - TryFromBytes::is_bit_valid(candidate.transparent_wrapper_into_inner()) + let candidate: Ptr<'_, $repr, (A, _, _)> = candidate.transmute::<$repr, _>(); + <$repr as TryFromBytes>::is_bit_valid(candidate) } }; ( @is_bit_valid $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? - $trait:ident for $ty:ty + $trait:ident for $ty:ty[$repr:ty] ) => { // Trait other than `TryFromBytes`; no `is_bit_valid` impl. }; } -/// Implements `TransparentWrapper` for an atomic type. +/// Implements `TransmuteFrom<$native>` for an atomic type and +/// vice-versa. /// /// # Safety /// @@ -356,18 +348,22 @@ macro_rules! impl_for_transparent_wrapper { target_has_atomic = "64", target_has_atomic = "ptr" ))] -macro_rules! unsafe_impl_transparent_wrapper_for_atomic { +macro_rules! unsafe_impl_transmute_from_for_atomic { ($(#[$attr:meta])* $(,)?) => {}; ($(#[$attr:meta])* $atomic:ty [$native:ty], $($atomics:ty [$natives:ty]),* $(,)?) => { $(#[$attr])* // SAFETY: See safety comment in next match arm. - unsafe impl crate::pointer::transmute::TransparentWrapper for $atomic { - unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); + unsafe impl crate::pointer::transmute::TransmuteFrom> for $atomic { + unsafe_impl_transmute_from_for_atomic!(@inner UnsafeCell<$native> => $atomic); + } + // SAFETY: See safety comment in next match arm. + unsafe impl crate::pointer::transmute::TransmuteFrom<$atomic> for UnsafeCell<$native> { + unsafe_impl_transmute_from_for_atomic!(@inner $atomic => UnsafeCell<$native>); } - unsafe_impl_transparent_wrapper_for_atomic!($(#[$attr])* $($atomics [$natives],)*); + unsafe_impl_transmute_from_for_atomic!($(#[$attr])* $($atomics [$natives],)*); }; ($(#[$attr:meta])* $tyvar:ident => $atomic:ty [$native:ty]) => { - // We implement for `$atomic` and set `Inner = $native`. The caller has + // We implement `TransmuteFrom<$native>` for `$atomic`. The caller has // promised that `$atomic` and `$native` are an atomic type and its // native counterpart, respectively. Per [1], `$atomic` and `$native` // have the same size. @@ -377,71 +373,38 @@ macro_rules! unsafe_impl_transparent_wrapper_for_atomic { // This type has the same size and bit validity as the underlying // integer type $(#[$attr])* - unsafe impl<$tyvar, I: crate::invariant::Invariants> crate::pointer::transmute::TransparentWrapper for $atomic { - unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); + unsafe impl<$tyvar> crate::pointer::transmute::TransmuteFrom> for $atomic { + unsafe_impl_transmute_from_for_atomic!(@inner UnsafeCell<$native> => $atomic); } - }; - (@inner $atomic:ty [$native:ty]) => { - type Inner = UnsafeCell<$native>; - - // SAFETY: It is "obvious" that each atomic type contains a single - // `UnsafeCell` that covers all bytes of the type, but we can also prove - // it: - // - Since `$atomic` provides an API which permits loading and storing - // values of type `$native` via a `&self` (shared) reference, *some* - // interior mutation must be happening, and interior mutation can only - // happen via `UnsafeCell`. Further, there must be enough bytes in - // `$atomic` covered by an `UnsafeCell` to hold every possible value - // of `$native`. - // - Per [1], `$atomic` has the same size as `$native`. This on its own - // isn't enough: it would still be possible for `$atomic` to store - // `$native` using a compact representation (for `$native` types for - // which some bit patterns are illegal). However, this is ruled out by - // the fact that `$atomic` has the same bit validity as `$native` [1]. - // Thus, we can conclude that every byte of `$atomic` must be covered - // by an `UnsafeCell`. - // - // Thus, every byte of `$atomic` is covered by an `UnsafeCell`, and we - // set `type Inner = UnsafeCell<$native>`. Thus, `Self` and - // `Self::Inner` have `UnsafeCell`s covering the same byte ranges. - // - // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: - // - // This type has the same size and bit validity as the underlying - // integer type - type UnsafeCellVariance = crate::pointer::transmute::Covariant; - // SAFETY: No safety justification is required for an invariant - // variance. - type AlignmentVariance = crate::pointer::transmute::Invariant; - - // SAFETY: Per [1], all atomic types have the same bit validity as their - // native counterparts. The caller has promised that `$atomic` and - // `$native` are an atomic type and its native counterpart, - // respectively. - // - // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: - // - // This type has the same size and bit validity as the underlying - // integer type - type ValidityVariance = crate::pointer::transmute::Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut $atomic) -> *mut UnsafeCell<$native> { - // SAFETY: Per [1] (from comment on impl block), `$atomic` has the - // same size as `$native`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() + unsafe impl<$tyvar> crate::pointer::transmute::TransmuteFrom<$atomic> for UnsafeCell<$native> { + unsafe_impl_transmute_from_for_atomic!(@inner $atomic => UnsafeCell<$native>); } + }; + (@inner $from:ty => $to:ty) => { + type Mapping = ( + // SAFETY: The only invariant which is preserved is `Exclusive -> + // Exclusive`. It is always sound to preserve `Exclusive` regardless + // of the presence or absence of `UnsafeCell`s. + crate::pointer::invariant::Preserved, + // SAFETY: No invariant is preserved; no safety proof required. + crate::pointer::invariant::Unknown, + // SAFETY: Per [1], all atomic types have the same bit validity as + // their native counterparts. The caller has promised that `$atomic` + // and `$native` are an atomic type and its native counterpart, + // respectively. + // + // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: + // + // This type has the same size and bit validity as the underlying + // integer type + crate::pointer::invariant::Preserved, + ); #[inline(always)] - fn cast_from_inner(ptr: *mut UnsafeCell<$native>) -> *mut $atomic { - // SAFETY: Per [1] (from comment on impl block), `$atomic` has the - // same size as `$native`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::<$atomic>() + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut $from) -> *mut $to { + ptr as *mut $to } }; } diff --git a/src/wrappers.rs b/src/wrappers.rs index ac2442486e..b0707560b1 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -200,7 +200,7 @@ impl Unalign { /// may prefer [`Deref::deref`], which is infallible. #[inline(always)] pub fn try_deref(&self) -> Result<&T, AlignmentError<&Self, T>> { - let inner = Ptr::from_ref(self).transparent_wrapper_into_inner(); + let inner = Ptr::from_ref(self).transmute(); match inner.bikeshed_try_into_aligned() { Ok(aligned) => Ok(aligned.as_ref()), Err(err) => Err(err.map_src(|src| src.into_unalign().as_ref())), @@ -217,7 +217,7 @@ impl Unalign { /// callers may prefer [`DerefMut::deref_mut`], which is infallible. #[inline(always)] pub fn try_deref_mut(&mut self) -> Result<&mut T, AlignmentError<&mut Self, T>> { - let inner = Ptr::from_mut(self).transparent_wrapper_into_inner(); + let inner = Ptr::from_mut(self).transmute(); match inner.bikeshed_try_into_aligned() { Ok(aligned) => Ok(aligned.as_mut()), Err(err) => Err(err.map_src(|src| src.into_unalign().as_mut())), @@ -401,14 +401,14 @@ impl Deref for Unalign { #[inline(always)] fn deref(&self) -> &T { - Ptr::from_ref(self).transparent_wrapper_into_inner().bikeshed_recall_aligned().as_ref() + Ptr::from_ref(self).transmute().bikeshed_recall_aligned().as_ref() } } impl DerefMut for Unalign { #[inline(always)] fn deref_mut(&mut self) -> &mut T { - Ptr::from_mut(self).transparent_wrapper_into_inner().bikeshed_recall_aligned().as_mut() + Ptr::from_mut(self).transmute().bikeshed_recall_aligned().as_mut() } }