Skip to content

Commit b3dc714

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 d65cc63 commit b3dc714

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
@@ -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: 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`.
@@ -511,6 +501,11 @@ mod _conversions {
511501
pub(crate) fn into_unalign(
512502
self,
513503
) -> Ptr<'a, crate::Unalign<T>, (I::Aliasing, Aligned, I::Validity)> {
504+
// FIXME(#1359): This should be a `transmute_with` call.
505+
// Unfortunately, to avoid blanket impl conflicts, we only implement
506+
// `TransmuteFrom<T>` for `Unalign<T>` (and vice versa) specifically
507+
// for `Valid` validity, not for all validity types.
508+
514509
// SAFETY:
515510
// - By `CastSized: Cast`, `CastSized` preserves referent address,
516511
// and so we don't need to consider projections in the following
@@ -567,7 +562,7 @@ mod _conversions {
567562
/// State transitions between invariants.
568563
mod _transitions {
569564
use super::*;
570-
use crate::pointer::transmute::TryTransmuteFromPtr;
565+
use crate::pointer::{cast::IdCast, transmute::TryTransmuteFromPtr};
571566

572567
impl<'a, T, I> Ptr<'a, T, I>
573568
where
@@ -766,59 +761,6 @@ mod _transitions {
766761
unsafe { self.assume_validity::<Valid>() }
767762
}
768763

769-
/// Recalls that `self`'s referent is initialized.
770-
#[doc(hidden)]
771-
#[must_use]
772-
#[inline]
773-
// FIXME(#859): Reconsider the name of this method before making it
774-
// public.
775-
pub fn bikeshed_recall_initialized_from_bytes(
776-
self,
777-
) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Initialized)>
778-
where
779-
T: crate::IntoBytes + crate::FromBytes,
780-
I: Invariants<Validity = Valid>,
781-
{
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() }
789-
}
790-
791-
/// Recalls that `self`'s referent is initialized.
792-
#[doc(hidden)]
793-
#[must_use]
794-
#[inline]
795-
// FIXME(#859): Reconsider the name of this method before making it
796-
// public.
797-
pub fn bikeshed_recall_initialized_immutable(
798-
self,
799-
) -> Ptr<'a, T, (Shared, I::Alignment, Initialized)>
800-
where
801-
T: crate::IntoBytes + crate::Immutable,
802-
I: Invariants<Aliasing = Shared, Validity = Valid>,
803-
{
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() }
820-
}
821-
822764
/// Checks that `self`'s referent is validly initialized for `T`,
823765
/// returning a `Ptr` with `Valid` on success.
824766
///
@@ -838,7 +780,7 @@ mod _transitions {
838780
where
839781
T: TryFromBytes
840782
+ Read<I::Aliasing, R>
841-
+ TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, S>,
783+
+ TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, IdCast, S>,
842784
I::Aliasing: Reference,
843785
I: Invariants<Validity = Initialized>,
844786
{
@@ -976,23 +918,17 @@ mod _casts {
976918
impl<'a, T, I> Ptr<'a, T, I>
977919
where
978920
T: 'a + KnownLayout + ?Sized,
979-
I: Invariants<Validity = Initialized>,
921+
I: Invariants,
980922
{
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-
984923
/// Casts this pointer-to-initialized into a pointer-to-bytes.
985924
#[allow(clippy::wrong_self_convention)]
986925
#[must_use]
987926
#[inline]
988927
pub fn as_bytes<R>(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)>
989928
where
990-
T: Read<I::Aliasing, R>,
991-
[u8]: Read<I::Aliasing, R>,
992-
I::Aliasing: Reference,
929+
[u8]: TransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, AsBytesCast, R>,
993930
{
994-
let ptr = self.cast::<_, AsBytesCast, _>();
995-
ptr.bikeshed_recall_aligned().recall_validity::<Valid, (_, (_, _))>()
931+
self.transmute_with::<[u8], Valid, AsBytesCast, _>().bikeshed_recall_aligned()
996932
}
997933
}
998934

0 commit comments

Comments
 (0)