Skip to content

Commit 2a92f9f

Browse files
committed
[pointer] Make invariants opaque, more ergonomic
Closes #1876
1 parent 471f4a9 commit 2a92f9f

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
@@ -401,9 +401,7 @@ mod _conversions {
401401
{
402402
/// Converts a `Ptr` an unaligned `T` into a `Ptr` to an aligned
403403
/// `Unalign<T>`.
404-
pub(crate) fn into_unalign(
405-
self,
406-
) -> Ptr<'a, crate::Unalign<T>, (I::Aliasing, Aligned, I::Validity)> {
404+
pub(crate) fn into_unalign(self) -> Ptr<'a, crate::Unalign<T>, I::WithAlignment<Aligned>> {
407405
// SAFETY:
408406
// - This cast preserves provenance.
409407
// - This cast preserves address. `Unalign<T>` promises to have the
@@ -421,7 +419,7 @@ mod _conversions {
421419
// SAFETY: `Unalign<T>` promises to have alignment 1, and so it is
422420
// trivially aligned.
423421
let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
424-
ptr
422+
ptr.unify_invariants()
425423
}
426424
}
427425
}
@@ -446,7 +444,7 @@ mod _transitions {
446444
#[inline]
447445
pub(crate) fn into_exclusive_or_post_monomorphization_error(
448446
self,
449-
) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> {
447+
) -> Ptr<'a, T, I::WithAliasing<Exclusive>> {
450448
// NOTE(https://github.com/rust-lang/rust/issues/131625): We do this
451449
// rather than just having `Aliasing::IS_EXCLUSIVE` have the panic
452450
// behavior because doing it that way causes rustdoc to fail while
@@ -506,7 +504,7 @@ mod _transitions {
506504
#[inline]
507505
pub(crate) const unsafe fn assume_aliasing<A: Aliasing>(
508506
self,
509-
) -> Ptr<'a, T, (A, I::Alignment, I::Validity)> {
507+
) -> Ptr<'a, T, I::WithAliasing<A>> {
510508
// SAFETY: The caller promises that `self` satisfies the aliasing
511509
// requirements of `A`.
512510
unsafe { self.assume_invariants() }
@@ -523,7 +521,7 @@ mod _transitions {
523521
#[inline]
524522
pub(crate) const unsafe fn assume_exclusive(
525523
self,
526-
) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> {
524+
) -> Ptr<'a, T, I::WithAliasing<Exclusive>> {
527525
// SAFETY: The caller promises that `self` satisfies the aliasing
528526
// requirements of `Exclusive`.
529527
unsafe { self.assume_aliasing::<Exclusive>() }
@@ -539,7 +537,7 @@ mod _transitions {
539537
#[inline]
540538
pub(crate) const unsafe fn assume_alignment<A: Alignment>(
541539
self,
542-
) -> Ptr<'a, T, (I::Aliasing, A, I::Validity)> {
540+
) -> Ptr<'a, T, I::WithAlignment<A>> {
543541
// SAFETY: The caller promises that `self`'s referent is
544542
// well-aligned for `T` if required by `A` .
545543
unsafe { self.assume_invariants() }
@@ -549,7 +547,7 @@ mod _transitions {
549547
/// on success.
550548
pub(crate) fn bikeshed_try_into_aligned(
551549
self,
552-
) -> Result<Ptr<'a, T, (I::Aliasing, Aligned, I::Validity)>, AlignmentError<Self, T>>
550+
) -> Result<Ptr<'a, T, I::WithAlignment<Aligned>>, AlignmentError<Self, T>>
553551
where
554552
T: Sized,
555553
{
@@ -567,9 +565,7 @@ mod _transitions {
567565
#[inline]
568566
// TODO(#859): Reconsider the name of this method before making it
569567
// public.
570-
pub(crate) const fn bikeshed_recall_aligned(
571-
self,
572-
) -> Ptr<'a, T, (I::Aliasing, Aligned, I::Validity)>
568+
pub(crate) const fn bikeshed_recall_aligned(self) -> Ptr<'a, T, I::WithAlignment<Aligned>>
573569
where
574570
T: crate::Unaligned,
575571
{
@@ -588,9 +584,7 @@ mod _transitions {
588584
#[doc(hidden)]
589585
#[must_use]
590586
#[inline]
591-
pub const unsafe fn assume_validity<V: Validity>(
592-
self,
593-
) -> Ptr<'a, T, (I::Aliasing, I::Alignment, V)> {
587+
pub const unsafe fn assume_validity<V: Validity>(self) -> Ptr<'a, T, I::WithValidity<V>> {
594588
// SAFETY: The caller promises that `self`'s referent conforms to
595589
// the validity requirement of `V`.
596590
unsafe { self.assume_invariants() }
@@ -605,9 +599,7 @@ mod _transitions {
605599
#[doc(hidden)]
606600
#[must_use]
607601
#[inline]
608-
pub const unsafe fn assume_initialized(
609-
self,
610-
) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Initialized)> {
602+
pub const unsafe fn assume_initialized(self) -> Ptr<'a, T, I::WithValidity<Initialized>> {
611603
// SAFETY: The caller has promised to uphold the safety
612604
// preconditions.
613605
unsafe { self.assume_validity::<Initialized>() }
@@ -622,7 +614,7 @@ mod _transitions {
622614
#[doc(hidden)]
623615
#[must_use]
624616
#[inline]
625-
pub const unsafe fn assume_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> {
617+
pub const unsafe fn assume_valid(self) -> Ptr<'a, T, I::WithValidity<Valid>> {
626618
// SAFETY: The caller has promised to uphold the safety
627619
// preconditions.
628620
unsafe { self.assume_validity::<Valid>() }
@@ -634,7 +626,7 @@ mod _transitions {
634626
#[inline]
635627
// TODO(#859): Reconsider the name of this method before making it
636628
// public.
637-
pub const fn bikeshed_recall_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)>
629+
pub const fn bikeshed_recall_valid(self) -> Ptr<'a, T, I::WithValidity<Valid>>
638630
where
639631
T: crate::FromBytes,
640632
I: Invariants<Validity = Initialized>,
@@ -661,7 +653,7 @@ mod _transitions {
661653
#[inline]
662654
pub(crate) fn try_into_valid(
663655
mut self,
664-
) -> Result<Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)>, ValidityError<Self, T>>
656+
) -> Result<Ptr<'a, T, I::WithValidity<Valid>>, ValidityError<Self, T>>
665657
where
666658
T: TryFromBytes,
667659
I::Aliasing: Reference,
@@ -670,7 +662,7 @@ mod _transitions {
670662
// This call may panic. If that happens, it doesn't cause any soundness
671663
// issues, as we have not generated any invalid state which we need to
672664
// fix before returning.
673-
if T::is_bit_valid(self.reborrow().forget_aligned()) {
665+
if T::is_bit_valid(self.reborrow().forget_aligned().unify_invariants()) {
674666
// SAFETY: If `T::is_bit_valid`, code may assume that `self`
675667
// contains a bit-valid instance of `Self`.
676668
Ok(unsafe { self.assume_valid() })
@@ -683,7 +675,7 @@ mod _transitions {
683675
#[doc(hidden)]
684676
#[must_use]
685677
#[inline]
686-
pub const fn forget_aligned(self) -> Ptr<'a, T, (I::Aliasing, Any, I::Validity)> {
678+
pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment<Any>> {
687679
// SAFETY: `Any` is less restrictive than `Aligned`.
688680
unsafe { self.assume_invariants() }
689681
}

0 commit comments

Comments
 (0)