Skip to content

Commit 5fcf372

Browse files
authored
[transmute] Encode cast in TryTransmuteFromPtr params (#2921)
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 1b012a1 commit 5fcf372

File tree

10 files changed

+106
-146
lines changed

10 files changed

+106
-146
lines changed

src/lib.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,9 +2040,7 @@ pub unsafe trait TryFromBytes {
20402040
// condition will not happen.
20412041
match source.try_into_valid() {
20422042
Ok(source) => Ok(source.as_mut()),
2043-
Err(e) => {
2044-
Err(e.map_src(|src| src.as_bytes::<BecauseExclusive>().as_mut()).into())
2045-
}
2043+
Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()),
20462044
}
20472045
}
20482046
Err(e) => Err(e.map_src(Ptr::as_mut).into()),
@@ -2622,9 +2620,7 @@ pub unsafe trait TryFromBytes {
26222620
// condition will not happen.
26232621
match source.try_into_valid() {
26242622
Ok(source) => Ok(source.as_mut()),
2625-
Err(e) => {
2626-
Err(e.map_src(|src| src.as_bytes::<BecauseExclusive>().as_mut()).into())
2627-
}
2623+
Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()),
26282624
}
26292625
}
26302626
Err(e) => Err(e.map_src(Ptr::as_mut).into()),
@@ -3044,7 +3040,7 @@ fn try_mut_from_prefix_suffix<T: IntoBytes + TryFromBytes + KnownLayout + ?Sized
30443040
// condition will not happen.
30453041
match candidate.try_into_valid() {
30463042
Ok(valid) => Ok((valid.as_mut(), prefix_suffix.as_mut())),
3047-
Err(e) => Err(e.map_src(|src| src.as_bytes::<BecauseExclusive>().as_mut()).into()),
3043+
Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()),
30483044
}
30493045
}
30503046
Err(e) => Err(e.map_src(Ptr::as_mut).into()),
@@ -4849,7 +4845,7 @@ pub unsafe trait FromBytes: FromZeros {
48494845
// cannot be violated even though `buf` may have more permissive bit
48504846
// validity than `ptr`.
48514847
let ptr = unsafe { ptr.assume_validity::<invariant::Initialized>() };
4852-
let ptr = ptr.as_bytes::<BecauseExclusive>();
4848+
let ptr = ptr.as_bytes();
48534849
src.read_exact(ptr.as_mut())?;
48544850
// SAFETY: `buf` entirely consists of initialized bytes, and `Self` is
48554851
// `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: 20 additions & 84 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`.
@@ -512,6 +502,11 @@ mod _conversions {
512502
pub(crate) fn into_unalign(
513503
self,
514504
) -> Ptr<'a, crate::Unalign<T>, (I::Aliasing, Aligned, I::Validity)> {
505+
// FIXME(#1359): This should be a `transmute_with` call.
506+
// Unfortunately, to avoid blanket impl conflicts, we only implement
507+
// `TransmuteFrom<T>` for `Unalign<T>` (and vice versa) specifically
508+
// for `Valid` validity, not for all validity types.
509+
515510
// SAFETY:
516511
// - By `CastSized: Cast`, `CastSized` preserves referent address,
517512
// and so we don't need to consider projections in the following
@@ -568,7 +563,7 @@ mod _conversions {
568563
/// State transitions between invariants.
569564
mod _transitions {
570565
use super::*;
571-
use crate::pointer::transmute::TryTransmuteFromPtr;
566+
use crate::pointer::{cast::IdCast, transmute::TryTransmuteFromPtr};
572567

573568
impl<'a, T, I> Ptr<'a, T, I>
574569
where
@@ -767,59 +762,6 @@ mod _transitions {
767762
unsafe { self.assume_validity::<Valid>() }
768763
}
769764

770-
/// Recalls that `self`'s referent is initialized.
771-
#[doc(hidden)]
772-
#[must_use]
773-
#[inline]
774-
// FIXME(#859): Reconsider the name of this method before making it
775-
// public.
776-
pub fn bikeshed_recall_initialized_from_bytes(
777-
self,
778-
) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Initialized)>
779-
where
780-
T: crate::IntoBytes + crate::FromBytes,
781-
I: Invariants<Validity = Valid>,
782-
{
783-
// SAFETY: The `T: IntoBytes + FromBytes` bound ensures that `T`'s
784-
// bit validity is equivalent to `[u8]`. In other words, the set of
785-
// allowed referents for a `Ptr<T, (_, _, Valid)>` is the set of
786-
// initialized bit patterns. The same is true of the set of allowed
787-
// referents for any `Ptr<_, (_, _, Initialized)>`. Thus, this call
788-
// does not change the set of allowed values in the referent.
789-
unsafe { self.assume_initialized() }
790-
}
791-
792-
/// Recalls that `self`'s referent is initialized.
793-
#[doc(hidden)]
794-
#[must_use]
795-
#[inline]
796-
// FIXME(#859): Reconsider the name of this method before making it
797-
// public.
798-
pub fn bikeshed_recall_initialized_immutable(
799-
self,
800-
) -> Ptr<'a, T, (Shared, I::Alignment, Initialized)>
801-
where
802-
T: crate::IntoBytes + crate::Immutable,
803-
I: Invariants<Aliasing = Shared, Validity = Valid>,
804-
{
805-
// SAFETY: Let `O` (for "old") be the set of allowed bit patterns in
806-
// `self`'s referent, and let `N` (for "new") be the set of allowed
807-
// bit patterns in the referent of the returned `Ptr`. `T:
808-
// IntoBytes` and `I: Invariants<Validity = Valid>` ensures that `O`
809-
// cannot contain any uninitialized bit patterns. Since the returned
810-
// `Ptr` has validity `Initialized`, `N` is equal to the set of all
811-
// initialized bit patterns. Thus, `O` is a subset of `N`, and so
812-
// the returned `Ptr`'s validity invariant is upheld.
813-
//
814-
// Since `T: Immutable` and aliasing is `Shared`, the returned `Ptr`
815-
// cannot be used to modify the referent. Before this call, `self`'s
816-
// referent is guaranteed by invariant on `Ptr` to satisfy `self`'s
817-
// validity invariant. Since the returned `Ptr` cannot be used to
818-
// modify the referent, this guarantee cannot be violated by the
819-
// returned `Ptr` (even if `O` is a strict subset of `N`).
820-
unsafe { self.assume_initialized() }
821-
}
822-
823765
/// Checks that `self`'s referent is validly initialized for `T`,
824766
/// returning a `Ptr` with `Valid` on success.
825767
///
@@ -839,7 +781,7 @@ mod _transitions {
839781
where
840782
T: TryFromBytes
841783
+ Read<I::Aliasing, R>
842-
+ TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, S>,
784+
+ TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, IdCast, S>,
843785
I::Aliasing: Reference,
844786
I: Invariants<Validity = Initialized>,
845787
{
@@ -977,23 +919,17 @@ mod _casts {
977919
impl<'a, T, I> Ptr<'a, T, I>
978920
where
979921
T: 'a + KnownLayout + ?Sized,
980-
I: Invariants<Validity = Initialized>,
922+
I: Invariants,
981923
{
982-
// FIXME: Is there any way to teach Rust that, for all `T, A, R`, `T:
983-
// Read<A, R>` implies `[u8]: Read<A, R>`?
984-
985924
/// Casts this pointer-to-initialized into a pointer-to-bytes.
986925
#[allow(clippy::wrong_self_convention)]
987926
#[must_use]
988927
#[inline]
989928
pub fn as_bytes<R>(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)>
990929
where
991-
T: Read<I::Aliasing, R>,
992-
[u8]: Read<I::Aliasing, R>,
993-
I::Aliasing: Reference,
930+
[u8]: TransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, AsBytesCast, R>,
994931
{
995-
let ptr = self.cast::<_, AsBytesCast, _>();
996-
ptr.bikeshed_recall_aligned().recall_validity::<Valid, (_, (_, _))>()
932+
self.transmute_with::<[u8], Valid, AsBytesCast, _>().bikeshed_recall_aligned()
997933
}
998934
}
999935

0 commit comments

Comments
 (0)