Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pointer][transmute] Support generic TransmuteFrom #1910

Open
wants to merge 1 commit into
base: I1ac2ae177a235083e33b09fc848423220d3da042
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 39 additions & 39 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,13 +443,13 @@ mod atomics {
use super::*;

macro_rules! impl_traits_for_atomics {
($($atomics:ident),* $(,)?) => {
($($atomics:ident[$repr:ty]),* $(,)?) => {
$(
impl_known_layout!($atomics);
impl_for_transparent_wrapper!(=> TryFromBytes for $atomics);
impl_for_transparent_wrapper!(=> FromZeros for $atomics);
impl_for_transparent_wrapper!(=> FromBytes for $atomics);
impl_for_transparent_wrapper!(=> IntoBytes for $atomics);
impl_for_transmute_from!(=> TryFromBytes for $atomics[UnsafeCell<$repr>]);
impl_for_transmute_from!(=> FromZeros for $atomics[UnsafeCell<$repr>]);
impl_for_transmute_from!(=> FromBytes for $atomics[UnsafeCell<$repr>]);
impl_for_transmute_from!(=> IntoBytes for $atomics[UnsafeCell<$repr>]);
)*
};
}
Expand All @@ -461,13 +461,13 @@ mod atomics {

use super::*;

impl_traits_for_atomics!(AtomicU8, AtomicI8);
impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]);

impl_known_layout!(AtomicBool);

impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool);
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool);
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool);
impl_for_transmute_from!(=> TryFromBytes for AtomicBool[UnsafeCell<bool>]);
impl_for_transmute_from!(=> FromZeros for AtomicBool[UnsafeCell<bool>]);
impl_for_transmute_from!(=> IntoBytes for AtomicBool[UnsafeCell<bool>]);

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

Expand All @@ -508,13 +508,13 @@ mod atomics {

use super::*;

impl_traits_for_atomics!(AtomicU16, AtomicI16);
impl_traits_for_atomics!(AtomicU16[u16], AtomicI16[i16]);

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

Expand All @@ -525,13 +525,13 @@ mod atomics {

use super::*;

impl_traits_for_atomics!(AtomicU32, AtomicI32);
impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]);

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

Expand All @@ -542,13 +542,13 @@ mod atomics {

use super::*;

impl_traits_for_atomics!(AtomicU64, AtomicI64);
impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]);

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

Expand All @@ -559,21 +559,21 @@ mod atomics {

use super::*;

impl_traits_for_atomics!(AtomicUsize, AtomicIsize);
impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]);

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

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

safety_comment! {
/// SAFETY:
/// This passes an atomic type and that type's native equivalent, as
/// required by the macro safety preconditions.
unsafe_impl_transparent_wrapper_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
unsafe_impl_transparent_wrapper_for_atomic!(T => AtomicPtr<T> [*mut T]);
unsafe_impl_transmute_from_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr<T> [*mut T]);
}
}
}
Expand Down Expand Up @@ -603,12 +603,12 @@ safety_comment! {
assert_unaligned!(PhantomData<()>, PhantomData<u8>, PhantomData<u64>);
}

impl_for_transparent_wrapper!(T: Immutable => Immutable for Wrapping<T>);
impl_for_transparent_wrapper!(T: TryFromBytes => TryFromBytes for Wrapping<T>);
impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping<T>);
impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping<T>);
impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping<T>);
impl_for_transparent_wrapper!(T: Unaligned => Unaligned for Wrapping<T>);
impl_for_transmute_from!(T: Immutable => Immutable for Wrapping<T>[T]);
impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping<T>[T]);
impl_for_transmute_from!(T: FromZeros => FromZeros for Wrapping<T>[T]);
impl_for_transmute_from!(T: FromBytes => FromBytes for Wrapping<T>[T]);
impl_for_transmute_from!(T: IntoBytes => IntoBytes for Wrapping<T>[T]);
impl_for_transmute_from!(T: Unaligned => Unaligned for Wrapping<T>[T]);
assert_unaligned!(Wrapping<()>, Wrapping<u8>);

