Skip to content

Commit 9b71dc8

Browse files
committed
[pointer][transmute] Support generic TransmuteFrom
This commit replaces the `TransparentWrapper` trait with a more generic, bidirectional `TransmuteFrom<T>` trait. `U: TransmuteFrom<T>` indicates that `T` and `U` have the same sizes and that `T` can be transmuted into `U` given certain alignment and validity invariant mappings. Makes progress on #1122 gherrit-pr-id: I7af68cdaa5ea47ab245a942d1cbd8bc5e6407223
1 parent 4795dcd commit 9b71dc8

File tree

7 files changed

+730
-442
lines changed

7 files changed

+730
-442
lines changed

src/impls.rs

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -443,13 +443,13 @@ mod atomics {
443443
use super::*;
444444

445445
macro_rules! impl_traits_for_atomics {
446-
($($atomics:ident),* $(,)?) => {
446+
($($atomics:ident[$repr:ty]),* $(,)?) => {
447447
$(
448448
impl_known_layout!($atomics);
449-
impl_for_transparent_wrapper!(=> TryFromBytes for $atomics);
450-
impl_for_transparent_wrapper!(=> FromZeros for $atomics);
451-
impl_for_transparent_wrapper!(=> FromBytes for $atomics);
452-
impl_for_transparent_wrapper!(=> IntoBytes for $atomics);
449+
impl_for_transmute_from!(=> TryFromBytes for $atomics[UnsafeCell<$repr>]);
450+
impl_for_transmute_from!(=> FromZeros for $atomics[UnsafeCell<$repr>]);
451+
impl_for_transmute_from!(=> FromBytes for $atomics[UnsafeCell<$repr>]);
452+
impl_for_transmute_from!(=> IntoBytes for $atomics[UnsafeCell<$repr>]);
453453
)*
454454
};
455455
}
@@ -461,13 +461,13 @@ mod atomics {
461461

462462
use super::*;
463463

464-
impl_traits_for_atomics!(AtomicU8, AtomicI8);
464+
impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]);
465465

466466
impl_known_layout!(AtomicBool);
467467

468-
impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool);
469-
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool);
470-
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool);
468+
impl_for_transmute_from!(=> TryFromBytes for AtomicBool[UnsafeCell<bool>]);
469+
impl_for_transmute_from!(=> FromZeros for AtomicBool[UnsafeCell<bool>]);
470+
impl_for_transmute_from!(=> IntoBytes for AtomicBool[UnsafeCell<bool>]);
471471

472472
safety_comment! {
473473
/// SAFETY:
@@ -497,7 +497,7 @@ mod atomics {
497497
/// SAFETY:
498498
/// All of these pass an atomic type and that type's native equivalent, as
499499
/// required by the macro safety preconditions.
500-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
500+
unsafe_impl_transmute_from_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
501501
}
502502
}
503503

@@ -508,13 +508,13 @@ mod atomics {
508508

509509
use super::*;
510510

511-
impl_traits_for_atomics!(AtomicU16, AtomicI16);
511+
impl_traits_for_atomics!(AtomicU16[u16], AtomicI16[i16]);
512512

513513
safety_comment! {
514514
/// SAFETY:
515515
/// All of these pass an atomic type and that type's native equivalent, as
516516
/// required by the macro safety preconditions.
517-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
517+
unsafe_impl_transmute_from_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
518518
}
519519
}
520520

@@ -525,13 +525,13 @@ mod atomics {
525525

526526
use super::*;
527527

528-
impl_traits_for_atomics!(AtomicU32, AtomicI32);
528+
impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]);
529529

530530
safety_comment! {
531531
/// SAFETY:
532532
/// All of these pass an atomic type and that type's native equivalent, as
533533
/// required by the macro safety preconditions.
534-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
534+
unsafe_impl_transmute_from_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
535535
}
536536
}
537537

@@ -542,13 +542,13 @@ mod atomics {
542542

543543
use super::*;
544544

545-
impl_traits_for_atomics!(AtomicU64, AtomicI64);
545+
impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]);
546546

547547
safety_comment! {
548548
/// SAFETY:
549549
/// All of these pass an atomic type and that type's native equivalent, as
550550
/// required by the macro safety preconditions.
551-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
551+
unsafe_impl_transmute_from_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
552552
}
553553
}
554554

@@ -559,21 +559,21 @@ mod atomics {
559559

560560
use super::*;
561561

562-
impl_traits_for_atomics!(AtomicUsize, AtomicIsize);
562+
impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]);
563563

