Skip to content

Commit

Permalink
[pointer][WIP] Transmute
Browse files Browse the repository at this point in the history
gherrit-pr-id: Iad14813bc6d933312bc8d7a1ddcf1aafc7126938
  • Loading branch information
joshlf committed Mar 3, 2025
1 parent daf3a21 commit 3b22cad
Show file tree
Hide file tree
Showing 11 changed files with 433 additions and 97 deletions.
32 changes: 21 additions & 11 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,10 +417,11 @@ mod atomics {
use super::*;

macro_rules! impl_traits_for_atomics {
($($atomics:ident),* $(,)?) => {
($($atomics:ident [$primitives:ident]),* $(,)?) => {
$(
impl_known_layout!($atomics);
impl_for_transparent_wrapper!(=> TryFromBytes for $atomics);
impl_for_transmute_from!(=> TryFromBytes for $atomics [UnsafeCell<$primitives>]);
// 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);
Expand All @@ -435,11 +436,12 @@ 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!(=> TryFromBytes for AtomicBool);
impl_for_transmute_from!(=> TryFromBytes for AtomicBool [UnsafeCell<bool>]);
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool);
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool);

Expand Down Expand Up @@ -472,6 +474,7 @@ mod atomics {
/// 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 @@ -482,13 +485,14 @@ 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 @@ -499,13 +503,14 @@ 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 @@ -516,13 +521,14 @@ 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 @@ -533,13 +539,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 => TryFromBytes for AtomicPtr<T>);
impl_for_transmute_from!(T => TryFromBytes for AtomicPtr<T> [UnsafeCell<*mut T>]);
impl_for_transparent_wrapper!(T => FromZeros for AtomicPtr<T>);

safety_comment! {
Expand All @@ -548,6 +555,9 @@ mod atomics {
/// 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 @@ -578,7 +588,7 @@ safety_comment! {
}

impl_for_transparent_wrapper!(T: Immutable => Immutable for Wrapping<T>);
impl_for_transparent_wrapper!(T: TryFromBytes => TryFromBytes for Wrapping<T>);
impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping<T>[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>);
Expand All @@ -599,7 +609,7 @@ impl_for_transparent_wrapper!(T: Unaligned => Unaligned for CoreMaybeUninit<T>);
assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit<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_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T> [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>);
Expand Down
29 changes: 20 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,10 @@ use core::{
#[cfg(feature = "std")]
use std::io;

use crate::pointer::invariant::{self, BecauseExclusive};
use crate::pointer::{
invariant::{self, BecauseExclusive},
BecauseFoo,
};

#[cfg(any(feature = "alloc", test))]
extern crate alloc;
Expand Down Expand Up @@ -805,6 +808,14 @@ pub unsafe trait KnownLayout {
// resulting size would not fit in a `usize`.
meta.size_for_metadata(Self::LAYOUT)
}

fn cast_from_raw<P: KnownLayout<PointerMetadata = Self::PointerMetadata> + ?Sized>(
ptr: NonNull<P>,
) -> NonNull<Self> {
let data = ptr.cast::<u8>();
let meta = P::pointer_to_metadata(ptr.as_ptr());
Self::raw_from_ptr_len(data, meta)
}
}

/// The metadata associated with a [`KnownLayout`] type.
Expand Down Expand Up @@ -2843,15 +2854,15 @@ 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();
// SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from
// `candidate`, which the caller promises is entirely initialized. Since
// `candidate` is a `MaybeUninit`, it has no validity requirements, and so
// no values written to `c_ptr` can violate its validity. Since `c_ptr` has
// `Exclusive` aliasing, no mutations may happen except via `c_ptr` so long
// as it is live, so we don't need to worry about the fact that `c_ptr` may
// have more restricted validity than `candidate`.
// no values written to an `Initialized` `c_ptr` can violate its validity.
// Since `c_ptr` has `Exclusive` aliasing, no mutations may happen except
// via `c_ptr` so long as it is live, so we don't need to worry about the
// fact that `c_ptr` may have more restricted validity than `candidate`.
let c_ptr = unsafe { c_ptr.assume_validity::<invariant::Initialized>() };
let c_ptr = c_ptr.transmute();

// This call may panic. If that happens, it doesn't cause any soundness
// issues, as we have not generated any invalid state which we need to
Expand All @@ -2861,7 +2872,7 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
// calling `try_into_valid` (and thus `is_bit_valid`) with a shared
// pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic
// condition will not happen.
if !T::is_bit_valid(c_ptr.forget_aligned()) {
if !util::SizedKnownLayout::<T>::is_bit_valid(c_ptr.forget_aligned()) {
return Err(ValidityError::new(source).into());
}

Expand Down Expand Up @@ -4258,7 +4269,7 @@ pub unsafe trait FromBytes: FromZeros {
let source = Ptr::from_mut(source);
let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count));
match maybe_slf {
Ok(slf) => Ok(slf.bikeshed_recall_valid().as_mut()),
Ok(slf) => Ok(slf.bikeshed_recall_valid::<(_, (_, BecauseExclusive))>().as_mut()),
Err(err) => Err(err.map_src(|s| s.as_mut())),
}
}
Expand Down Expand Up @@ -4728,7 +4739,7 @@ fn ref_from_prefix_suffix<T: FromBytes + KnownLayout + Immutable + ?Sized>(
/// If there are insufficient bytes, or if that affix of `source` is not
/// appropriately aligned, this returns `Err`.
#[inline(always)]
fn mut_from_prefix_suffix<T: FromBytes + KnownLayout + ?Sized>(
fn mut_from_prefix_suffix<T: FromBytes + IntoBytes + KnownLayout + ?Sized>(
source: &mut [u8],
meta: Option<T::PointerMetadata>,
cast_type: CastType,
Expand Down
8 changes: 6 additions & 2 deletions src/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ mod inner;
#[doc(hidden)]
pub mod invariant;
mod ptr;
mod transmute;

#[doc(hidden)]
pub use invariant::{BecauseExclusive, BecauseImmutable, Read};
pub(crate) use transmute::*;
#[doc(hidden)]
pub use ptr::Ptr;
pub use {
invariant::{BecauseExclusive, BecauseImmutable, Read},
ptr::Ptr,
};

use crate::Unaligned;

Expand Down
Loading

0 comments on commit 3b22cad

Please sign in to comment.