Skip to content

Commit 565194b

Browse files
committed
[transmute] Encode cast in TryTransmuteFromPtr params
This prepares us for a future change in which some impls will only be sound for certain cast types. It also allows us to simplify some APIs and implementations on `Ptr`. Makes progress on #2701, #1940, #1852 gherrit-pr-id: G1cb98a9a25bc3bcf02d17e63b5389c2d66e9b4d8
1 parent aec697e commit 565194b

File tree

6 files changed

+93
-98
lines changed

6 files changed

+93
-98
lines changed

src/lib.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1943,9 +1943,7 @@ pub unsafe trait TryFromBytes {
19431943
// condition will not happen.
19441944
match source.try_into_valid() {
19451945
Ok(source) => Ok(source.as_mut()),
1946-
Err(e) => {
1947-
Err(e.map_src(|src| src.as_bytes::<BecauseExclusive>().as_mut()).into())
1948-
}
1946+
Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()),
19491947
}
19501948
}
19511949
Err(e) => Err(e.map_src(Ptr::as_mut).into()),
@@ -2525,9 +2523,7 @@ pub unsafe trait TryFromBytes {
25252523
// condition will not happen.
25262524
match source.try_into_valid() {
25272525
Ok(source) => Ok(source.as_mut()),
2528-
Err(e) => {
2529-
Err(e.map_src(|src| src.as_bytes::<BecauseExclusive>().as_mut()).into())
2530-
}
2526+
Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()),
25312527
}
25322528
}
25332529
Err(e) => Err(e.map_src(Ptr::as_mut).into()),
@@ -2947,7 +2943,7 @@ fn try_mut_from_prefix_suffix<T: IntoBytes + TryFromBytes + KnownLayout + ?Sized
29472943
// condition will not happen.
29482944
match candidate.try_into_valid() {
29492945
Ok(valid) => Ok((valid.as_mut(), prefix_suffix.as_mut())),
2950-
Err(e) => Err(e.map_src(|src| src.as_bytes::<BecauseExclusive>().as_mut()).into()),
2946+
Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()),
29512947
}
29522948
}
29532949
Err(e) => Err(e.map_src(Ptr::as_mut).into()),
@@ -4752,7 +4748,7 @@ pub unsafe trait FromBytes: FromZeros {
47524748
// cannot be violated even though `buf` may have more permissive bit
47534749
// validity than `ptr`.
47544750
let ptr = unsafe { ptr.assume_validity::<invariant::Initialized>() };
4755-
let ptr = ptr.as_bytes::<BecauseExclusive>();
4751+
let ptr = ptr.as_bytes();
47564752
src.read_exact(ptr.as_mut())?;
47574753
// SAFETY: `buf` entirely consists of initialized bytes, and `Self` is
47584754
// `FromBytes`.

src/pointer/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ where
3636
I: invariant::Invariants<Validity = invariant::Initialized>,
3737
I::Aliasing: invariant::Reference,
3838
{
39-
ptr.as_bytes::<BecauseImmutable>().as_ref().iter().all(|&byte| byte == 0)
39+
ptr.as_bytes().as_ref().iter().all(|&byte| byte == 0)
4040
}
4141

4242
#[doc(hidden)]
@@ -315,7 +315,8 @@ pub mod cast {
315315
}
316316

317317
/// A cast from `T` to `[u8]`.
318-
pub(crate) struct AsBytesCast;
318+
#[allow(missing_copy_implementations, missing_debug_implementations)]
319+
pub struct AsBytesCast;
319320

320321
// SAFETY: `project` constructs a pointer with the same address as `src`
321322
// and with a referent of the same size as `*src`. It does this using

src/pointer/ptr.rs

Lines changed: 25 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ mod _external {
160160
/// Methods for converting to and from `Ptr` and Rust's safe reference types.
161161
mod _conversions {
162162
use super::*;
163-
use crate::pointer::cast::CastSized;
163+
use crate::pointer::cast::{CastExact, CastSized, IdCast};
164164

165165
/// `&'a T` → `Ptr<'a, T>`
166166
impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)>
@@ -381,16 +381,18 @@ mod _conversions {
381381
pub(crate) fn transmute<U, V, R>(self) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)>
382382
where
383383
V: Validity,
384-
U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, R> + SizeEq<T> + ?Sized,
384+
U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, <U as SizeEq<T>>::CastFrom, R>
385+
+ SizeEq<T>
386+
+ ?Sized,
385387
{
386388
self.transmute_with::<U, V, <U as SizeEq<T>>::CastFrom, R>()
387389
}
388390

389391
pub(crate) fn transmute_with<U, V, C, R>(self) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)>
390392
where
391393
V: Validity,
392-
U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, R> + ?Sized,
393-
C: crate::pointer::cast::CastExact<T, U>,
394+
U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, C, R> + ?Sized,
395+
C: CastExact<T, U>,
394396
{
395397
// SAFETY:
396398
// - By `C: CastExact`, `C` preserves referent address, and so we
@@ -403,10 +405,8 @@ mod _conversions {
403405
// at the same time, as neither can perform interior mutation
404406
// - It is directly guaranteed that it is sound for shared code to
405407
// operate on these references simultaneously
406-
// - By `U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V>`, it is
407-
// sound to perform this transmute using an address- and
408-
// size-preserving cast. By `C: CastExact`, `C` is address- and
409-
// size-preserving.
408+
// - By `U: TransmuteFromPtr<T, I::Aliasing, I::Validity, C, V>`, it
409+
// is sound to perform this transmute using `C`.
410410
unsafe { self.project_transmute_unchecked::<_, _, C>() }
411411
}
412412

@@ -416,19 +416,9 @@ mod _conversions {
416416
pub fn recall_validity<V, R>(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, V)>
417417
where
418418
V: Validity,
419-
T: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, R>,
419+
T: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, IdCast, R>,
420420
{
421-
// SAFETY:
422-
// - By `SizeEq::CastFrom: Cast`, `SizeEq::CastFrom` preserves
423-
// referent address, and so we don't need to consider projections
424-
// in the following safety arguments.
425-
// - It is trivially sound to have multiple `&T` referencing the
426-
// same referent simultaneously
427-
// - By `T: TransmuteFromPtr<T, I::Aliasing, I::Validity, V>`, it is
428-
// sound to perform this transmute using an address- and
429-
// size-preserving cast (which `IdCast` is).
430-
let ptr =
431-
unsafe { self.project_transmute_unchecked::<_, _, crate::pointer::cast::IdCast>() };
421+
let ptr = self.transmute_with::<T, V, IdCast, R>();
432422
// SAFETY: `self` and `ptr` have the same address and referent type.
433423
// Therefore, if `self` satisfies `I::Alignment`, then so does
434424
// `ptr`.
@@ -511,6 +501,10 @@ mod _conversions {
511501
pub(crate) fn into_unalign(
512502
self,
513503
) -> Ptr<'a, crate::Unalign<T>, (I::Aliasing, Aligned, I::Validity)> {
504+
// TODO: Get this working:
505+
//
506+
// let ptr = self.transmute_with::<crate::Unalign<T>, I::Validity, CastSizedExact, _>();
507+
514508
// SAFETY:
515509
// - By `CastSized: Cast`, `CastSized` preserves referent address,
516510
// and so we don't need to consider projections in the following
@@ -567,7 +561,7 @@ mod _conversions {
567561
/// State transitions between invariants.
568562
mod _transitions {
569563
use super::*;
570-
use crate::pointer::transmute::TryTransmuteFromPtr;
564+
use crate::pointer::{cast::IdCast, transmute::TryTransmuteFromPtr};
571565

572566
impl<'a, T, I> Ptr<'a, T, I>
573567
where
@@ -779,13 +773,9 @@ mod _transitions {
779773
T: crate::IntoBytes + crate::FromBytes,
780774
I: Invariants<Validity = Valid>,
781775
{
782-
// SAFETY: The `T: IntoBytes + FromBytes` bound ensures that `T`'s
783-
// bit validity is equivalent to `[u8]`. In other words, the set of
784-
// allowed referents for a `Ptr<T, (_, _, Valid)>` is the set of
785-
// initialized bit patterns. The same is true of the set of allowed
786-
// referents for any `Ptr<_, (_, _, Initialized)>`. Thus, this call
787-
// does not change the set of allowed values in the referent.
788-
unsafe { self.assume_initialized() }
776+
let ptr = self.transmute_with::<T, Initialized, IdCast, _>();
777+
// SAFETY: TODO
778+
unsafe { ptr.assume_alignment() }
789779
}
790780

791781
/// Recalls that `self`'s referent is initialized.
@@ -801,22 +791,9 @@ mod _transitions {
801791
T: crate::IntoBytes + crate::Immutable,
802792
I: Invariants<Aliasing = Shared, Validity = Valid>,
803793
{
804-
// SAFETY: Let `O` (for "old") be the set of allowed bit patterns in
805-
// `self`'s referent, and let `N` (for "new") be the set of allowed
806-
// bit patterns in the referent of the returned `Ptr`. `T:
807-
// IntoBytes` and `I: Invariants<Validity = Valid>` ensures that `O`
808-
// cannot contain any uninitialized bit patterns. Since the returned
809-
// `Ptr` has validity `Initialized`, `N` is equal to the set of all
810-
// initialized bit patterns. Thus, `O` is a subset of `N`, and so
811-
// the returned `Ptr`'s validity invariant is upheld.
812-
//
813-
// Since `T: Immutable` and aliasing is `Shared`, the returned `Ptr`
814-
// cannot be used to modify the referent. Before this call, `self`'s
815-
// referent is guaranteed by invariant on `Ptr` to satisfy `self`'s
816-
// validity invariant. Since the returned `Ptr` cannot be used to
817-
// modify the referent, this guarantee cannot be violated by the
818-
// returned `Ptr` (even if `O` is a strict subset of `N`).
819-
unsafe { self.assume_initialized() }
794+
let ptr = self.transmute_with::<T, Initialized, IdCast, _>();
795+
// SAFETY: TODO
796+
unsafe { ptr.assume_alignment() }
820797
}
821798

822799
/// Checks that `self`'s referent is validly initialized for `T`,
@@ -838,7 +815,7 @@ mod _transitions {
838815
where
839816
T: TryFromBytes
840817
+ Read<I::Aliasing, R>
841-
+ TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, S>,
818+
+ TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, IdCast, S>,
842819
I::Aliasing: Reference,
843820
I: Invariants<Validity = Initialized>,
844821
{
@@ -976,23 +953,17 @@ mod _casts {
976953
impl<'a, T, I> Ptr<'a, T, I>
977954
where
978955
T: 'a + KnownLayout + ?Sized,
979-
I: Invariants<Validity = Initialized>,
956+
I: Invariants,
980957
{
981-
// FIXME: Is there any way to teach Rust that, for all `T, A, R`, `T:
982-
// Read<A, R>` implies `[u8]: Read<A, R>`?
983-
984958
/// Casts this pointer-to-initialized into a pointer-to-bytes.
985959
#[allow(clippy::wrong_self_convention)]
986960
#[must_use]
987961
#[inline]
988962
pub fn as_bytes<R>(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)>
989963
where
990-
T: Read<I::Aliasing, R>,
991-
[u8]: Read<I::Aliasing, R>,
992-
I::Aliasing: Reference,
964+
[u8]: TransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, AsBytesCast, R>,
993965
{
994-
let ptr = self.cast::<_, AsBytesCast, _>();
995-
ptr.bikeshed_recall_aligned().recall_validity::<Valid, (_, (_, _))>()
966+
self.transmute_with::<[u8], Valid, AsBytesCast, _>().bikeshed_recall_aligned()
996967
}
997968
}
998969

0 commit comments

Comments
 (0)