Skip to content

Commit

Permalink
[WIP][pointer] Support generic TransmuteFrom
Browse files Browse the repository at this point in the history
Makes progress on #1122
  • Loading branch information
joshlf committed Oct 13, 2024
1 parent a2a4c7f commit 528f3e3
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 426 deletions.
66 changes: 33 additions & 33 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_transparent_wrapper!(=> TryFromBytes for $atomics[UnsafeCell<$repr>]);
impl_for_transparent_wrapper!(=> FromZeros for $atomics[UnsafeCell<$repr>]);
impl_for_transparent_wrapper!(=> FromBytes for $atomics[UnsafeCell<$repr>]);
impl_for_transparent_wrapper!(=> 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_transparent_wrapper!(=> TryFromBytes for AtomicBool[UnsafeCell<bool>]);
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool[UnsafeCell<bool>]);
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool[UnsafeCell<bool>]);

safety_comment! {
/// SAFETY:
Expand Down Expand Up @@ -508,7 +508,7 @@ mod atomics {

use super::*;

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

safety_comment! {
/// SAFETY:
Expand All @@ -525,7 +525,7 @@ mod atomics {

use super::*;

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

safety_comment! {
/// SAFETY:
Expand All @@ -542,7 +542,7 @@ mod atomics {

use super::*;

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

safety_comment! {
/// SAFETY:
Expand All @@ -559,14 +559,14 @@ 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_transparent_wrapper!(T => TryFromBytes for AtomicPtr<T>[UnsafeCell<*mut T>]);
impl_for_transparent_wrapper!(T => FromZeros for AtomicPtr<T>[UnsafeCell<*mut T>]);

safety_comment! {
/// SAFETY:
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_transparent_wrapper!(T: Immutable => Immutable for Wrapping<T>[T]);
impl_for_transparent_wrapper!(T: TryFromBytes => TryFromBytes for Wrapping<T>[T]);
impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping<T>[T]);
impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping<T>[T]);
impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping<T>[T]);
impl_for_transparent_wrapper!(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_transparent_wrapper!(T: Immutable => Immutable for MaybeUninit<T>[T]);
impl_for_transparent_wrapper!(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_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>[T]);
impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T>[T]);
impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>[T]);
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>[T]);
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>[T]);
impl_for_transparent_wrapper!(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_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>[T]);
impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>[T]);
impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>[T]);
impl_for_transparent_wrapper!(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 @@ -2718,7 +2718,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();
// 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
143 changes: 109 additions & 34 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,24 @@ pub mod invariant {
mod mapping {
use super::*;

pub trait Mapping {
type Aliasing: AliasingMapping;
type Alignment: AlignmentMapping;
type Validity: ValidityMapping;
}

impl<A: AliasingMapping, AA: AlignmentMapping, V: ValidityMapping> Mapping for (A, AA, V) {
type Aliasing = A;
type Alignment = AA;
type Validity = V;
}

impl Mapping for Preserved {
type Aliasing = Preserved;
type Alignment = Preserved;
type Validity = Preserved;
}

pub trait AliasingMapping {
type FromAny: Aliasing;
type FromShared: Aliasing;
Expand All @@ -360,6 +378,16 @@ pub mod invariant {
type FromValid: Validity;
}

// TODO: Better name?
pub enum Preserved {}

#[allow(type_alias_bounds)]
pub type Mapped<I: Invariants, M: Mapping> = (
MappedAliasing<I::Aliasing, M::Aliasing>,
MappedAlignment<I::Alignment, M::Alignment>,
MappedValidity<I::Validity, M::Validity>,
);

#[allow(type_alias_bounds)]
pub type MappedAliasing<I: Aliasing, M: AliasingMapping> = I::MappedTo<M>;

Expand All @@ -377,13 +405,42 @@ pub mod invariant {
type FromExclusive = FromExclusive;
}

pub enum UnsafeCellMismatch {}

impl AliasingMapping for UnsafeCellMismatch {
type FromAny = Any;
type FromShared = Any;
type FromExclusive = Exclusive;
}

impl AliasingMapping for Preserved {
type FromAny = Any;
type FromShared = Shared;
type FromExclusive = Exclusive;
}

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

impl AlignmentMapping for Any {
type FromAny = Any;
type FromAligned = Any;
}

impl AlignmentMapping for Preserved {
type FromAny = Any;
type FromAligned = Aligned;
}

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

impl<
FromAny: Validity,
FromAsInitialized: Validity,
Expand All @@ -409,6 +466,41 @@ pub mod invariant {
type FromInitialized = FromInitialized;
type FromValid = Any;
}

impl ValidityMapping for Any {
type FromAny = Any;
type FromAsInitialized = Any;
type FromInitialized = Any;
type FromValid = Any;
}

impl ValidityMapping for Preserved {
type FromAny = Any;
type FromAsInitialized = AsInitialized;
type FromInitialized = Initialized;
type FromValid = Valid;
}

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

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

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

Expand Down Expand Up @@ -458,9 +550,7 @@ mod _external {
/// Methods for converting to and from `Ptr` and Rust's safe reference types.
mod _conversions {
use super::*;
use crate::pointer::transmute::{
AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance,
};
use crate::pointer::transmute::TransmuteFrom;

/// `&'a T` → `Ptr<'a, T>`
impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)>
Expand Down Expand Up @@ -651,25 +741,22 @@ mod _conversions {
}
}

/// `Ptr<'a, T = Wrapper<U>>` → `Ptr<'a, U>`
/// `Ptr<'a, T>` → `Ptr<'a, U>`
impl<'a, T, I> Ptr<'a, T, I>
where
T: 'a + TransparentWrapper<I, UnsafeCellVariance = Covariant> + ?Sized,
T: 'a + ?Sized,
I: Invariants,
{
/// Converts `self` to a transparent wrapper type into a `Ptr` to the
/// wrapped inner type.
pub(crate) fn transparent_wrapper_into_inner(
self,
) -> Ptr<
'a,
T::Inner,
(
I::Aliasing,
<T::AlignmentVariance as AlignmentVariance<I::Alignment>>::Applied,
<T::ValidityVariance as ValidityVariance<I::Validity>>::Applied,
),
> {
// (
// Mapped<I, U::Mapping>,
// // I::Aliasing,
// // MappedAlignment<I::Alignment, U::AlignmentMapping>,
// // MappedValidity<I::Validity, U::ValidityMapping>,
// ),
pub(crate) fn transmute<U>(self) -> Ptr<'a, U, Mapped<I, U::Mapping>>
where
U: ?Sized + TransmuteFrom<T>,
{
// SAFETY:
// - By invariant on `TransparentWrapper::cast_into_inner`:
// - This cast preserves address and referent size, and thus the
Expand All @@ -680,20 +767,8 @@ mod _conversions {
// byte ranges. Since `p` and the returned pointer address the
// same byte range, they refer to `UnsafeCell`s at the same byte
// ranges.
let c = unsafe { self.cast_unsized(|p| T::cast_into_inner(p)) };
// SAFETY: By invariant on `TransparentWrapper`, since `self`
// satisfies the alignment invariant `I::Alignment`, `c` (of type
// `T::Inner`) satisfies the given "applied" alignment invariant.
let c = unsafe {
c.assume_alignment::<<T::AlignmentVariance as AlignmentVariance<I::Alignment>>::Applied>()
};
// SAFETY: By invariant on `TransparentWrapper`, since `self`
// satisfies the validity invariant `I::Validity`, `c` (of type
// `T::Inner`) satisfies the given "applied" validity invariant.
let c = unsafe {
c.assume_validity::<<T::ValidityVariance as ValidityVariance<I::Validity>>::Applied>()
};
c
let ptr = unsafe { self.cast_unsized(|p| U::cast_from(p)) };
unsafe { ptr.assume_invariants() }
}
}

Expand Down Expand Up @@ -779,7 +854,7 @@ mod _transitions {
/// # Safety
///
/// The caller promises that `self` satisfies the invariants `H`.
const unsafe fn assume_invariants<H: Invariants>(self) -> Ptr<'a, T, H> {
pub(super) const unsafe fn assume_invariants<H: Invariants>(self) -> Ptr<'a, T, H> {
// SAFETY: The caller has promised to satisfy all parameterized
// invariants of `Ptr`. `Ptr`'s other invariants are satisfied
// by-contract by the source `Ptr`.
Expand Down
Loading

0 comments on commit 528f3e3

Please sign in to comment.