Skip to content

Commit ec53bee

Browse files
committed
[pointer][WIP] Validity in referent
gherrit-pr-id: Icdd795ee43df33bd553deb69675c1cdca686a1d8
1 parent 354267d commit ec53bee

File tree

4 files changed

+218
-181
lines changed

4 files changed

+218
-181
lines changed

src/pointer/invariant.rs

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
pub trait Invariants: Sealed {
1818
type Aliasing: Aliasing;
1919
type Alignment: Alignment;
20-
type Validity: Validity;
20+
// type Validity: Validity;
2121
}
2222

23-
impl<A: Aliasing, AA: Alignment, V: Validity> Invariants for (A, AA, V) {
23+
impl<A: Aliasing, AA: Alignment> Invariants for (A, AA) {
2424
type Aliasing = A;
2525
type Alignment = AA;
26-
type Validity = V;
26+
// type Validity = V;
2727
}
2828

2929
/// The aliasing invariant of a [`Ptr`][super::Ptr].
@@ -83,7 +83,17 @@ pub trait Alignment: Sealed {}
8383
/// mechanism (e.g. a `&` reference used to derive `src`) to write `x` where
8484
/// `x ∈ S(T, V)` but `x ∉ S(U, W)`, which would violate the guarantee that
8585
/// `dst`'s referent may only contain values in `S(U, W)`.
86-
pub unsafe trait Validity: Sealed {}
86+
pub unsafe trait Validity: Sealed {
87+
type Inner: ?Sized;
88+
}
89+
90+
/// Does `V` have the same validity invariant as `Self`?
91+
///
92+
/// # Safety
93+
///
94+
/// Unsafe code may assume that `W: SameValidity<V>` guarantees that `V` and `W`
95+
/// have the same validity invariant.
96+
pub unsafe trait SameValidity<V>: Sealed {}
8797

8898
/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`].
8999
///
@@ -128,14 +138,24 @@ impl Alignment for Unaligned {}
128138
pub enum Aligned {}
129139
impl Alignment for Aligned {}
130140

141+
struct NeverPhantomData<T: ?Sized> {
142+
_marker: core::marker::PhantomData<T>,
143+
_never: core::convert::Infallible,
144+
}
145+
131146
/// Any bit pattern is allowed in the `Ptr`'s referent, including uninitialized
132147
/// bytes.
133-
pub enum Uninit {}
148+
pub struct Uninit<T: ?Sized>(NeverPhantomData<T>);
134149
// SAFETY: `Uninit`'s validity is well-defined for all `T: ?Sized`, and is not a
135150
// function of any property of `T` other than its bit validity (in fact, it's
136151
// not even a property of `T`'s bit validity, but this is more than we are
137152
// required to uphold).
138-
unsafe impl Validity for Uninit {}
153+
unsafe impl<T: ?Sized> Validity for Uninit<T> {
154+
type Inner = T;
155+
}
156+
157+
// SAFETY: The same validity (`Uninit`) is used for both types.
158+
unsafe impl<T: ?Sized, U: ?Sized> SameValidity<Uninit<T>> for Uninit<U> {}
139159

140160
/// The byte ranges initialized in `T` are also initialized in the referent of a
141161
/// `Ptr<T>`.
@@ -164,36 +184,48 @@ unsafe impl Validity for Uninit {}
164184
/// variant's bit validity (although note that the variant may contain another
165185
/// enum type, in which case the same rules apply depending on the state of
166186
/// its discriminant, and so on recursively).
167-
pub enum AsInitialized {}
187+
pub struct AsInitialized<T: ?Sized>(NeverPhantomData<T>);
168188
// SAFETY: `AsInitialized`'s validity is well-defined for all `T: ?Sized`, and
169189
// is not a function of any property of `T` other than its bit validity.
170-
unsafe impl Validity for AsInitialized {}
190+
unsafe impl<T: ?Sized> Validity for AsInitialized<T> {
191+
type Inner = T;
192+
}
193+
// SAFETY: The same validity (`AsInitialized`) is used for both types.
194+
unsafe impl<T: ?Sized, U: ?Sized> SameValidity<AsInitialized<T>> for AsInitialized<U> {}
171195

172196
/// The byte ranges in the referent are fully initialized. In other words, if
173197
/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`.
174-
pub enum Initialized {}
198+
pub struct Initialized<T: ?Sized>(NeverPhantomData<T>);
175199
// SAFETY: `Initialized`'s validity is well-defined for all `T: ?Sized`, and is
176200
// not a function of any property of `T` other than its bit validity (in fact,
177201
// it's not even a property of `T`'s bit validity, but this is more than we are
178202
// required to uphold).
179-
unsafe impl Validity for Initialized {}
203+
unsafe impl<T: ?Sized> Validity for Initialized<T> {
204+
type Inner = T;
205+
}
206+
// SAFETY: The same validity (`Initialized`) is used for both types.
207+
unsafe impl<T: ?Sized, U: ?Sized> SameValidity<Initialized<T>> for Initialized<U> {}
180208

181209
/// The referent of a `Ptr<T>` is bit-valid for `T`.
182-
pub enum Valid {}
210+
pub struct Valid<T: ?Sized>(NeverPhantomData<T>);
183211
// SAFETY: `Valid`'s validity is well-defined for all `T: ?Sized`, and is not a
184212
// function of any property of `T` other than its bit validity.
185-
unsafe impl Validity for Valid {}
213+
unsafe impl<T: ?Sized> Validity for Valid<T> {
214+
type Inner = T;
215+
}
216+
// SAFETY: The same validity (`Valid`) is used for both types.
217+
unsafe impl<T: ?Sized, U: ?Sized> SameValidity<Valid<T>> for Valid<U> {}
186218

187219
/// # Safety
188220
///
189-
/// `DT: CastableFrom<ST, SV, DV>` is sound if `SV = DV = Uninit` or `SV = DV =
190-
/// Initialized`.
191-
pub unsafe trait CastableFrom<ST: ?Sized, SV, DV> {}
221+
/// `U: CastableFrom<T>` is sound if `T` and `U` have the same validity, and
222+
/// that validity is either [`Uninit`] or [`Initialized`].
223+
pub unsafe trait CastableFrom<T: ?Sized> {}
192224

193-
// SAFETY: `SV = DV = Uninit`.
194-
unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Uninit, Uninit> for DT {}
195-
// SAFETY: `SV = DV = Initialized`.
196-
unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Initialized, Initialized> for DT {}
225+
// SAFETY: Both types have validity `Uninit`.
226+
unsafe impl<T: ?Sized, U: ?Sized> CastableFrom<Uninit<T>> for Uninit<U> {}
227+
// SAFETY: Both types have validity `Initialized`.
228+
unsafe impl<T: ?Sized, U: ?Sized> CastableFrom<Initialized<T>> for Initialized<U> {}
197229

198230
/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations.
199231
///
@@ -238,12 +270,12 @@ mod sealed {
238270
impl Sealed for Unaligned {}
239271
impl Sealed for Aligned {}
240272

241-
impl Sealed for Uninit {}
242-
impl Sealed for AsInitialized {}
243-
impl Sealed for Initialized {}
244-
impl Sealed for Valid {}
273+
impl<T: ?Sized> Sealed for Uninit<T> {}
274+
impl<T: ?Sized> Sealed for AsInitialized<T> {}
275+
impl<T: ?Sized> Sealed for Initialized<T> {}
276+
impl<T: ?Sized> Sealed for Valid<T> {}
245277

246-
impl<A: Sealed, AA: Sealed, V: Sealed> Sealed for (A, AA, V) {}
278+
impl<A: Sealed, AA: Sealed> Sealed for (A, AA) {}
247279

248280
impl Sealed for BecauseImmutable {}
249281
impl Sealed for BecauseExclusive {}

src/pointer/mod.rs

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,55 +17,51 @@ mod transmute;
1717
#[doc(hidden)]
1818
pub(crate) use transmute::*;
1919
#[doc(hidden)]
20-
pub use {
21-
invariant::{BecauseExclusive, BecauseImmutable, Read},
22-
ptr::Ptr,
23-
};
20+
pub use {invariant::*, ptr::Ptr};
2421

2522
use crate::Unaligned;
2623

2724
/// A shorthand for a maybe-valid, maybe-aligned reference. Used as the argument
2825
/// to [`TryFromBytes::is_bit_valid`].
2926
///
3027
/// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid
31-
pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unaligned> =
32-
Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>;
28+
pub type Maybe<'a, T, Aliasing = Shared, Alignment = Unaligned> =
29+
Ptr<'a, Initialized<T>, (Aliasing, Alignment)>;
3330

3431
/// A semi-user-facing wrapper type representing a maybe-aligned reference, for
3532
/// use in [`TryFromBytes::is_bit_valid`].
3633
///
3734
/// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid
38-
pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unaligned> =
39-
Ptr<'a, T, (Aliasing, Alignment, invariant::Valid)>;
35+
pub type MaybeAligned<'a, T, Aliasing = Shared, Alignment = Unaligned> =
36+
Ptr<'a, Valid<T>, (Aliasing, Alignment)>;
4037

4138
// These methods are defined on the type alias, `MaybeAligned`, so as to bring
4239
// them to the forefront of the rendered rustdoc for that type alias.
43-
impl<'a, T, Aliasing, Alignment> MaybeAligned<'a, T, Aliasing, Alignment>
40+
impl<'a, T, A, AA> MaybeAligned<'a, T, A, AA>
4441
where
4542
T: 'a + ?Sized,
46-
Aliasing: invariant::Aliasing,
47-
Alignment: invariant::Alignment,
43+
A: Aliasing,
44+
AA: Alignment,
4845
{
4946
/// Reads the value from `MaybeAligned`.
5047
#[must_use]
5148
#[inline]
5249
pub fn read_unaligned<R>(self) -> T
5350
where
54-
T: Copy,
55-
T: invariant::Read<Aliasing, R>,
51+
T: Read<A, R> + Copy,
5652
{
5753
// SAFETY: By invariant on `MaybeAligned`, `self` contains
58-
// validly-initialized data for `T`. By `T: Read<Aliasing>`, we are
59-
// permitted to perform a read of `self`'s referent.
54+
// validly-initialized data for `T`. By `T: Read<A>`, we are permitted
55+
// to perform a read of `self`'s referent.
6056
unsafe { self.as_inner().read_unaligned() }
6157
}
6258
}
6359

64-
impl<'a, T, Aliasing, Alignment> MaybeAligned<'a, T, Aliasing, Alignment>
60+
impl<'a, T, A, AA> MaybeAligned<'a, T, A, AA>
6561
where
6662
T: 'a + ?Sized,
67-
Aliasing: invariant::Reference,
68-
Alignment: invariant::Alignment,
63+
A: Reference,
64+
AA: Alignment,
6965
{
7066
/// Views the value as an aligned reference.
7167
///
@@ -74,18 +70,18 @@ where
7470
#[inline]
7571
pub fn unaligned_as_ref(self) -> &'a T
7672
where
77-
T: Unaligned,
73+
T: crate::Unaligned,
7874
{
7975
self.bikeshed_recall_aligned().as_ref()
8076
}
8177
}
8278

8379
/// Checks if the referent is zeroed.
84-
pub(crate) fn is_zeroed<T, I>(ptr: Ptr<'_, T, I>) -> bool
80+
pub(crate) fn is_zeroed<T, I>(ptr: Ptr<'_, Initialized<T>, I>) -> bool
8581
where
86-
T: crate::Immutable + crate::KnownLayout,
87-
I: invariant::Invariants<Validity = invariant::Initialized>,
88-
I::Aliasing: invariant::Reference,
82+
T: crate::Immutable + crate::KnownLayout + ?Sized,
83+
I: Invariants,
84+
I::Aliasing: Reference,
8985
{
9086
ptr.as_bytes::<BecauseImmutable>().as_ref().iter().all(|&byte| byte == 0)
9187
}

0 commit comments

Comments
 (0)