diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index 42c9ca63bc..c0d0cd746e 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -10,48 +10,42 @@ //! The parameterized invariants of a [`Ptr`][super::Ptr]. //! -//! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) -//! triples implementing the [`Invariants`] trait. +//! A `Ptr` has the following invariants: +//! - [`V: Validity`][validity-trait] encodes the bit validity of `Ptr`'s +//! referent, which is of type [`V::Inner`][validity-inner] +//! - [`I: Invariants`][invariants-trait], where +//! [`I::Aliasing`][invariants-aliasing] and +//! [`I::Alignment`][invariants-alignment] encode the `Ptr`'s aliasing and +//! alignment invariants respectively +//! +//! [validity-trait]: Validity +//! [validity-inner]: Validity::Inner +//! [invariants-trait]: Invariants +//! [invariants-aliasing]: Invariants::Aliasing +//! [invariants-alignment]: Invariants::Alignment + +use core::marker::PhantomData; -/// The invariants of a [`Ptr`][super::Ptr]. +/// The aliasing and alignment invariants of a [`Ptr`][super::Ptr]. pub trait Invariants: Sealed { type Aliasing: Aliasing; type Alignment: Alignment; - type Validity: Validity; /// Invariants identical to `Self` except with a different aliasing /// invariant. - type WithAliasing: Invariants< - Aliasing = A, - Alignment = Self::Alignment, - Validity = Self::Validity, - >; + type WithAliasing: Invariants; /// Invariants identical to `Self` except with a different alignment /// invariant. - type WithAlignment: Invariants< - Aliasing = Self::Aliasing, - Alignment = A, - Validity = Self::Validity, - >; - - /// Invariants identical to `Self` except with a different validity - /// invariant. - type WithValidity: Invariants< - Aliasing = Self::Aliasing, - Alignment = Self::Alignment, - Validity = V, - >; + type WithAlignment: Invariants; } -impl Invariants for (A, AA, V) { +impl Invariants for (A, AA) { type Aliasing = A; type Alignment = AA; - type Validity = V; - type WithAliasing = (AB, AA, V); - type WithAlignment = (A, AB, V); - type WithValidity = (A, AA, VB); + type WithAliasing = (AB, AA); + type WithAlignment = (A, AB); } /// The aliasing invariant of a [`Ptr`][super::Ptr]. @@ -79,7 +73,24 @@ pub trait Alignment: Sealed { } /// The validity invariant of a [`Ptr`][super::Ptr]. +/// +/// A `V: Validity` defines both the referent type of a `Ptr` +/// ([`V::Inner`](Validity::Inner)) and the bit validity of the referent value. +/// Bit validity specifies a set, `S`, of possible values which may exist at the +/// `Ptr`'s referent. Code operating on a `Ptr` may assume that bit validity +/// holds - namely, that it will only observe referent values in `S`. It must +/// also uphold bit validity - namely, it must only write values in `S` to the +/// referent. +/// +/// The specific definition of `S` for a given validity type (i.e., `V: +/// Validity`) is documented on that type. +/// +/// The available validities are [`Uninit`], [`AsInitialized`], [`Initialized`], +/// and [`Valid`]. pub trait Validity: Sealed { + type Inner: ?Sized; + type WithInner: Validity; + #[doc(hidden)] type MappedTo: Validity; } @@ -98,8 +109,16 @@ pub enum Unknown {} impl Alignment for Unknown { type MappedTo = M::FromUnknown; } -impl Validity for Unknown { - type MappedTo = M::FromUnknown; + +/// A validity which permits arbitrary bytes - including uninitialized bytes - +/// at any byte offset. +pub struct Uninit(PhantomData); + +impl Validity for Uninit { + type Inner = T; + type WithInner = Uninit; + + type MappedTo = M::FromUninit; } /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. @@ -138,11 +157,11 @@ impl Alignment for Aligned { /// The byte ranges initialized in `T` are also initialized in the referent. /// -/// Formally: uninitialized bytes may only be present in `Ptr`'s referent -/// where they are guaranteed to be present in `T`. This is a dynamic property: -/// if, at a particular byte offset, a valid enum discriminant is set, the -/// subsequent bytes may only have uninitialized bytes as specificed by the -/// corresponding enum. +/// Formally: uninitialized bytes may only be present in +/// `Ptr>`'s referent where they are guaranteed to be present +/// in `T`. This is a dynamic property: if, at a particular byte offset, a valid +/// enum discriminant is set, the subsequent bytes may only have uninitialized +/// bytes as specificed by the corresponding enum. /// /// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in /// the range `[0, len)`: @@ -162,22 +181,28 @@ impl Alignment for Aligned { /// variant's bit validity (although note that the variant may contain another /// 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 { - type MappedTo = M::FromAsInitialized; +pub struct AsInitialized(PhantomData); +impl Validity for AsInitialized { + type Inner = T; + type WithInner = 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]`. -pub enum Initialized {} -impl Validity for Initialized { - type MappedTo = M::FromInitialized; +pub struct Initialized(PhantomData); +impl Validity for Initialized { + type Inner = T; + type WithInner = Initialized; + type MappedTo = M::FromInitialized; } /// The referent is bit-valid for `T`. -pub enum Valid {} -impl Validity for Valid { - type MappedTo = M::FromValid; +pub struct Valid(PhantomData); +impl Validity for Valid { + type Inner = T; + type WithInner = Valid; + type MappedTo = M::FromValid; } /// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations. @@ -224,16 +249,18 @@ mod sealed { impl Sealed for Unknown {} + impl Sealed for Uninit {} + impl Sealed for Shared {} impl Sealed for Exclusive {} impl Sealed for Aligned {} - impl Sealed for AsInitialized {} - impl Sealed for Initialized {} - impl Sealed for Valid {} + impl Sealed for AsInitialized {} + impl Sealed for Initialized {} + impl Sealed for Valid {} - impl Sealed for (A, AA, V) {} + impl Sealed for (A, AA) {} } pub use mapping::*; @@ -268,10 +295,10 @@ mod mapping { /// Mappings are used by [`Ptr`](crate::Ptr) conversion methods to preserve /// or modify invariants as required by each method's semantics. pub trait ValidityMapping { - type FromUnknown: Validity; - type FromAsInitialized: Validity; - type FromInitialized: Validity; - type FromValid: Validity; + type FromUninit: Validity; + type FromAsInitialized: Validity; + type FromInitialized: Validity; + type FromValid: Validity; } /// The application of the [`AlignmentMapping`] `M` to the [`Alignment`] `A`. @@ -280,7 +307,8 @@ mod mapping { /// The application of the [`ValidityMapping`] `M` to the [`Validity`] `A`. #[allow(type_alias_bounds)] - pub type MappedValidity = V::MappedTo; + pub type MappedValidity = + as Validity>::WithInner; impl AlignmentMapping for ((Unknown, FromUnknown), (Shared, FromAligned)) @@ -290,28 +318,28 @@ mod mapping { } impl< - FromUnknown: Validity, + FromUninit: Validity, FromAsInitialized: Validity, FromInitialized: Validity, FromValid: Validity, > ValidityMapping for ( - (Unknown, FromUnknown), + (Unknown, FromUninit), (AsInitialized, FromAsInitialized), (Initialized, FromInitialized), (Valid, FromValid), ) { - type FromUnknown = FromUnknown; - type FromAsInitialized = FromAsInitialized; - type FromInitialized = FromInitialized; - type FromValid = FromValid; + type FromUninit = FromUninit::WithInner; + type FromAsInitialized = FromAsInitialized::WithInner; + type FromInitialized = FromInitialized::WithInner; + type FromValid = FromValid::WithInner; } impl ValidityMapping for (Initialized, FromInitialized) { - type FromUnknown = Unknown; - type FromAsInitialized = Unknown; - type FromInitialized = FromInitialized; - type FromValid = Unknown; + type FromUninit = Uninit; + type FromAsInitialized = Uninit; + type FromInitialized = FromInitialized::WithInner; + type FromValid = Uninit; } } diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 1b9bd44234..5d38a92b90 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -25,14 +25,14 @@ use crate::Unaligned; /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = - Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>; + Ptr<'a, invariant::Initialized, (Aliasing, Alignment)>; /// A semi-user-facing wrapper type representing a maybe-aligned reference, for /// use in [`TryFromBytes::is_bit_valid`]. /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = - Ptr<'a, T, (Aliasing, Alignment, invariant::Valid)>; + Ptr<'a, invariant::Valid, (Aliasing, Alignment)>; // These methods are defined on the type alias, `MaybeAligned`, so as to bring // them to the forefront of the rendered rustdoc for that type alias. @@ -77,10 +77,10 @@ where } /// Checks if the referent is zeroed. -pub(crate) fn is_zeroed(ptr: Ptr<'_, T, I>) -> bool +pub(crate) fn is_zeroed(ptr: Ptr<'_, invariant::Initialized, I>) -> bool where T: crate::Immutable + crate::KnownLayout, - I: invariant::Invariants, + I: invariant::Invariants, I::Aliasing: invariant::Reference, { ptr.as_bytes::().as_ref().iter().all(|&byte| byte == 0) diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index c134139032..90087aafdf 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -20,49 +20,49 @@ mod def { /// A raw pointer with more restrictions. /// - /// `Ptr` is similar to [`NonNull`], but it is more restrictive in the - /// following ways (note that these requirements only hold of non-zero-sized - /// referents): + /// `Ptr` where [`V: Validity`](Validity) is similar to + /// [`NonNull`], but it is more restrictive in the following ways + /// (note that these requirements only hold of non-zero-sized referents): /// - It must derive from a valid allocation. /// - It must reference a byte range which is contained inside the /// allocation from which it derives. /// - As a consequence, the byte range it references must have a size /// which does not overflow `isize`. /// - /// Depending on how `Ptr` is parameterized, it may have additional + /// Depending on how `Ptr` is parameterized, it may have additional /// invariants: + /// - `ptr` conforms to the validity invariant of [`V`](invariant::Validity) /// - `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). /// - `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// - `ptr` conforms to the validity invariant of - /// [`I::Validity`](invariant::Validity). /// /// `Ptr<'a, T>` is [covariant] in `'a` and `T`. /// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html - pub struct Ptr<'a, T, I> + pub struct Ptr<'a, V, I> where - T: ?Sized, + V: Validity, + V::Inner: 'a, I: Invariants, { /// # Invariants /// - /// 0. `ptr` conforms to the aliasing invariant of + /// 0. `ptr`'s referent conforms to the validity invariant of + /// [`V`](invariant::Validity) + /// 1. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). - /// 1. `ptr` conforms to the alignment invariant of + /// 2. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// 2. `ptr` conforms to the validity invariant of - /// [`I::Validity`](invariant::Validity). // SAFETY: `PtrInner<'a, T>` is covariant over `'a` and `T`. - ptr: PtrInner<'a, T>, - _variance: PhantomData<::Variance<'a, T>>, + ptr: PtrInner<'a, V::Inner>, + _variance: PhantomData<::Variance<'a, V::Inner>>, _invariants: PhantomData, } - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { /// Constructs a `Ptr` from a [`NonNull`]. @@ -82,13 +82,13 @@ mod def { /// address space. /// 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to /// live for at least `'a`. - /// 6. `ptr` conforms to the aliasing invariant of + /// 6. `ptr` conforms to the validity invariant of + /// [`V`](invariant::Validity). + /// 7. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). - /// 7. `ptr` conforms to the alignment invariant of + /// 8. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// 8. `ptr` conforms to the validity invariant of - /// [`I::Validity`](invariant::Validity). - pub(super) const unsafe fn new(ptr: NonNull) -> Ptr<'a, T, I> { + pub(super) const unsafe fn new(ptr: NonNull) -> Ptr<'a, V, I> { // SAFETY: The caller has promised (in 0 - 5) to satisfy all safety // invariants of `PtrInner::new`. let ptr = unsafe { PtrInner::new(ptr) }; @@ -103,13 +103,13 @@ mod def { /// /// The caller promises that: /// - /// 0. `ptr` conforms to the aliasing invariant of + /// 0. `ptr` conforms to the validity invariant of + /// [`V`](invariant::Validity). + /// 1. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). - /// 1. `ptr` conforms to the alignment invariant of + /// 2. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). - /// 2. `ptr` conforms to the validity invariant of - /// [`I::Validity`](invariant::Validity). - pub(super) const unsafe fn from_inner(ptr: PtrInner<'a, T>) -> Ptr<'a, T, I> { + pub(super) const unsafe fn from_inner(ptr: PtrInner<'a, V::Inner>) -> Ptr<'a, V, I> { // SAFETY: The caller has promised to satisfy all safety invariants // of `Ptr`. Self { ptr, _variance: PhantomData, _invariants: PhantomData } @@ -120,7 +120,7 @@ mod def { /// Note that this method does not consume `self`. The caller should /// watch out for `unsafe` code which uses the returned value in a way /// that violates the safety invariants of `self`. - pub(crate) const fn as_inner(&self) -> PtrInner<'a, T> { + pub(crate) const fn as_inner(&self) -> PtrInner<'a, V::Inner> { self.ptr } } @@ -136,9 +136,9 @@ mod _external { /// SAFETY: Shared pointers are safely `Copy`. `Ptr`'s other invariants /// (besides aliasing) are unaffected by the number of references that exist /// to `Ptr`'s referent. - impl<'a, T, I> Copy for Ptr<'a, T, I> + impl Copy for Ptr<'_, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { } @@ -146,9 +146,9 @@ mod _external { /// SAFETY: Shared pointers are safely `Clone`. `Ptr`'s other invariants /// (besides aliasing) are unaffected by the number of references that exist /// to `Ptr`'s referent. - impl<'a, T, I> Clone for Ptr<'a, T, I> + impl Clone for Ptr<'_, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { #[inline] @@ -157,9 +157,9 @@ mod _external { } } - impl<'a, T, I> Debug for Ptr<'a, T, I> + impl Debug for Ptr<'_, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { #[inline] @@ -175,51 +175,44 @@ mod _conversions { use crate::util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance}; /// `&'a T` → `Ptr<'a, T>` - impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)> - where - T: 'a + ?Sized, - { + impl<'a, T: ?Sized> Ptr<'a, Valid, (Shared, Aligned)> { /// Constructs a `Ptr` from a shared reference. #[doc(hidden)] #[inline] pub fn from_ref(ptr: &'a T) -> Self { let inner = PtrInner::from_ref(ptr); // SAFETY: - // 0. `ptr`, by invariant on `&'a T`, conforms to the aliasing + // 0. `ptr`, by invariant on `&'a T`, conforms to the validity + // invariant of `Valid`. + // 1. `ptr`, by invariant on `&'a T`, conforms to the aliasing // invariant of `Shared`. - // 1. `ptr`, by invariant on `&'a T`, conforms to the alignment + // 2. `ptr`, by invariant on `&'a T`, conforms to the alignment // invariant of `Aligned`. - // 2. `ptr`, by invariant on `&'a T`, conforms to the validity - // invariant of `Valid`. unsafe { Self::from_inner(inner) } } } /// `&'a mut T` → `Ptr<'a, T>` - impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)> - where - T: 'a + ?Sized, - { + impl<'a, T: ?Sized> Ptr<'a, Valid, (Exclusive, Aligned)> { /// Constructs a `Ptr` from an exclusive reference. #[inline] pub(crate) fn from_mut(ptr: &'a mut T) -> Self { let inner = PtrInner::from_mut(ptr); // SAFETY: - // 0. `ptr`, by invariant on `&'a mut T`, conforms to the aliasing + // 0. `ptr`, by invariant on `&'a mut T`, conforms to the validity + // invariant of `Valid`. + // 1. `ptr`, by invariant on `&'a mut T`, conforms to the aliasing // invariant of `Exclusive`. - // 1. `ptr`, by invariant on `&'a mut T`, conforms to the alignment + // 2. `ptr`, by invariant on `&'a mut T`, conforms to the alignment // invariant of `Aligned`. - // 2. `ptr`, by invariant on `&'a mut T`, conforms to the validity - // invariant of `Valid`. unsafe { Self::from_inner(inner) } } } /// `Ptr<'a, T>` → `&'a T` - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, T: ?Sized, I> Ptr<'a, Valid, I> where - T: 'a + ?Sized, - I: Invariants, + I: Invariants, I::Aliasing: Reference, { /// Converts `self` to a shared reference. @@ -247,8 +240,8 @@ mod _conversions { // This is ensured by contract on all `PtrInner`s. // // 3. The pointer must point to an initialized instance of `T`. This - // is ensured by-contract on `Ptr`, because the `I::Validity` is - // `Valid`. + // is ensured by-contract on `Ptr`, because the validity is + // `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by // contract on `Ptr`, because `I::Aliasing: Reference`. Either it @@ -262,9 +255,9 @@ mod _conversions { } } - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, I::Aliasing: Reference, { @@ -276,20 +269,20 @@ mod _conversions { #[doc(hidden)] #[inline] #[allow(clippy::needless_lifetimes)] // Allows us to name the lifetime in the safety comment below. - pub fn reborrow<'b>(&'b mut self) -> Ptr<'b, T, I> + pub fn reborrow<'b>(&'b mut self) -> Ptr<'b, V, I> where 'a: 'b, { // SAFETY: The following all hold by invariant on `self`, and thus // hold of `ptr = self.as_inner()`: - // 0. SEE BELOW. - // 1. `ptr` conforms to the alignment invariant of - // [`I::Alignment`](invariant::Alignment). - // 2. `ptr` conforms to the validity invariant of - // [`I::Validity`](invariant::Validity). + // 0. `ptr` conforms to the validity invariant of + // [`V`](invariant::Validity). + // 1. SEE BELOW. + // 2. `ptr` conforms to the alignment invariant of + // [`I::Alignment`](invariant::Alignment). // - // For aliasing (6 above), since `I::Aliasing: Reference`, - // there are two cases for `I::Aliasing`: + // For aliasing, since `I::Aliasing: Reference`, there are two cases + // for `I::Aliasing`: // - For `invariant::Shared`: `'a` outlives `'b`, and so the // returned `Ptr` does not permit accessing the referent any // longer than is possible via `self`. For shared aliasing, it is @@ -310,10 +303,7 @@ mod _conversions { } /// `Ptr<'a, T>` → `&'a mut T` - impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)> - where - T: 'a + ?Sized, - { + impl<'a, T: ?Sized> Ptr<'a, Valid, (Exclusive, Aligned)> { /// Converts `self` to a mutable reference. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_mut(self) -> &'a mut T { @@ -335,8 +325,8 @@ mod _conversions { // This is ensured by contract on all `PtrInner`s. // // 3. The pointer must point to an initialized instance of `T`. This - // is ensured by-contract on `Ptr`, because the validity - // invariant is `Valid`. + // is ensured by-contract on `Ptr`, because the validity is + // `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by // contract on `Ptr`, because the `ALIASING_INVARIANT` is @@ -349,9 +339,10 @@ mod _conversions { } /// `Ptr<'a, T = Wrapper>` → `Ptr<'a, U>` - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + TransparentWrapper + ?Sized, + V: 'a + Validity, + V::Inner: TransparentWrapper, I: Invariants, { /// Converts `self` to a transparent wrapper type into a `Ptr` to the @@ -360,11 +351,15 @@ mod _conversions { self, ) -> Ptr< 'a, - T::Inner, + <::ValidityVariance as ValidityVariance>::Applied< + V, + ::Inner, + >, ( I::Aliasing, - >::Applied, - >::Applied, + <::AlignmentVariance as AlignmentVariance>::Applied< + I::Alignment, + >, ), > { // SAFETY: @@ -377,31 +372,38 @@ 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)) }; + let c = unsafe { self.cast_unsized_unchecked(V::Inner::cast_into_inner) }; // 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>() + c.assume_alignment::<<::AlignmentVariance as AlignmentVariance>::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. + // satisfies the validity invariant `V`, `c` (of type + // `V::Inner::Inner`) satisfies the given "applied" validity + // invariant. let c = unsafe { - c.assume_validity::<>::Applied>() + c.assume_validity::<<::ValidityVariance as ValidityVariance>::Applied::Inner>>() }; - c + c.unify_validity() } } /// `Ptr<'a, T, (_, _, _)>` → `Ptr<'a, Unalign, (_, Aligned, _)>` - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where + V: Validity, I: Invariants, { /// Converts a `Ptr` an unaligned `T` into a `Ptr` to an aligned /// `Unalign`. - pub(crate) fn into_unalign(self) -> Ptr<'a, crate::Unalign, I::WithAlignment> { + pub(crate) fn into_unalign( + self, + ) -> Ptr<'a, V::WithInner>, I::WithAlignment> + where + V::Inner: Sized, + { // SAFETY: // - This cast preserves provenance. // - This cast preserves address. `Unalign` promises to have the @@ -411,11 +413,11 @@ mod _conversions { // `UnsafeCell`s at the same locations as `p`. let ptr = unsafe { #[allow(clippy::as_conversions)] - self.cast_unsized_unchecked(|p: *mut T| p as *mut crate::Unalign) + self.cast_unsized_unchecked(|p: *mut V::Inner| p as *mut crate::Unalign) }; // SAFETY: `Unalign` promises to have the same bit validity as // `T`. - let ptr = unsafe { ptr.assume_validity::() }; + let ptr = unsafe { ptr.assume_validity::() }; // SAFETY: `Unalign` promises to have alignment 1, and so it is // trivially aligned. let ptr = unsafe { ptr.assume_alignment::() }; @@ -429,9 +431,9 @@ mod _transitions { use super::*; use crate::{AlignmentError, TryFromBytes, ValidityError}; - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { /// Returns a `Ptr` with [`Exclusive`] aliasing if `self` already has @@ -444,7 +446,7 @@ mod _transitions { #[inline] pub(crate) fn into_exclusive_or_post_monomorphization_error( self, - ) -> Ptr<'a, T, I::WithAliasing> { + ) -> Ptr<'a, V, I::WithAliasing> { // NOTE(https://github.com/rust-lang/rust/issues/131625): We do this // rather than just having `Aliasing::IS_EXCLUSIVE` have the panic // behavior because doing it that way causes rustdoc to fail while @@ -471,12 +473,15 @@ mod _transitions { unsafe { self.assume_exclusive() } } - /// Assumes that `self` satisfies the invariants `H`. + /// Assumes that `self` satisfies the invariants `W` and `H`. /// /// # Safety /// - /// The caller promises that `self` satisfies the invariants `H`. - const unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { + /// The caller promises that `self` satisfies the invariants `W` and + /// `H`. + const unsafe fn assume_invariants, H: Invariants>( + self, + ) -> Ptr<'a, W, 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`. @@ -485,14 +490,27 @@ mod _transitions { /// Helps the type system unify two distinct invariant types which are /// actually the same. - pub(crate) const fn unify_invariants< - H: Invariants, - >( - self, - ) -> Ptr<'a, T, H> { + pub(crate) const fn unify_invariants(self) -> Ptr<'a, V, H> + where + H: Invariants, + { // SAFETY: The associated type bounds on `H` ensure that the // invariants are unchanged. - unsafe { self.assume_invariants::() } + unsafe { self.assume_invariants::() } + } + + /// Helps the type system unify two distinct validity invariants which + /// are actually the same. + pub(crate) const fn unify_validity(self) -> Ptr<'a, W, I> + where + W: Validity = V>, + { + // SAFETY: The associated type bounds on `W` ensure that the + // validity invariant is unchanged. In particular, `Inner = + // V::Inner` ensures that the target types are the same, and + // `WithInner = V` ensures that `W` and `V` are the same + // type of validity (e.g., both `Initialized`). + unsafe { self.assume_invariants::() } } /// Assumes that `self` satisfies the aliasing requirement of `A`. @@ -504,7 +522,7 @@ mod _transitions { #[inline] pub(crate) const unsafe fn assume_aliasing( self, - ) -> Ptr<'a, T, I::WithAliasing> { + ) -> Ptr<'a, V, I::WithAliasing> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `A`. unsafe { self.assume_invariants() } @@ -521,7 +539,7 @@ mod _transitions { #[inline] pub(crate) const unsafe fn assume_exclusive( self, - ) -> Ptr<'a, T, I::WithAliasing> { + ) -> Ptr<'a, V, I::WithAliasing> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `Exclusive`. unsafe { self.assume_aliasing::() } @@ -537,7 +555,7 @@ mod _transitions { #[inline] pub(crate) const unsafe fn assume_alignment( self, - ) -> Ptr<'a, T, I::WithAlignment> { + ) -> Ptr<'a, V, I::WithAlignment> { // SAFETY: The caller promises that `self`'s referent is // well-aligned for `T` if required by `A` . unsafe { self.assume_invariants() } @@ -547,12 +565,12 @@ mod _transitions { /// on success. pub(crate) fn bikeshed_try_into_aligned( self, - ) -> Result>, AlignmentError> + ) -> Result>, AlignmentError> where - T: Sized, + V::Inner: Sized, { if let Err(err) = - crate::util::validate_aligned_to::<_, T>(self.as_inner().as_non_null()) + crate::util::validate_aligned_to::<_, V::Inner>(self.as_inner().as_non_null()) { return Err(err.with_src(self)); } @@ -565,9 +583,9 @@ mod _transitions { #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub(crate) const fn bikeshed_recall_aligned(self) -> Ptr<'a, T, I::WithAlignment> + pub(crate) const fn bikeshed_recall_aligned(self) -> Ptr<'a, V, I::WithAlignment> where - T: crate::Unaligned, + V::Inner: crate::Unaligned, { // SAFETY: The bound `T: Unaligned` ensures that `T` has no // non-trivial alignment requirement. @@ -575,18 +593,20 @@ mod _transitions { } /// Assumes that `self`'s referent conforms to the validity requirement - /// of `V`. + /// of `W`. /// /// # Safety /// /// The caller promises that `self`'s referent conforms to the validity - /// requirement of `V`. + /// requirement of `W`. #[doc(hidden)] #[must_use] #[inline] - pub const unsafe fn assume_validity(self) -> Ptr<'a, T, I::WithValidity> { + pub const unsafe fn assume_validity( + self, + ) -> Ptr<'a, W::WithInner, I> { // SAFETY: The caller promises that `self`'s referent conforms to - // the validity requirement of `V`. + // the validity requirement of `W`. unsafe { self.assume_invariants() } } @@ -599,10 +619,10 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub const unsafe fn assume_initialized(self) -> Ptr<'a, T, I::WithValidity> { + pub const unsafe fn assume_initialized(self) -> Ptr<'a, Initialized, I> { // SAFETY: The caller has promised to uphold the safety // preconditions. - unsafe { self.assume_validity::() } + unsafe { self.assume_validity::>() } } /// A shorthand for `self.assume_validity()`. @@ -614,27 +634,40 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub const unsafe fn assume_valid(self) -> Ptr<'a, T, I::WithValidity> { + pub const unsafe fn assume_valid(self) -> Ptr<'a, Valid, I> { // SAFETY: The caller has promised to uphold the safety // preconditions. - unsafe { self.assume_validity::() } + unsafe { self.assume_validity::>() } } + /// Forgets that `self`'s referent is validly-aligned for `T`. + #[doc(hidden)] + #[must_use] + #[inline] + pub const fn forget_aligned(self) -> Ptr<'a, V, I::WithAlignment> { + // SAFETY: `Unknown` is less restrictive than `Aligned`. + unsafe { self.assume_invariants() } + } + } + + impl<'a, T, I> Ptr<'a, Initialized, I> + where + T: ?Sized, + I: Invariants, + { /// Recalls that `self`'s referent is bit-valid for `T`. #[doc(hidden)] #[must_use] #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub const fn bikeshed_recall_valid(self) -> Ptr<'a, T, I::WithValidity> + pub const fn bikeshed_recall_valid(self) -> Ptr<'a, Valid, I> where T: crate::FromBytes, - I: Invariants, { // SAFETY: The bound `T: FromBytes` ensures that any initialized - // sequence of bytes is bit-valid for `T`. `I: Invariants` ensures that all of the referent bytes - // are initialized. + // sequence of bytes is bit-valid for `T`. `V = Initialized` + // ensures that all of the referent bytes are initialized. unsafe { self.assume_valid() } } @@ -653,11 +686,10 @@ mod _transitions { #[inline] pub(crate) fn try_into_valid( mut self, - ) -> Result>, ValidityError> + ) -> Result, I>, ValidityError> where T: TryFromBytes + Read, I::Aliasing: Reference, - I: Invariants, { // 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 @@ -670,15 +702,6 @@ mod _transitions { Err(ValidityError::new(self)) } } - - /// Forgets that `self`'s referent is validly-aligned for `T`. - #[doc(hidden)] - #[must_use] - #[inline] - pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment> { - // SAFETY: `Unknown` is less restrictive than `Aligned`. - unsafe { self.assume_invariants() } - } } } @@ -687,9 +710,9 @@ mod _casts { use super::*; use crate::{CastError, SizeError}; - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, V, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity, I: Invariants, { /// Casts to a different (unsized) target type without checking interior @@ -709,14 +732,11 @@ mod _casts { /// at ranges identical to those at which `UnsafeCell`s exist in `*p` #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized_unchecked *mut U>( + pub unsafe fn cast_unsized_unchecked *mut T>( self, cast: F, - ) -> Ptr< - 'a, - U, - (I::Aliasing, Unknown, MappedValidity), - > { + ) -> Ptr<'a, MappedValidity, (I::Aliasing, Unknown)> + { let ptr = cast(self.as_inner().as_non_null().as_ptr()); // SAFETY: Caller promises that `cast` returns a pointer whose @@ -747,7 +767,14 @@ mod _casts { // space. // 5. By invariant on `self`, if `self`'s referent is not zero // sized, then `A` is guaranteed to live for at least `'a`. - // 6. `ptr` conforms to the aliasing invariant of `I::Aliasing`: + // 6. If `V = Unknown`, `AsInitialized`, or `Valid`, the output + // validity invariant is `Unknown`. `ptr` trivially conforms to + // this invariant. If `V = Initialized`, the output validity + // invariant is `Initialized`. Regardless of what subset of + // `self`'s referent is referred to by `ptr`, if all of `self`'s + // referent is initialized, then the same holds of `ptr`'s + // referent. + // 7. `ptr` conforms to the aliasing invariant of `I::Aliasing`: // - `Exclusive`: `self` is the only `Ptr` or reference which is // permitted to read or modify the referent for the lifetime // `'a`. Since we consume `self` by value, the returned pointer @@ -771,15 +798,8 @@ mod _casts { // invariant on `self`, no other code assumes that this will // not happen. // - `Inaccessible`: There are no restrictions we need to uphold. - // 7. `ptr`, trivially, conforms to the alignment invariant of + // 8. `ptr`, trivially, conforms to the alignment invariant of // `Unknown`. - // 8. If `I::Validity = Unknown`, `AsInitialized`, or `Valid`, the - // output validity invariant is `Unknown`. `ptr` trivially - // conforms to this invariant. If `I::Validity = Initialized`, - // the output validity invariant is `Initialized`. Regardless of - // what subset of `self`'s referent is referred to by `ptr`, if - // all of `self`'s referent is initialized, then the same holds - // of `ptr`'s referent. unsafe { Ptr::new(ptr) } } @@ -793,38 +813,34 @@ mod _casts { /// - `u` has the same provenance as `p` #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized( + pub unsafe fn cast_unsized( self, cast: F, - ) -> Ptr< - 'a, - U, - (I::Aliasing, Unknown, MappedValidity), - > + ) -> Ptr<'a, MappedValidity, (I::Aliasing, Unknown)> where - T: Read, - U: 'a + ?Sized + Read, - F: FnOnce(*mut T) -> *mut U, + V::Inner: Read, + T: 'a + ?Sized + Read, + F: FnOnce(*mut V::Inner) -> *mut T, { - // SAFETY: Because `T` and `U` both implement `Read`, - // either: + // SAFETY: Because `T::Inner` and `W` both implement + // `Read`, either: // - `I::Aliasing` is `Exclusive` - // - `T` and `U` are both `Immutable`, in which case they trivially - // contain `UnsafeCell`s at identical locations + // - `V::Inner` and `W` are both `Immutable`, in which case they + // trivially contain `UnsafeCell`s at identical locations // // The caller promises all other safety preconditions. unsafe { self.cast_unsized_unchecked(cast) } } } - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, T, I> Ptr<'a, Initialized, I> where - T: 'a + KnownLayout + ?Sized, - I: Invariants, + T: ?Sized + KnownLayout, + I: Invariants, { /// Casts this pointer-to-initialized into a pointer-to-bytes. #[allow(clippy::wrong_self_convention)] - pub(crate) fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> + pub(crate) fn as_bytes(self) -> Ptr<'a, Valid<[u8]>, (I::Aliasing, Aligned)> where T: Read, I::Aliasing: Reference, @@ -844,7 +860,7 @@ mod _casts { // pointer's address, and `bytes` is the length of `p`, so the // returned pointer addresses the same bytes as `p` // - `slice_from_raw_parts_mut` and `.cast` both preserve provenance - let ptr: Ptr<'a, [u8], _> = unsafe { + let ptr: Ptr<'a, Initialized<[u8]>, _> = unsafe { self.cast_unsized(|p: *mut T| { #[allow(clippy::as_conversions)] core::ptr::slice_from_raw_parts_mut(p.cast::(), bytes) @@ -855,24 +871,24 @@ mod _casts { } } - impl<'a, T, I, const N: usize> Ptr<'a, [T; N], I> + impl<'a, V, T, I, const N: usize> Ptr<'a, V, I> where - T: 'a, + V: Validity, I: Invariants, { /// Casts this pointer-to-array into a slice. #[allow(clippy::wrong_self_convention)] - pub(crate) fn as_slice(self) -> Ptr<'a, [T], I> { + pub(crate) fn as_slice(self) -> Ptr<'a, V::WithInner<[T]>, I> { let slice = self.as_inner().as_slice(); // SAFETY: Note that, by post-condition on `PtrInner::as_slice`, // `slice` refers to the same byte range as `self.as_inner()`. // - // 6. Thus, `slice` conforms to the aliasing invariant of + // 6. By the above lemma, `slice` conforms to the validity invariant + // of `V` because `self` does. + // 7. Thus, `slice` conforms to the aliasing invariant of // `I::Aliasing` because `self` does. - // 7. By the above lemma, `slice` conforms to the alignment + // 8. By the above lemma, `slice` conforms to the alignment // invariant of `I::Alignment` because `self` does. - // 8. By the above lemma, `slice` conforms to the validity invariant - // of `I::Validity` because `self` does. unsafe { Ptr::from_inner(slice) } } } @@ -880,20 +896,21 @@ mod _casts { /// For caller convenience, these methods are generic over alignment /// invariant. In practice, the referent is always well-aligned, because the /// alignment of `[u8]` is 1. - impl<'a, I> Ptr<'a, [u8], I> + impl<'a, I> Ptr<'a, Valid<[u8]>, I> where - I: Invariants, + I: Invariants, { - /// Attempts to cast `self` to a `U` using the given cast type. + /// Attempts to cast `self` to a `Ptr>` using the given + /// cast type. /// - /// If `U` is a slice DST and pointer metadata (`meta`) is provided, + /// If `T` is a slice DST and pointer metadata (`meta`) is provided, /// then the cast will only succeed if it would produce an object with /// the given metadata. /// - /// Returns `None` if the resulting `U` would be invalidly-aligned, if - /// no `U` can fit in `self`, or if the provided pointer metadata - /// describes an invalid instance of `U`. On success, returns a pointer - /// to the largest-possible `U` which fits in `self`. + /// Returns `None` if the resulting `T` would be invalidly-aligned, if + /// no `T` can fit in `self`, or if the provided pointer metadata + /// describes an invalid instance of `T`. On success, returns a pointer + /// to the largest-possible `T` which fits in `self`. /// /// # Safety /// @@ -907,17 +924,17 @@ mod _casts { /// - If this is a suffix cast, `remainder` has the same address as /// `self`. #[inline(always)] - pub(crate) fn try_cast_into( + pub(crate) fn try_cast_into( self, cast_type: CastType, - meta: Option, + meta: Option, ) -> Result< - (Ptr<'a, U, (I::Aliasing, Aligned, Initialized)>, Ptr<'a, [u8], I>), - CastError, + (Ptr<'a, Initialized, (I::Aliasing, Aligned)>, Ptr<'a, Valid<[u8]>, I>), + CastError, > where I::Aliasing: Reference, - U: 'a + ?Sized + KnownLayout + Read, + T: KnownLayout + Read + ?Sized, { let (inner, remainder) = self.as_inner().try_cast_into(cast_type, meta).map_err(|err| { @@ -930,41 +947,41 @@ mod _casts { })?; // SAFETY: - // 0. Since `U: Read`, either: + // 0. By trait bound, `self` - and thus `target` - is a bit-valid + // `[u8]`. All bit-valid `[u8]`s have all of their bytes + // initialized, so `ptr` conforms to the validity invariant of + // `Initialized`. + // 1. Since `W: Read`, either: // - `I::Aliasing` is `Exclusive`, in which case both `src` and // `ptr` conform to `Exclusive` - // - `I::Aliasing` is `Shared` or `Inaccessible` and `U` is + // - `I::Aliasing` is `Shared` or `Inaccessible` and `W` is // `Immutable` (we already know that `[u8]: Immutable`). In - // this case, neither `U` nor `[u8]` permit mutation, and so + // this case, neither `W` nor `[u8]` permit mutation, and so // `Shared` aliasing is satisfied. `Inaccessible` is trivially // satisfied since it imposes no requirements. - // 1. `ptr` conforms to the alignment invariant of `Aligned` because + // 2. `ptr` conforms to the alignment invariant of `Aligned` because // it is derived from `try_cast_into`, which promises that the - // object described by `target` is validly aligned for `U`. - // 2. By trait bound, `self` - and thus `target` - is a bit-valid - // `[u8]`. All bit-valid `[u8]`s have all of their bytes - // initialized, so `ptr` conforms to the validity invariant of - // `Initialized`. + // object described by `target` is validly aligned for `W`. let res = unsafe { Ptr::from_inner(inner) }; // SAFETY: - // 0. `self` and `remainder` both have the type `[u8]`. Thus, they - // have `UnsafeCell`s at the same locations. Type casting does - // not affect aliasing. - // 1. `[u8]` has no alignment requirement. - // 2. `self` has validity `Valid` and has type `[u8]`. Since + // 0. `self` has validity `Valid` and has type `[u8]`. Since // `remainder` references a subset of `self`'s referent, it is // also bit-valid. + // 1. `self` and `remainder` both have the type `[u8]`. Thus, they + // have `UnsafeCell`s at the same locations. Type casting does + // not affect aliasing. + // 2. `[u8]` has no alignment requirement. let remainder = unsafe { Ptr::from_inner(remainder) }; Ok((res, remainder)) } - /// Attempts to cast `self` into a `U`, failing if all of the bytes of - /// `self` cannot be treated as a `U`. + /// Attempts to cast `self` into a `Ptr>`, failing if all + /// of the bytes of `self`'s referent cannot be treated as a `T`. /// /// In particular, this method fails if `self` is not validly-aligned - /// for `U` or if `self`'s size is not a valid size for `U`. + /// for `T` or if `self`'s size is not a valid size for `T`. /// /// # Safety /// @@ -972,13 +989,13 @@ mod _casts { /// references the same byte range as `self`. #[allow(unused)] #[inline(always)] - pub(crate) fn try_cast_into_no_leftover( + pub(crate) fn try_cast_into_no_leftover( self, - meta: Option, - ) -> Result, CastError> + meta: Option, + ) -> Result, (I::Aliasing, Aligned)>, CastError> where I::Aliasing: Reference, - U: 'a + ?Sized + KnownLayout + Read, + T: ?Sized + KnownLayout + Read, { match self.try_cast_into(CastType::Prefix, meta) { Ok((slf, remainder)) => { @@ -998,7 +1015,7 @@ mod _casts { // `slf`. let slf = unsafe { slf.assume_alignment::() }; let slf = slf.unify_invariants(); - Err(CastError::Size(SizeError::<_, U>::new(slf))) + Err(CastError::Size(SizeError::<_, T>::new(slf))) } } Err(err) => Err(err), @@ -1006,9 +1023,9 @@ mod _casts { } } - impl<'a, T, I> Ptr<'a, core::cell::UnsafeCell, I> + impl<'a, V, T: ?Sized, I> Ptr<'a, V, I> where - T: 'a + ?Sized, + V: Validity>, I: Invariants, { /// Converts this `Ptr` into a pointer to the underlying data. @@ -1021,7 +1038,7 @@ mod _casts { /// [`UnsafeCell::get_mut`]: core::cell::UnsafeCell::get_mut #[must_use] #[inline(always)] - pub fn get_mut(self) -> Ptr<'a, T, I> { + pub fn get_mut(self) -> Ptr<'a, V::WithInner, I> { // SAFETY: The closure uses an `as` cast, which preserves address // range and provenance. #[allow(clippy::as_conversions)] @@ -1050,7 +1067,7 @@ mod _casts { // `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`. - let ptr = unsafe { ptr.assume_validity::() }; + let ptr = unsafe { ptr.assume_validity::() }; ptr.unify_invariants() } } @@ -1060,10 +1077,9 @@ mod _casts { mod _project { use super::*; - impl<'a, T, I> Ptr<'a, T, I> + impl<'a, T: ?Sized, I> Ptr<'a, Initialized, I> where - T: 'a + ?Sized, - I: Invariants, + I: Invariants, { /// Projects a field from `self`. /// @@ -1073,10 +1089,10 @@ mod _project { /// `cast_unsized_unchecked`. #[doc(hidden)] #[inline] - pub unsafe fn project( + pub unsafe fn project( self, - projector: impl FnOnce(*mut T) -> *mut U, - ) -> Ptr<'a, U, (I::Aliasing, Unknown, Initialized)> { + projector: impl FnOnce(*mut T) -> *mut W, + ) -> Ptr<'a, Initialized, (I::Aliasing, Unknown)> { // TODO(#1122): If `cast_unsized` were able to reason that, when // casting from an `Initialized` pointer, the result is another // `Initialized` pointer, we could remove this method entirely. @@ -1087,9 +1103,9 @@ mod _project { } } - impl<'a, T, I> Ptr<'a, [T], I> + impl Ptr<'_, V, I> where - T: 'a, + V: Validity, I: Invariants, { /// The number of slice elements in the object referenced by `self`. @@ -1102,23 +1118,23 @@ mod _project { } } - impl<'a, T, I> Ptr<'a, [T], I> + impl<'a, V, T, I> Ptr<'a, V, I> where - T: 'a, + V: Validity, I: Invariants, I::Aliasing: Reference, { /// Iteratively projects the elements `Ptr` from `Ptr<[T]>`. - pub(crate) fn iter(&self) -> impl Iterator> { + pub(crate) fn iter(&self) -> impl Iterator, I>> { // SAFETY: - // 0. `elem` conforms to the aliasing invariant of `I::Aliasing` + // 0. `elem`, conditionally, conforms to the validity invariant of + // `V`. If `elem` is projected from data valid for `[T]`, `elem` + // will be valid for `T`. + // 1. `elem` conforms to the aliasing invariant of `I::Aliasing` // because projection does not impact the aliasing invariant. - // 1. `elem`, conditionally, conforms to the validity invariant of + // 2. `elem`, conditionally, conforms to the validity invariant of // `I::Alignment`. If `elem` is projected from data well-aligned // for `[T]`, `elem` will be valid for `T`. - // 2. `elem`, conditionally, conforms to the validity invariant of - // `I::Validity`. If `elem` is projected from data valid for - // `[T]`, `elem` will be valid for `T`. self.as_inner().iter().map(|elem| unsafe { Ptr::from_inner(elem) }) } } @@ -1176,7 +1192,7 @@ mod tests { // SAFETY: The bytes in `slf` must be initialized. unsafe fn validate_and_get_len( - slf: Ptr<'_, T, (Shared, Aligned, Initialized)>, + slf: Ptr<'_, Initialized, (Shared, Aligned)>, ) -> usize { let t = slf.bikeshed_recall_valid().as_ref(); diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 1ee8a36d4e..4a7af46962 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}, + pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants, Valid}, FromBytes, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, }; @@ -532,17 +532,17 @@ pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( #[doc(hidden)] #[inline] fn try_cast_or_pme( - src: Ptr<'_, Src, I>, + src: Ptr<'_, Valid, I>, ) -> Result< - Ptr<'_, Dst, (I::Aliasing, invariant::Unknown, invariant::Valid)>, - ValidityError, Dst>, + Ptr<'_, Valid, (I::Aliasing, invariant::Unknown)>, + ValidityError, I>, Dst>, > where // TODO(#2226): There should be a `Src: FromBytes` bound here, but doing so // requires deeper surgery. Src: IntoBytes + invariant::Read, Dst: TryFromBytes + invariant::Read, - I: Invariants, + I: Invariants, I::Aliasing: invariant::Reference, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); @@ -576,7 +576,7 @@ where // SAFETY: `ptr` is `src`, and has the same alignment invariant. let ptr = unsafe { ptr.assume_alignment::() }; // SAFETY: `ptr` is `src` and has the same validity invariant. - let ptr = unsafe { ptr.assume_validity::() }; + let ptr = unsafe { ptr.assume_validity::() }; Err(ValidityError::new(ptr.unify_invariants())) } } diff --git a/src/util/macros.rs b/src/util/macros.rs index 67840e2875..ef12e7b1ab 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -266,13 +266,13 @@ macro_rules! impl_for_transparent_wrapper { #[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::util::*; impl_for_transparent_wrapper!(@define_is_transparent_wrapper $trait); #[cfg_attr(coverage_nightly, coverage(off))] - const fn f() { - is_transparent_wrapper::(); + const fn f<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?>() { + is_transparent_wrapper::<$ty>(); } } @@ -343,7 +343,7 @@ macro_rules! impl_for_transparent_wrapper { }; (@define_is_transparent_wrapper $trait:ident, $variance:ident) => { #[cfg_attr(coverage_nightly, coverage(off))] - const fn is_transparent_wrapper + ?Sized>() + const fn is_transparent_wrapper + ?Sized>() where W::Inner: $trait, {} diff --git a/src/util/mod.rs b/src/util/mod.rs index ad59881f96..6cf924d9db 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -22,7 +22,7 @@ use core::{ use crate::{ error::AlignmentError, - pointer::invariant::{self, Invariants}, + pointer::invariant::{self, Validity}, Unalign, }; @@ -46,12 +46,12 @@ use crate::{ /// [`T::AlignmentVariance`]: TransparentWrapper::AlignmentVariance /// [`T::ValidityVariance`]: TransparentWrapper::ValidityVariance #[doc(hidden)] -pub unsafe trait TransparentWrapper { +pub unsafe trait TransparentWrapper { type Inner: ?Sized; type UnsafeCellVariance; - type AlignmentVariance: AlignmentVariance; - type ValidityVariance: ValidityVariance; + type AlignmentVariance: AlignmentVariance; + type ValidityVariance: ValidityVariance; /// Casts a wrapper pointer to an inner pointer. /// @@ -72,38 +72,38 @@ pub unsafe trait TransparentWrapper { #[allow(unreachable_pub)] #[doc(hidden)] -pub trait AlignmentVariance { - type Applied: invariant::Alignment; +pub trait AlignmentVariance { + type Applied: invariant::Alignment; } #[allow(unreachable_pub)] #[doc(hidden)] -pub trait ValidityVariance { - type Applied: invariant::Validity; +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 AlignmentVariance for Covariant { + type Applied = A; } -impl ValidityVariance for Covariant { - type Applied = I; +impl ValidityVariance for Covariant { + type Applied = V::WithInner; } #[doc(hidden)] #[allow(missing_copy_implementations, missing_debug_implementations)] pub enum Invariant {} -impl AlignmentVariance for Invariant { - type Applied = invariant::Unknown; +impl AlignmentVariance for Invariant { + type Applied = invariant::Unknown; } -impl ValidityVariance for Invariant { - type Applied = invariant::Unknown; +impl ValidityVariance for Invariant { + type Applied = invariant::Uninit; } // SAFETY: @@ -114,7 +114,7 @@ impl ValidityVariance for Invariant { // // `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as // `T` -unsafe impl TransparentWrapper for MaybeUninit { +unsafe impl TransparentWrapper for MaybeUninit { type Inner = T; // SAFETY: `MaybeUninit` has `UnsafeCell`s covering the same byte ranges @@ -170,7 +170,7 @@ unsafe impl TransparentWrapper for MaybeUninit { // // `ManuallyDrop` is guaranteed to have the same layout and bit validity as // `T` -unsafe impl TransparentWrapper for ManuallyDrop { +unsafe impl TransparentWrapper for ManuallyDrop { type Inner = T; // SAFETY: Per [1], `ManuallyDrop` has `UnsafeCell`s covering the same @@ -224,7 +224,7 @@ unsafe impl TransparentWrapper for ManuallyDrop // [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 { +unsafe impl TransparentWrapper for Wrapping { type Inner = T; // SAFETY: Per [1], `Wrapping` has the same layout as `T`. Since its @@ -287,7 +287,7 @@ unsafe impl TransparentWrapper for Wrapping { // // `UnsafeCell` has the same in-memory representation as its inner type // `T`. -unsafe impl TransparentWrapper for UnsafeCell { +unsafe impl TransparentWrapper for UnsafeCell { type Inner = T; // SAFETY: Since we set this to `Invariant`, we make no safety claims. @@ -333,7 +333,7 @@ unsafe impl TransparentWrapper for UnsafeCell { // SAFETY: `Unalign` promises to have the same size as `T`. // // See inline comments for other safety justifications. -unsafe impl TransparentWrapper for Unalign { +unsafe impl TransparentWrapper for Unalign { type Inner = T; // SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same @@ -385,7 +385,7 @@ macro_rules! unsafe_impl_transparent_wrapper_for_atomic { ($(#[$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 crate::util::TransparentWrapper for $atomic { unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); } unsafe_impl_transparent_wrapper_for_atomic!($(#[$attr])* $($atomics [$natives],)*); @@ -401,7 +401,7 @@ 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::util::TransparentWrapper for $atomic { + unsafe impl<$tyvar> crate::util::TransparentWrapper for $atomic { unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); } };