Skip to content

Commit da4069e

Browse files
committed
[pointer] Make invariants opaque, more ergonomic
Closes #1876
1 parent 25de780 commit da4069e

File tree

2 files changed

+63
-43
lines changed

2 files changed

+63
-43
lines changed

src/pointer/invariant.rs

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,40 @@ pub trait Invariants: Sealed {
1818
type Aliasing: Aliasing;
1919
type Alignment: Alignment;
2020
type Validity: Validity;
21+
22+
/// Invariants identical to `Self` except with a different aliasing
23+
/// invariant.
24+
type WithAliasing<A: Aliasing>: Invariants<
25+
Aliasing = A,
26+
Alignment = Self::Alignment,
27+
Validity = Self::Validity,
28+
>;
29+
30+
/// Invariants identical to `Self` except with a different alignment
31+
/// invariant.
32+
type WithAlignment<A: Alignment>: Invariants<
33+
Aliasing = Self::Aliasing,
34+
Alignment = A,
35+
Validity = Self::Validity,
36+
>;
37+
38+
/// Invariants identical to `Self` except with a different validity
39+
/// invariant.
40+
type WithValidity<V: Validity>: Invariants<
41+
Aliasing = Self::Aliasing,
42+
Alignment = Self::Alignment,
43+
Validity = V,
44+
>;
2145
}
2246

2347
impl<A: Aliasing, AA: Alignment, V: Validity> Invariants for (A, AA, V) {
2448
type Aliasing = A;
2549
type Alignment = AA;
2650
type Validity = V;
51+
52+
type WithAliasing<AB: Aliasing> = (AB, AA, V);
53+
type WithAlignment<AB: Alignment> = (A, AB, V);
54+
type WithValidity<VB: Validity> = (A, AA, VB);
2755
}
2856