564564
impl_known_layout!(T => AtomicPtr<T>);
565565

566566
// TODO(#170): Implement `FromBytes` and `IntoBytes` once we implement
567567
// those traits for `*mut T`.
568-
impl_for_transparent_wrapper!(T => TryFromBytes for AtomicPtr<T>);
569-
impl_for_transparent_wrapper!(T => FromZeros for AtomicPtr<T>);
568+
impl_for_transmute_from!(T => TryFromBytes for AtomicPtr<T>[UnsafeCell<*mut T>]);
569+
impl_for_transmute_from!(T => FromZeros for AtomicPtr<T>[UnsafeCell<*mut T>]);
570570

571571
safety_comment! {
572572
/// SAFETY:
573573
/// This passes an atomic type and that type's native equivalent, as
574574
/// required by the macro safety preconditions.
575-
unsafe_impl_transparent_wrapper_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
576-
unsafe_impl_transparent_wrapper_for_atomic!(T => AtomicPtr<T> [*mut T]);
575+
unsafe_impl_transmute_from_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
576+
unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr<T> [*mut T]);
577577
}
578578
}
579579
}
@@ -603,12 +603,12 @@ safety_comment! {
603603
assert_unaligned!(PhantomData<()>, PhantomData<u8>, PhantomData<u64>);
604604
}
605605

606-
impl_for_transparent_wrapper!(T: Immutable => Immutable for Wrapping<T>);
607-
impl_for_transparent_wrapper!(T: TryFromBytes => TryFromBytes for Wrapping<T>);
608-
impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping<T>);
609-
impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping<T>);
610-
impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping<T>);
611-
impl_for_transparent_wrapper!(T: Unaligned => Unaligned for Wrapping<T>);
606+
impl_for_transmute_from!(T: Immutable => Immutable for Wrapping<T>[T]);
607+
impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping<T>[T]);
608+
impl_for_transmute_from!(T: FromZeros => FromZeros for Wrapping<T>[T]);
609+
impl_for_transmute_from!(T: FromBytes => FromBytes for Wrapping<T>[T]);
610+
impl_for_transmute_from!(T: IntoBytes => IntoBytes for Wrapping<T>[T]);
611+
impl_for_transmute_from!(T: Unaligned => Unaligned for Wrapping<T>[T]);
612612
assert_unaligned!(Wrapping<()>, Wrapping<u8>);
613613

614614
safety_comment! {
@@ -620,22 +620,22 @@ safety_comment! {
620620
unsafe_impl!(T => FromBytes for MaybeUninit<T>);
621621
}
622622

623-
impl_for_transparent_wrapper!(T: Immutable => Immutable for MaybeUninit<T>);
624-
impl_for_transparent_wrapper!(T: Unaligned => Unaligned for MaybeUninit<T>);
623+
impl_for_transmute_from!(T: Immutable => Immutable for MaybeUninit<T>[T]);
624+
impl_for_transmute_from!(T: Unaligned => Unaligned for MaybeUninit<T>[T]);
625625
assert_unaligned!(MaybeUninit<()>, MaybeUninit<u8>);
626626

627-
impl_for_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>);
628-
impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T>);
629-
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>);
630-
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>);
631-
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>);
632-
impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>);
627+
impl_for_transmute_from!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>[T]);
628+
impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T>[T]);
629+
impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>[T]);
630+
impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>[T]);
631+
impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>[T]);
632+
impl_for_transmute_from!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>[T]);
633633
assert_unaligned!(ManuallyDrop<()>, ManuallyDrop<u8>);
634634

635-
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>);
636-
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>);
637-
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>);
638-
impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>);
635+
impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>[T]);
636+
impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>[T]);
637+
impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>[T]);
638+
impl_for_transmute_from!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>[T]);
639639
assert_unaligned!(UnsafeCell<()>, UnsafeCell<u8>);
640640

641641
// SAFETY: See safety comment in `is_bit_valid` impl.

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2720,7 +2720,7 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
27202720
// We use `from_mut` despite not mutating via `c_ptr` so that we don't need
27212721
// to add a `T: Immutable` bound.
27222722
let c_ptr = Ptr::from_mut(&mut candidate);
2723-
let c_ptr = c_ptr.transparent_wrapper_into_inner();
2723+
let c_ptr = c_ptr.transmute::<_, pointer::transmute::BecauseBidirectional>();
27242724
// SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from
27252725
// `candidate`, which the caller promises is entirely initialized.
27262726
let c_ptr = unsafe { c_ptr.assume_validity::<invariant::Initialized>() };

