diff --git a/src/impls.rs b/src/impls.rs index 0a552d5231..319d71e853 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. @@ -648,7 +648,10 @@ unsafe impl TryFromBytes for UnsafeCell { } #[inline] - fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool + where + Self: invariant::Read, + { // The only way to implement this function is using an exclusive-aliased // pointer. `UnsafeCell`s cannot be read via shared-aliased pointers // (other than by using `unsafe` code, which we can't use since we can't @@ -700,11 +703,12 @@ safety_comment! { /// [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#array-layout unsafe_impl!(const N: usize, T: Immutable => Immutable for [T; N]); unsafe_impl!(const N: usize, T: TryFromBytes => TryFromBytes for [T; N]; |c: Maybe<[T; N]>| { + use invariant::*; // Note that this call may panic, but it would still be sound even if it // did. `is_bit_valid` does not promise that it will not panic (in fact, // it explicitly warns that it's a possibility), and we have not // violated any safety invariants that we must fix before returning. - <[T] as TryFromBytes>::is_bit_valid(c.as_slice()) + <[T] as TryFromBytes>::is_bit_valid::>>(c.as_slice()) }); unsafe_impl!(const N: usize, T: FromZeros => FromZeros for [T; N]); unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]); diff --git a/src/lib.rs b/src/lib.rs index 2db7816c0e..e11196a463 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1321,7 +1321,9 @@ pub unsafe trait TryFromBytes { /// [`UnsafeCell`]: core::cell::UnsafeCell /// [`Shared`]: invariant::Shared #[doc(hidden)] - fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool; + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool + where + Self: invariant::Read; /// Attempts to interpret the given `source` as a `&Self`. /// @@ -2718,7 +2720,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..7331e40a5c 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,23 @@ 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> + + AliasingInner = Inaccessible> + + AliasingInner = Shared> + + AliasingInner = Exclusive> + + Sealed +{ /// Is `Self` [`Exclusive`]? #[doc(hidden)] const IS_EXCLUSIVE: bool; @@ -65,44 +82,85 @@ 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; +#[doc(hidden)] +pub trait AlignmentInner: Sealed { + type MappedTo: Alignment; } /// The alignment invariant of a [`Ptr`][super::Ptr]. -pub trait Alignment: Sealed { - #[doc(hidden)] - type MappedTo: Alignment; +pub trait Alignment: + AlignmentInner = Self> + + AlignmentInner = Unknown> + + AlignmentInner = Aligned> + + Sealed +{ +} +impl< + A: AlignmentInner = Self> + + AlignmentInner = Unknown> + + AlignmentInner = Aligned>, + > Alignment for A +{ } -/// The validity invariant of a [`Ptr`][super::Ptr]. -pub trait Validity: Sealed { - #[doc(hidden)] +#[doc(hidden)] +pub trait ValidityInner: Sealed { type MappedTo: Validity; } +/// The validity invariant of a [`Ptr`][super::Ptr]. +pub trait Validity: + ValidityInner = Self> + + ValidityInner = Unknown> + + ValidityInner = AsInitialized> + + ValidityInner = Initialized> + + ValidityInner = Valid> + + Sealed +{ +} +impl< + V: ValidityInner = Self> + + ValidityInner = Unknown> + + ValidityInner = AsInitialized> + + ValidityInner = Initialized> + + ValidityInner = Valid>, + > 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 +171,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 +182,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 +208,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 +262,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; } @@ -210,27 +293,48 @@ impl Validity for Valid { /// /// As a consequence, if `T: Read`, then any `Ptr` is /// permitted to perform unsynchronized reads from its referent. -pub trait Read {} - -impl Read for T {} -impl Read for T {} - -/// Used to disambiguate [`Read`] impls. -pub trait ReadReason: Sealed {} +pub trait Read {} /// Unsynchronized reads are permitted because only one live [`Ptr`](crate::Ptr) /// or reference may exist to the referent bytes at a time. #[derive(Copy, Clone, Debug)] #[doc(hidden)] pub enum BecauseExclusive {} -impl ReadReason for BecauseExclusive {} +impl Read for T {} /// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s or /// references permit interior mutation. #[derive(Copy, Clone, Debug)] #[doc(hidden)] pub enum BecauseImmutable {} -impl ReadReason for BecauseImmutable {} +impl Read for T {} + +macro_rules! declare_because { + ($($name:ident),*) => {$( + #[doc(hidden)] + pub struct $name(core::marker::PhantomData); + )*}; +} + +declare_because!( + BecauseSliceElem, + BecauseArrayElem, + BecauseSlice // BecauseArray +); + +#[doc(hidden)] +pub struct BecauseArray(core::marker::PhantomData<([(); N], R)>); + +impl Read> for [T] where T: Read {} +impl Read> for T where [T]: Read {} +impl Read> for [T; N] where + T: Read +{ +} +impl Read> for T where + [T; N]: Read +{ +} use sealed::Sealed; mod sealed { @@ -260,6 +364,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 +446,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 +480,60 @@ mod mapping { type FromExclusive = FromExclusive; } + impl AliasingMapping for Inaccessible { + type FromInaccessible = Inaccessible; + type FromShared = Inaccessible; + type FromExclusive = Inaccessible; + } + + 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 AliasingMapping for Shared { + type FromInaccessible = Shared; + type FromShared = Shared; + type FromExclusive = Shared; + } + + impl AliasingMapping for Exclusive { + type FromInaccessible = Exclusive; + type FromShared = Exclusive; + 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 +559,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/mod.rs b/src/pointer/mod.rs index e7b8c0e802..944a959da7 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -12,9 +12,10 @@ mod inner; #[doc(hidden)] pub mod invariant; mod ptr; +pub(crate) mod transmute; #[doc(hidden)] -pub use invariant::{BecauseExclusive, BecauseImmutable, Read, ReadReason}; +pub use invariant::{BecauseExclusive, BecauseImmutable, Read}; #[doc(hidden)] pub use ptr::Ptr; @@ -48,7 +49,6 @@ where pub fn read_unaligned(self) -> T where T: Copy, - R: invariant::ReadReason, T: invariant::Read, { // SAFETY: By invariant on `MaybeAligned`, `raw` contains diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index cb729dbb4f..633c21a06d 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -172,7 +172,7 @@ mod _external { /// Methods for converting to and from `Ptr` and Rust's safe reference types. mod _conversions { use super::*; - use crate::util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance}; + use crate::pointer::transmute::TransmuteFromPtr; /// `&'a T` → `Ptr<'a, T>` impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)> @@ -348,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 @@ -377,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() } } } @@ -476,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`. @@ -658,7 +637,6 @@ mod _transitions { T: TryFromBytes + Read, I::Aliasing: Reference, I: Invariants, - R: crate::pointer::ReadReason, { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to @@ -805,8 +783,6 @@ mod _casts { where T: Read, U: 'a + ?Sized + Read, - R: ReadReason, - S: ReadReason, F: FnOnce(*mut T) -> *mut U, { // SAFETY: Because `T` and `U` both implement `Read`, @@ -829,7 +805,6 @@ mod _casts { #[allow(clippy::wrong_self_convention)] pub(crate) fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> where - R: ReadReason, T: Read, I::Aliasing: Reference, { @@ -919,7 +894,6 @@ mod _casts { CastError, > where - R: ReadReason, I::Aliasing: Reference, U: 'a + ?Sized + KnownLayout + Read, { @@ -983,7 +957,6 @@ mod _casts { where I::Aliasing: Reference, U: 'a + ?Sized + KnownLayout + Read, - R: ReadReason, { match self.try_cast_into(CastType::Prefix, meta) { Ok((slf, remainder)) => { diff --git a/src/pointer/transmute.rs b/src/pointer/transmute.rs new file mode 100644 index 0000000000..890682afd2 --- /dev/null +++ b/src/pointer/transmute.rs @@ -0,0 +1,168 @@ +// Copyright 2024 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use core::{ + cell::UnsafeCell, + mem::{ManuallyDrop, MaybeUninit}, + num::Wrapping, +}; + +use crate::{pointer::invariant::*, Unalign}; + +// T -> U +// U: TransmuteFrom +// T: Read +// +// U: Read + +/// [`Ptr`](crate::Ptr) referents that disallow mutation. +/// +/// `T: NoWrite` implies that a pointer to `T` with aliasing `A` does not +/// permit mutation. This can be because `A` is [`Inaccessible`] or because `A` +/// is [`Shared`] and `T` does not permit interior mutation. +/// +/// # Safety +/// +/// If `T: NoWrite`, then any `Ptr` is guaranteed not to be able +/// to mutate its referent. +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, +{ +} + +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(ptr: *mut T) -> *mut Self; +} + +unsafe impl TransmuteFrom for T { + type Mapping = Preserved; + + fn cast_from(ptr: *mut T) -> *mut T { + ptr + } +} + +unsafe impl TransmuteFrom for MaybeUninit { + type Mapping = (Preserved, Preserved, Valid); + + fn cast_from(ptr: *mut T) -> *mut MaybeUninit { + ptr.cast() + } +} + +unsafe impl TransmuteFrom> for T { + type Mapping = (Preserved, Preserved, Unknown); + + fn cast_from(ptr: *mut MaybeUninit) -> *mut T { + ptr.cast() + } +} + +unsafe impl TransmuteFrom for ManuallyDrop { + type Mapping = Preserved; + + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut T) -> *mut ManuallyDrop { + ptr as *mut ManuallyDrop + } +} + +unsafe impl TransmuteFrom> for T { + type Mapping = Preserved; + + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut ManuallyDrop) -> *mut T { + ptr as *mut T + } +} + +unsafe impl TransmuteFrom for Wrapping { + type Mapping = Preserved; + + fn cast_from(ptr: *mut T) -> *mut Wrapping { + ptr.cast() + } +} + +unsafe impl TransmuteFrom> for T { + type Mapping = Preserved; + + fn cast_from(ptr: *mut Wrapping) -> *mut T { + ptr.cast() + } +} + +unsafe impl TransmuteFrom for UnsafeCell { + type Mapping = (UnsafeCellMismatch, Preserved, Preserved); + + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut T) -> *mut UnsafeCell { + ptr as *mut UnsafeCell + } +} + +unsafe impl TransmuteFrom> for T { + type Mapping = (UnsafeCellMismatch, Preserved, Preserved); + + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut UnsafeCell) -> *mut T { + ptr as *mut T + } +} + +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); + + fn cast_from(ptr: *mut Unalign) -> *mut T { + ptr.cast() + } +} + +unsafe impl TransmuteFrom<[T; N]> for [T] { + type Mapping = Preserved; + + fn cast_from(ptr: *mut [T; N]) -> *mut [T] { + unsafe { core::ptr::slice_from_raw_parts_mut(ptr.cast(), N) } + } +} diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index bd8898a4b8..9d3f6ed77c 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -25,7 +25,7 @@ use core::mem::{self, ManuallyDrop}; use core::ptr::{self, NonNull}; use crate::{ - pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants, ReadReason}, + pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants}, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, }; @@ -528,7 +528,6 @@ where Dst: TryFromBytes + invariant::Read, I: Invariants, I::Aliasing: invariant::Reference, - R: ReadReason, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); diff --git a/src/util/macros.rs b/src/util/macros.rs index 9b33757e59..7585ffe723 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -137,7 +137,10 @@ macro_rules! unsafe_impl { fn only_derive_is_allowed_to_implement_this_trait() {} #[inline] - fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool + where + Self: invariant::Read + { // SAFETY: // - The cast preserves address. The caller has promised that the // cast results in an object of equal or lesser size, and so the @@ -159,7 +162,10 @@ macro_rules! unsafe_impl { fn only_derive_is_allowed_to_implement_this_trait() {} #[inline] - fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool + where + Self: invariant::Read + { // SAFETY: // - The cast preserves address. The caller has promised that the // cast results in an object of equal or lesser size, and so the @@ -178,7 +184,10 @@ macro_rules! unsafe_impl { #[allow(clippy::missing_inline_in_public_items)] #[cfg_attr(coverage_nightly, coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() {} - #[inline(always)] fn is_bit_valid(_: Maybe<'_, Self, AA>) -> bool { true } + #[inline(always)] fn is_bit_valid(_: Maybe<'_, Self, AA>) -> bool + where + Self: invariant::Read + { true } }; (@method $trait:ident) => { #[allow(clippy::missing_inline_in_public_items)] @@ -190,159 +199,279 @@ 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, util::*}; + use crate::pointer::transmute::*; - impl_for_transparent_wrapper!(@define_is_transparent_wrapper $trait); - - #[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 `::is_bit_valid(c)` only returns `true` if `c` references - // a bit-valid instance of `W::Inner`. Thus, ` { + // 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`. 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()) + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool + where + Self: invariant::Read + { + let candidate: Ptr<'_, $repr, (A, _, _)> = candidate.transmute(); + <$repr as TryFromBytes>::is_bit_valid::<_, R>(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 `TransmuteFrom>` for an atomic type and +/// vice-versa. +/// +/// # Safety +/// +/// The caller promises that `$atomic` is an atomic type whose natie equivalent +/// is `$native`. +#[cfg(any( + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr" +))] +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::TransmuteFrom> for $atomic { + // SAFETY: See safety comment in next match arm. + unsafe_impl_transmute_from_for_atomic!(@inner UnsafeCell<$native> => $atomic | Unknown); + } + // SAFETY: See safety comment in next match arm. + unsafe impl crate::pointer::transmute::TransmuteFrom<$atomic> for UnsafeCell<$native> { + // SAFETY: See safety comment in next match arm. + unsafe_impl_transmute_from_for_atomic!(@inner $atomic => UnsafeCell<$native> | Preserved); + } + unsafe_impl_transmute_from_for_atomic!($(#[$attr])* $($atomics [$natives],)*); + }; + ($(#[$attr:meta])* $tyvar:ident => $atomic:ty [$native:ty]) => { + // 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. Per [1], `$native` and `UnsafeCell<$native>` have + // the same size. + // + // [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 + // + // [2] Per https://doc.rust-lang.org/1.81.0/std/cell/struct.UnsafeCell.html#memory-layout: + // + // `UnsafeCell` has the same in-memory representation as its inner + // type `T`. + $(#[$attr])* + unsafe impl<$tyvar> crate::pointer::transmute::TransmuteFrom> for $atomic { + // SAFETY: It is always trivially sound to produce a `Ptr` with + // `Unknown` alignment. + unsafe_impl_transmute_from_for_atomic!(@inner UnsafeCell<$native> => $atomic | Unknown); + } + + unsafe impl<$tyvar> crate::pointer::transmute::TransmuteFrom<$atomic> for UnsafeCell<$native> { + // SAFETY: Per [1], an atomic's alignment is equal to its size. This + // is the maximum possible alignment for any non-zero-sized type + // since size must be a multiple of alignment [2]. Thus, if + // `UnsafeCell<$native>` (which has the same size as `$atomic` as + // proven above) is well-aligned, then so is an `$atomic` at the + // same memory address. + // + // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: + // + // However, the alignment of this type is always equal to its + // size, even on targets where `u64`` has a lesser alignment. + // + // [2] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment: + // + // The size of a value is always a multiple of its alignment. + unsafe_impl_transmute_from_for_atomic!(@inner $atomic => UnsafeCell<$native> | Preserved); + } + }; + // # Safety + // + // The caller promises that `$alignment_mapping` is sound. + (@inner $from:ty => $to:ty | $alignment_mapping:ident) => { + type Mapping = ( + // 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 + // so `$atomic` and `UnsafeCell<$native>` have `UnsafeCell`s + // covering the same byte ranges. That is required in order for + // `Preserved` to be the correct aliasing mapping. + // + // [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, + // The caller guarantees the safety of this mapping. + crate::pointer::invariant::$alignment_mapping, + // 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)] + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut $from) -> *mut $to { + ptr as *mut $to + } + }; +} + /// Implements a trait for a type, bounding on each memeber of the power set of /// a set of type variables. This is useful for implementing traits for tuples /// or `fn` types. diff --git a/src/util/mod.rs b/src/util/mod.rs index dd2e5bdd61..3822873dfe 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -12,463 +12,9 @@ mod macros; #[doc(hidden)] pub mod macro_util; -use core::{ - cell::UnsafeCell, - marker::PhantomData, - mem::{self, ManuallyDrop, MaybeUninit}, - num::{NonZeroUsize, Wrapping}, - ptr::NonNull, -}; - -use crate::{ - error::AlignmentError, - pointer::invariant::{self, Invariants}, - 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 core::{marker::PhantomData, mem, num::NonZeroUsize, ptr::NonNull}; - /// Casts an inner pointer to a wrapper pointer. - /// - /// # 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; -} - -#[allow(unreachable_pub)] -#[doc(hidden)] -pub trait AlignmentVariance { - type Applied: invariant::Alignment; -} - -#[allow(unreachable_pub)] -#[doc(hidden)] -pub trait ValidityVariance { - type Applied: invariant::Validity; -} - -#[doc(hidden)] -#[allow(missing_copy_implementations, missing_debug_implementations)] -pub enum Covariant {} - -impl AlignmentVariance for Covariant { - type Applied = I; -} - -impl ValidityVariance for Covariant { - type Applied = I; -} - -#[doc(hidden)] -#[allow(missing_copy_implementations, missing_debug_implementations)] -pub enum Invariant {} - -impl AlignmentVariance for Invariant { - type Applied = invariant::Unknown; -} - -impl ValidityVariance for Invariant { - type Applied = invariant::Unknown; -} - -// 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::() - } - - #[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::>() - } -} - -// 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; - } - - #[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; - } -} - -// 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::() - } - - #[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::>() - } -} - -// 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; - } - - #[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; - } -} - -// 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::() - } - - #[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::>() - } -} - -/// Implements `TransparentWrapper` for an atomic type. -/// -/// # Safety -/// -/// The caller promises that `$atomic` is an atomic type whose natie equivalent -/// is `$native`. -#[cfg(any( - target_has_atomic = "8", - target_has_atomic = "16", - target_has_atomic = "32", - target_has_atomic = "64", - target_has_atomic = "ptr" -))] -macro_rules! unsafe_impl_transparent_wrapper_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::util::TransparentWrapper for $atomic { - unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); - } - unsafe_impl_transparent_wrapper_for_atomic!($(#[$attr])* $($atomics [$natives],)*); - }; - ($(#[$attr:meta])* $tyvar:ident => $atomic:ty [$native:ty]) => { - // We implement for `$atomic` and set `Inner = $native`. 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. - // - // [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 - $(#[$attr])* - unsafe impl<$tyvar, I: crate::invariant::Invariants> crate::util::TransparentWrapper for $atomic { - unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); - } - }; - (@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::util::Covariant; - - // SAFETY: No safety justification is required for an invariant - // variance. - type AlignmentVariance = crate::util::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::util::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::>() - } - - #[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>() - } - }; -} +use crate::error::AlignmentError; /// Like [`PhantomData`], but [`Send`] and [`Sync`] regardless of whether the /// wrapped `T` is. 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() } }