2957
/// The aliasing invariant of a [`Ptr`][super::Ptr].
@@ -107,29 +135,29 @@ impl Alignment for Aligned {}
107135
/// The byte ranges initialized in `T` are also initialized in the referent.
108136
///
109137
/// Formally: uninitialized bytes may only be present in `Ptr<T>`'s referent
110-
/// where they are guaranteed to be present in `T`. This is a dynamic property:
111-
/// if, at a particular byte offset, a valid enum discriminant is set, the
112-
/// subsequent bytes may only have uninitialized bytes as specificed by the
113-
/// corresponding enum.
138+
/// where they are guaranteed to be present in `T`. This is a dynamic
139+
/// property: if, at a particular byte offset, a valid enum discriminant is
140+
/// set, the subsequent bytes may only have uninitialized bytes as
141+
/// specificed by the corresponding enum.
114142
///
115-
/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in
116-
/// the range `[0, len)`:
117-
/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t`
118-
/// is initialized, then the byte at offset `b` within `*ptr` must be
143+
/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`,
144+
/// in the range `[0, len)`:
145+
/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in
146+
/// `t` is initialized, then the byte at offset `b` within `*ptr` must be
119147
/// initialized.
120-
/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be
121-
/// the subset of valid instances of `T` of length `len` which contain `c` in
122-
/// the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte
123-
/// at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr`
124-
/// must be initialized.
148+
/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S`
149+
/// be the subset of valid instances of `T` of length `len` which contain
150+
/// `c` in the offset range `[0, b)`. If, in any instance of `t: T` in
151+
/// `S`, the byte at offset `b` in `t` is initialized, then the byte at
152+
/// offset `b` in `*ptr` must be initialized.
125153
///
126-
/// Pragmatically, this means that if `*ptr` is guaranteed to contain an enum
127-
/// type at a particular offset, and the enum discriminant stored in `*ptr`
128-
/// corresponds to a valid variant of that enum type, then it is guaranteed
129-
/// that the appropriate bytes of `*ptr` are initialized as defined by that
130-
/// variant's bit validity (although note that the variant may contain another
131-
/// enum type, in which case the same rules apply depending on the state of
132-
/// its discriminant, and so on recursively).
154+
/// Pragmatically, this means that if `*ptr` is guaranteed to contain an
155+
/// enum type at a particular offset, and the enum discriminant stored in
156+
/// `*ptr` corresponds to a valid variant of that enum type, then it is
157+
/// guaranteed that the appropriate bytes of `*ptr` are initialized as
158+
/// defined by that variant's bit validity (although note that the variant
159+
/// may contain another enum type, in which case the same rules apply
160+
/// depending on the state of its discriminant, and so on recursively).
133161
pub enum AsInitialized {}
134162
impl Validity for AsInitialized {}
135163

src/pointer/ptr.rs

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -416,9 +416,7 @@ mod _conversions {
416416
{
417417
/// Converts a `Ptr` an unaligned `T` into a `Ptr` to an aligned
418418
/// `Unalign<T>`.
419-
pub(crate) fn into_unalign(
420-
self,
421-
) -> Ptr<'a, crate::Unalign<T>, (I::Aliasing, Aligned, I::Validity)> {
419+
pub(crate) fn into_unalign(self) -> Ptr<'a, crate::Unalign<T>, I::WithAlignment<Aligned>> {
422420
// SAFETY:
423421
// - This cast preserves provenance.
424422
// - This cast preserves address. `Unalign<T>` promises to have the
@@ -436,7 +434,7 @@ mod _conversions {
436434
// SAFETY: `Unalign<T>` promises to have alignment 1, and so it is
437435
// trivially aligned.
438436
let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
439-
ptr
437+
ptr.unify_invariants()
440438
}
441439
}
442440
}
@@ -461,7 +459,7 @@ mod _transitions {
461459
#[inline]
462460
pub(crate) fn into_exclusive_or_post_monomorphization_error(
463461
self,
464-
) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> {
462+
) -> Ptr<'a, T, I::WithAliasing<Exclusive>> {
465463
// NOTE(https://github.com/rust-lang/rust/issues/131625): We do this
466464
// rather than just having `Aliasing::IS_EXCLUSIVE` have the panic
467465
// behavior because doing it that way causes rustdoc to fail while
@@ -521,7 +519,7 @@ mod _transitions {
521519
#[inline]
522520
pub(crate) const unsafe fn assume_aliasing<A: Aliasing>(
523521
self,
524-
) -> Ptr<'a, T, (A, I::Alignment, I::Validity)> {
522+
) -> Ptr<'a, T, I::WithAliasing<A>> {
525523
// SAFETY: The caller promises that `self` satisfies the aliasing
526524
// requirements of `A`.
527525
unsafe { self.assume_invariants() }
@@ -538,7 +536,7 @@ mod _transitions {
538536
#[inline]
539537
pub(crate) const unsafe fn assume_exclusive(
540538
self,
541-
) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> {
539+
) -> Ptr<'a, T, I::WithAliasing<Exclusive>> {
542540
// SAFETY: The caller promises that `self` satisfies the aliasing
543541
// requirements of `Exclusive`.
544542
unsafe { self.assume_aliasing::<Exclusive>() }
@@ -554,7 +552,7 @@ mod _transitions {
554552
#[inline]
555553
pub(crate) const unsafe fn assume_alignment<A: Alignment>(
556554
self,
557-
) -> Ptr<'a, T, (I::Aliasing, A, I::Validity)> {
555+
) -> Ptr<'a, T, I::WithAlignment<A>> {
558556
// SAFETY: The caller promises that `self`'s referent is
559557
// well-aligned for `T` if required by `A` .
560558
unsafe { self.assume_invariants() }
@@ -564,7 +562,7 @@ mod _transitions {
564562
/// on success.
565563
pub(crate) fn bikeshed_try_into_aligned(
566564
self,
567-
) -> Result<Ptr<'a, T, (I::Aliasing, Aligned, I::Validity)>, AlignmentError<Self, T>>
565+
) -> Result<Ptr<'a, T, I::WithAlignment<Aligned>>, AlignmentError<Self, T>>
568566
where
569567
T: Sized,
570568
{
@@ -582,9 +580,7 @@ mod _transitions {
582580
#[inline]
583581
// TODO(#859): Reconsider the name of this method before making it
584582
// public.
585-
pub(crate) const fn bikeshed_recall_aligned(
586-
self,
587-
) -> Ptr<'a, T, (I::Aliasing, Aligned, I::Validity)>
583+
pub(crate) const fn bikeshed_recall_aligned(self) -> Ptr<'a, T, I::WithAlignment<Aligned>>
588584
where
589585
T: crate::Unaligned,
590586
{
@@ -603,9 +599,7 @@ mod _transitions {
603599
#[doc(hidden)]
604600
#[must_use]
605601
#[inline]
606-
pub const unsafe fn assume_validity<V: Validity>(
607-
self,
608-
) -> Ptr<'a, T, (I::Aliasing, I::Alignment, V)> {
602+
pub const unsafe fn assume_validity<V: Validity>(self) -> Ptr<'a, T, I::WithValidity<V>> {
609603
// SAFETY: The caller promises that `self`'s referent conforms to
610604
// the validity requirement of `V`.
611605
unsafe { self.assume_invariants() }
@@ -620,9 +614,7 @@ mod _transitions {
620614
#[doc(hidden)]
621615
#[must_use]
622616
#[inline]
623-
pub const unsafe fn assume_initialized(
624-
self,
625-
) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Initialized)> {
617+
pub const unsafe fn assume_initialized(self) -> Ptr<'a, T, I::WithValidity<Initialized>> {
626618
// SAFETY: The caller has promised to uphold the safety
627619
// preconditions.
628620
unsafe { self.assume_validity::<Initialized>() }
@@ -637,7 +629,7 @@ mod _transitions {
637629
#[doc(hidden)]
638630
#[must_use]
639631
#[inline]
640-
pub const unsafe fn assume_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> {
632+
pub const unsafe fn assume_valid(self) -> Ptr<'a, T, I::WithValidity<Valid>> {
641633
// SAFETY: The caller has promised to uphold the safety
642634
// preconditions.
643635
unsafe { self.assume_validity::<Valid>() }
@@ -649,7 +641,7 @@ mod _transitions {
649641
#[inline]
650642
// TODO(#859): Reconsider the name of this method before making it
651643
// public.
652-
pub const fn bikeshed_recall_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)>
644+
pub const fn bikeshed_recall_valid(self) -> Ptr<'a, T, I::WithValidity<Valid>>
653645
where
654646
T: crate::FromBytes,
655647
I: Invariants<Validity = Initialized>,
@@ -676,7 +668,7 @@ mod _transitions {
676668
#[inline]
677669
pub(crate) fn try_into_valid(
678670
mut self,
679-
) -> Result<Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)>, ValidityError<Self, T>>
671+
) -> Result<Ptr<'a, T, I::WithValidity<Valid>>, ValidityError<Self, T>>
680672
where
681673
T: TryFromBytes,
682674
I::Aliasing: Reference,
@@ -685,7 +677,7 @@ mod _transitions {
685677
// This call may panic. If that happens, it doesn't cause any soundness
686678
// issues, as we have not generated any invalid state which we need to
687679
// fix before returning.
688-
if T::is_bit_valid(self.reborrow().forget_aligned()) {
680+
if T::is_bit_valid(self.reborrow().forget_aligned().unify_invariants()) {
689681
// SAFETY: If `T::is_bit_valid`, code may assume that `self`
690682
// contains a bit-valid instance of `Self`.
691683
Ok(unsafe { self.assume_valid() })
@@ -698,7 +690,7 @@ mod _transitions {
698690
#[doc(hidden)]
699691
#[must_use]
700692
#[inline]
701-
pub const fn forget_aligned(self) -> Ptr<'a, T, (I::Aliasing, Any, I::Validity)> {
693+
pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment<Any>> {
702694
// SAFETY: `Any` is less restrictive than `Aligned`.
703695
unsafe { self.assume_invariants() }
704696
}

0 commit comments

Comments
 (0)