src/pointer/invariant.rs

Lines changed: 112 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl<A: Aliasing, AA: Alignment, V: Validity> Invariants for (A, AA, V) {
5757
/// The aliasing invariant of a [`Ptr`][super::Ptr].
5858
///
5959
/// All aliasing invariants must permit reading from the bytes of a pointer's
60-
/// referent which are not covered by [`UnsafeCell`]s.
60+
/// referent which are not covered by [`UnsafeCell`](core::cell::UnsafeCell)s.
6161
pub trait Aliasing: Sealed {
6262
/// Is `Self` [`Exclusive`]?
6363
#[doc(hidden)]
@@ -70,18 +70,56 @@ pub trait Aliasing: Sealed {
7070
type Variance<'a, T: 'a + ?Sized>;
7171
}
7272

73-
/// The alignment invariant of a [`Ptr`][super::Ptr].
74-
pub trait Alignment: Sealed {
75-
#[doc(hidden)]
73+
// NOTE: The `AlignmentInner`/`Alignment` distinction is required so that we can
74+
// add a `MappedTo<Preserved> = Self` bound. For an explanation of the design
75+
// space (and prior attempts), see:
76+
// https://users.rust-lang.org/t/how-to-implement-a-type-level-map-with-an-identity-function/119745
77+
#[doc(hidden)]
78+
pub trait AlignmentInner: Sealed {
7679
type MappedTo<M: AlignmentMapping>: Alignment;
7780
}
7881

79-
/// The validity invariant of a [`Ptr`][super::Ptr].
80-
pub trait Validity: Sealed {
81-
#[doc(hidden)]
82+
/// The alignment invariant of a [`Ptr`][super::Ptr].
83+
pub trait Alignment:
84+
AlignmentInner<MappedTo<Preserved> = Self>
85+
+ AlignmentInner<MappedTo<Unknown> = Unknown>
86+
+ AlignmentInner<MappedTo<Aligned> = Aligned>
87+
+ Sealed
88+
{
89+
}
90+
impl<
91+
A: AlignmentInner<MappedTo<Preserved> = Self>
92+
+ AlignmentInner<MappedTo<Unknown> = Unknown>
93+
+ AlignmentInner<MappedTo<Aligned> = Aligned>,
94+
> Alignment for A
95+
{
96+
}
97+
98+
#[doc(hidden)]
99+
pub trait ValidityInner: Sealed {
82100
type MappedTo<M: ValidityMapping>: Validity;
83101
}
84102

103+
/// The validity invariant of a [`Ptr`][super::Ptr].
104+
pub trait Validity:
105+
ValidityInner<MappedTo<Preserved> = Self>
106+
+ ValidityInner<MappedTo<Unknown> = Unknown>
107+
+ ValidityInner<MappedTo<AsInitialized> = AsInitialized>
108+
+ ValidityInner<MappedTo<Initialized> = Initialized>
109+
+ ValidityInner<MappedTo<Valid> = Valid>
110+
+ Sealed
111+
{
112+
}
113+
impl<
114+
V: ValidityInner<MappedTo<Preserved> = Self>
115+
+ ValidityInner<MappedTo<Unknown> = Unknown>
116+
+ ValidityInner<MappedTo<AsInitialized> = AsInitialized>
117+
+ ValidityInner<MappedTo<Initialized> = Initialized>
118+
+ ValidityInner<MappedTo<Valid> = Valid>,
119+
> Validity for V
120+
{
121+
}
122+
85123
/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`].
86124
///
87125
/// # Safety
@@ -93,10 +131,10 @@ pub trait Reference: Aliasing + Sealed {}
93131
/// It is unknown whether any invariant holds.
94132
pub enum Unknown {}
95133

96-
impl Alignment for Unknown {
134+
impl AlignmentInner for Unknown {
97135
type MappedTo<M: AlignmentMapping> = M::FromUnknown;
98136
}
99-
impl Validity for Unknown {
137+
impl ValidityInner for Unknown {
100138
type MappedTo<M: ValidityMapping> = M::FromUnknown;
101139
}
102140

@@ -127,10 +165,10 @@ impl Aliasing for Exclusive {
127165
}
128166
impl Reference for Exclusive {}
129167

130-
/// The referent is aligned: for `Ptr<T>`, the referent's address is a
131-
/// multiple of the `T`'s alignment.
168+
/// The referent is aligned: for `Ptr<T>`, the referent's address is a multiple
169+
/// of the `T`'s alignment.
132170
pub enum Aligned {}
133-
impl Alignment for Aligned {
171+
impl AlignmentInner for Aligned {
134172
type MappedTo<M: AlignmentMapping> = M::FromAligned;
135173
}
136174

@@ -161,20 +199,20 @@ impl Alignment for Aligned {
161199
/// enum type, in which case the same rules apply depending on the state of
162200
/// its discriminant, and so on recursively).
163201
pub enum AsInitialized {}
164-
impl Validity for AsInitialized {
202+
impl ValidityInner for AsInitialized {
165203
type MappedTo<M: ValidityMapping> = M::FromAsInitialized;
166204
}
167205

168-
/// The byte ranges in the referent are fully initialized. In other words, if
169-
/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`.
206+
/// The byte ranges in the referent are fully initialized. In other words,
207+
/// if the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`.
170208
pub enum Initialized {}
171-
impl Validity for Initialized {
209+
impl ValidityInner for Initialized {
172210
type MappedTo<M: ValidityMapping> = M::FromInitialized;
173211
}
174212

175213
/// The referent is bit-valid for `T`.
176214
pub enum Valid {}
177-
impl Validity for Valid {
215+
impl ValidityInner for Valid {
178216
type MappedTo<M: ValidityMapping> = M::FromValid;
179217
}
180218

@@ -272,6 +310,12 @@ mod mapping {
272310
type FromValid: Validity;
273311
}
274312

313+
/// A mapping which preserves all invariants as-is.
314+
///
315+
/// `Preserved` is a valid type for any mapping trait ([`AlignmentMapping`]
316+
/// and [`ValidityMapping`]).
317+
pub enum Preserved {}
318+
275319
/// The application of the [`AlignmentMapping`] `M` to the [`Alignment`] `A`.
276320
#[allow(type_alias_bounds)]
277321
pub type MappedAlignment<A: Alignment, M: AlignmentMapping> = A::MappedTo<M>;
@@ -281,12 +325,27 @@ mod mapping {
281325
pub type MappedValidity<V: Validity, M: ValidityMapping> = V::MappedTo<M>;
282326

283327
impl<FromUnknown: Alignment, FromAligned: Alignment> AlignmentMapping
284-
for ((Unknown, FromUnknown), (Shared, FromAligned))
328+
for ((Unknown, FromUnknown), (Aligned, FromAligned))
285329
{
286330
type FromUnknown = FromUnknown;
287331
type FromAligned = FromAligned;
288332
}
289333

334+
impl AlignmentMapping for Unknown {
335+
type FromUnknown = Unknown;
336+
type FromAligned = Unknown;
337+
}
338+
339+
impl AlignmentMapping for Preserved {
340+
type FromUnknown = Unknown;
341+
type FromAligned = Aligned;
342+
}
343+
344+
impl AlignmentMapping for Aligned {
345+
type FromUnknown = Aligned;
346+
type FromAligned = Aligned;
347+
}
348+
290349
impl<
291350
FromUnknown: Validity,
292351
FromAsInitialized: Validity,
@@ -312,4 +371,39 @@ mod mapping {
312371
type FromInitialized = FromInitialized;
313372
type FromValid = Unknown;
314373
}
374+
375+
impl ValidityMapping for Unknown {
376+
type FromUnknown = Unknown;
377+
type FromAsInitialized = Unknown;
378+
type FromInitialized = Unknown;
379+
type FromValid = Unknown;
380+
}
381+
382+
impl ValidityMapping for Preserved {
383+
type FromUnknown = Unknown;
384+
type FromAsInitialized = AsInitialized;
385+
type FromInitialized = Initialized;
386+
type FromValid = Valid;
387+
}
388+
389+
impl ValidityMapping for AsInitialized {
390+
type FromUnknown = AsInitialized;
391+
type FromAsInitialized = AsInitialized;
392+
type FromInitialized = AsInitialized;
393+
type FromValid = AsInitialized;
394+
}
395+
396+
impl ValidityMapping for Initialized {
397+
type FromUnknown = Initialized;
398+
type FromAsInitialized = Initialized;
399+
type FromInitialized = Initialized;
400+
type FromValid = Initialized;
401+
}
402+
403+
impl ValidityMapping for Valid {
404+
type FromUnknown = Valid;
405+
type FromAsInitialized = Valid;
406+
type FromInitialized = Valid;
407+
type FromValid = Valid;
408+
}
315409
}

0 commit comments

Comments
 (0)