safety_comment! {
Expand All @@ -620,22 +620,22 @@ safety_comment! {
unsafe_impl!(T => FromBytes for MaybeUninit<T>);
}

impl_for_transparent_wrapper!(T: Immutable => Immutable for MaybeUninit<T>);
impl_for_transparent_wrapper!(T: Unaligned => Unaligned for MaybeUninit<T>);
impl_for_transmute_from!(T: Immutable => Immutable for MaybeUninit<T>[T]);
impl_for_transmute_from!(T: Unaligned => Unaligned for MaybeUninit<T>[T]);
assert_unaligned!(MaybeUninit<()>, MaybeUninit<u8>);

impl_for_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>);
impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T>);
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>);
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>);
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>);
impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>);
impl_for_transmute_from!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>[T]);
impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T>[T]);
impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>[T]);
impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>[T]);
impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>[T]);
impl_for_transmute_from!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>[T]);
assert_unaligned!(ManuallyDrop<()>, ManuallyDrop<u8>);

impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>);
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>);
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>);
impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>);
impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>[T]);
impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>[T]);
impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>[T]);
impl_for_transmute_from!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>[T]);
assert_unaligned!(UnsafeCell<()>, UnsafeCell<u8>);

// SAFETY: See safety comment in `is_bit_valid` impl.
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2720,7 +2720,7 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
// We use `from_mut` despite not mutating via `c_ptr` so that we don't need
// to add a `T: Immutable` bound.
let c_ptr = Ptr::from_mut(&mut candidate);
let c_ptr = c_ptr.transparent_wrapper_into_inner();
let c_ptr = c_ptr.transmute::<_, pointer::transmute::BecauseBidirectional>();
// SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from
// `candidate`, which the caller promises is entirely initialized.
let c_ptr = unsafe { c_ptr.assume_validity::<invariant::Initialized>() };
Expand Down
130 changes: 112 additions & 18 deletions src/pointer/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl<A: Aliasing, AA: Alignment, V: Validity> Invariants for (A, AA, V) {
/// The aliasing invariant of a [`Ptr`][super::Ptr].
///
/// All aliasing invariants must permit reading from the bytes of a pointer's
/// referent which are not covered by [`UnsafeCell`]s.
/// referent which are not covered by [`UnsafeCell`](core::cell::UnsafeCell)s.
pub trait Aliasing: Sealed {
/// Is `Self` [`Exclusive`]?
#[doc(hidden)]
Expand All @@ -70,18 +70,56 @@ pub trait Aliasing: Sealed {
type Variance<'a, T: 'a + ?Sized>;
}

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

/// The validity invariant of a [`Ptr`][super::Ptr].
pub trait Validity: Sealed {
#[doc(hidden)]
/// The alignment invariant of a [`Ptr`][super::Ptr].
pub trait Alignment:
AlignmentInner<MappedTo<Preserved> = Self>
+ AlignmentInner<MappedTo<Unknown> = Unknown>
+ AlignmentInner<MappedTo<Aligned> = Aligned>
+ Sealed
{
}
impl<
A: AlignmentInner<MappedTo<Preserved> = Self>
+ AlignmentInner<MappedTo<Unknown> = Unknown>
+ AlignmentInner<MappedTo<Aligned> = Aligned>,
> Alignment for A
{
}

#[doc(hidden)]
pub trait ValidityInner: Sealed {
type MappedTo<M: ValidityMapping>: Validity;
}

/// The validity invariant of a [`Ptr`][super::Ptr].
pub trait Validity:
ValidityInner<MappedTo<Preserved> = Self>
+ ValidityInner<MappedTo<Unknown> = Unknown>
+ ValidityInner<MappedTo<AsInitialized> = AsInitialized>
+ ValidityInner<MappedTo<Initialized> = Initialized>
+ ValidityInner<MappedTo<Valid> = Valid>
+ Sealed
{
}
impl<
V: ValidityInner<MappedTo<Preserved> = Self>
+ ValidityInner<MappedTo<Unknown> = Unknown>
+ ValidityInner<MappedTo<AsInitialized> = AsInitialized>
+ ValidityInner<MappedTo<Initialized> = Initialized>
+ ValidityInner<MappedTo<Valid> = Valid>,
> Validity for V
{
}

/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`].
///
/// # Safety
Expand All @@ -93,10 +131,10 @@ pub trait Reference: Aliasing + Sealed {}
/// It is unknown whether any invariant holds.
pub enum Unknown {}

impl Alignment for Unknown {
impl AlignmentInner for Unknown {
type MappedTo<M: AlignmentMapping> = M::FromUnknown;
}
impl Validity for Unknown {
impl ValidityInner for Unknown {
type MappedTo<M: ValidityMapping> = M::FromUnknown;
}

Expand Down Expand Up @@ -127,10 +165,10 @@ impl Aliasing for Exclusive {
}
impl Reference for Exclusive {}

/// The referent is aligned: for `Ptr<T>`, the referent's address is a
/// multiple of the `T`'s alignment.
/// The referent is aligned: for `Ptr<T>`, the referent's address is a multiple
/// of the `T`'s alignment.
pub enum Aligned {}
impl Alignment for Aligned {
impl AlignmentInner for Aligned {
type MappedTo<M: AlignmentMapping> = M::FromAligned;
}

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

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

/// The referent is bit-valid for `T`.
pub enum Valid {}
impl Validity for Valid {
impl ValidityInner for Valid {
type MappedTo<M: ValidityMapping> = M::FromValid;
}

Expand Down Expand Up @@ -272,6 +310,12 @@ mod mapping {
type FromValid: Validity;
}

/// A mapping which preserves all invariants as-is.
///
/// `Preserved` is a valid type for any mapping trait ([`AlignmentMapping`]
/// and [`ValidityMapping`]).
pub enum Preserved {}

/// The application of the [`AlignmentMapping`] `M` to the [`Alignment`] `A`.
#[allow(type_alias_bounds)]
pub type MappedAlignment<A: Alignment, M: AlignmentMapping> = A::MappedTo<M>;
Expand All @@ -281,12 +325,27 @@ mod mapping {
pub type MappedValidity<V: Validity, M: ValidityMapping> = V::MappedTo<M>;

impl<FromUnknown: Alignment, FromAligned: Alignment> AlignmentMapping
for ((Unknown, FromUnknown), (Shared, FromAligned))
for ((Unknown, FromUnknown), (Aligned, FromAligned))
{
type FromUnknown = FromUnknown;
type FromAligned = FromAligned;
}

impl AlignmentMapping for Unknown {
type FromUnknown = Unknown;
type FromAligned = Unknown;
}

impl AlignmentMapping for Preserved {
type FromUnknown = Unknown;
type FromAligned = Aligned;
}

impl AlignmentMapping for Aligned {
type FromUnknown = Aligned;
type FromAligned = Aligned;
}

impl<
FromUnknown: Validity,
FromAsInitialized: Validity,
Expand All @@ -312,4 +371,39 @@ mod mapping {
type FromInitialized = FromInitialized;
type FromValid = Unknown;
}

impl ValidityMapping for Unknown {
type FromUnknown = Unknown;
type FromAsInitialized = Unknown;
type FromInitialized = Unknown;
type FromValid = Unknown;
}

impl ValidityMapping for Preserved {
type FromUnknown = Unknown;
type FromAsInitialized = AsInitialized;
type FromInitialized = Initialized;
type FromValid = Valid;
}

impl ValidityMapping for AsInitialized {
type FromUnknown = AsInitialized;
type FromAsInitialized = AsInitialized;
type FromInitialized = AsInitialized;
type FromValid = AsInitialized;
}

impl ValidityMapping for Initialized {
type FromUnknown = Initialized;
type FromAsInitialized = Initialized;
type FromInitialized = Initialized;
type FromValid = Initialized;
}

impl ValidityMapping for Valid {
type FromUnknown = Valid;
type FromAsInitialized = Valid;
type FromInitialized = Valid;
type FromValid = Valid;
}
}
Loading
Loading