Skip to content
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
121 changes: 107 additions & 14 deletions zerocopy/src/pointer/transmute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,35 @@ macro_rules! unsafe_impl_shared_compatible {
}};
}

impl_transitive_transmute_from!(T => MaybeUninit<T> => T => Wrapping<T>);
impl_transitive_transmute_from!(T => Wrapping<T> => T => MaybeUninit<T>);
impl_transitive_size_eq!(T => MaybeUninit<T> => T => Wrapping<T>);

// FIXME: The pinned extractor makes MaybeUninit opaque without retaining its
// storage. These two conditional impls need that model before they can carry
// invariant_proof markers.
//
// SAFETY: The standard library guarantees that `MaybeUninit<T>` and
// `Wrapping<T>` have the same size as `T`. Thus both conditional bounds apply:
// `T: TransmuteFrom<MaybeUninit<T>, Safe, Safe>` preserves bit validity, and
// `Wrapping<T>: TransmuteFrom<T, Safe, Safe>` preserves it again.
unsafe impl<T> TransmuteFrom<MaybeUninit<T>, Safe, Safe> for Wrapping<T>
where
T: TransmuteFrom<MaybeUninit<T>, Safe, Safe>,
Wrapping<T>: TransmuteFrom<T, Safe, Safe>,
{
}

impl_transitive_size_eq!(T => Wrapping<T> => T => MaybeUninit<T>);

// SAFETY: All three types have the same size, as justified above. Thus both
// conditional bounds apply: `T: TransmuteFrom<Wrapping<T>, Safe, Safe>` preserves
// bit validity, and `MaybeUninit<T>: TransmuteFrom<T, Safe, Safe>` preserves it
// again.
unsafe impl<T> TransmuteFrom<Wrapping<T>, Safe, Safe> for MaybeUninit<T>
where
T: TransmuteFrom<Wrapping<T>, Safe, Safe>,
MaybeUninit<T>: TransmuteFrom<T, Safe, Safe>,
{
}

// SAFETY: `ManuallyDrop<T>` has the same size and bit validity as `T` [1], and
// implements `Deref<Target = T>` [2]. Thus, it is already possible for safe
Expand Down Expand Up @@ -336,9 +363,9 @@ impl<T: ?Sized> SizeEq<T> for T {
type CastFrom = cast::IdCast;
}

// SAFETY: Since `Src: IntoBytes`, the set of valid `Src`'s is the set of
// initialized bit patterns, which is exactly the set allowed in the referent of
// any `Initialized` `Ptr`.
// SAFETY: `Src: IntoBytes` guarantees that every valid representation of
// `Src` is entirely initialized. If the referent widths agree, those same
// bytes satisfy `Initialized` for `Dst`.
unsafe impl<Src, Dst> TransmuteFrom<Src, Safe, Initialized> for Dst
where
Src: IntoBytes + ?Sized,
Expand All @@ -347,8 +374,8 @@ where
}

// SAFETY: Since `Dst: FromBytes`, any initialized bit pattern may appear in the
// referent of a `Ptr<Dst, (_, _, Safe)>`. This is exactly equal to the set of
// bit patterns which may appear in the referent of any `Initialized` `Ptr`.
// referent of a `Ptr<Dst, (_, _, Safe)>`. If the referent widths agree,
// `Initialized` source bytes therefore satisfy `Safe` for `Dst`.
unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Safe> for Dst
where
Src: ?Sized,
Expand Down Expand Up @@ -393,14 +420,31 @@ where
//
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
// `T`
unsafe impl<T: ?Sized> TransmuteFrom<T, Safe, Safe> for ManuallyDrop<T> {}

// SAFETY: By the preceding safety proof, `ManuallyDrop<T>` and `T` have the
// same bit validity.
unsafe impl<T: ?Sized> TransmuteFrom<ManuallyDrop<T>, Safe, Safe> for T {}

// SAFETY: By the preceding safety proof, `ManuallyDrop<T>` and `T` have the
// same size in both cast directions.
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => ManuallyDrop<T>) };
const _: () =
unsafe { unsafe_impl_transparent_wrapper_casts_and_size_eq!(pub T: ?Sized => ManuallyDrop<T>) };

// SAFETY:
// - `Unalign<T>` promises to have the same size as `T`.
// - `Unalign<T>` promises to have the same validity as `T`.
unsafe impl<T> TransmuteFrom<T, Safe, Safe> for Unalign<T> {}

// SAFETY: By the preceding safety proof, `Unalign<T>` and `T` have the
// same bit validity.
unsafe impl<T> TransmuteFrom<Unalign<T>, Safe, Safe> for T {}

// SAFETY: By the preceding safety proof, `Unalign<T>` and `T` have the
// same size in both cast directions.
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Unalign<T>) };
const _: () = unsafe { unsafe_impl_transparent_wrapper_casts_and_size_eq!(pub T => Unalign<T>) };
// SAFETY: `Unalign<T>` promises to have the same size and validity as `T`.
// Given `u: &Unalign<T>`, it is already possible to obtain `let t =
// u.try_deref().unwrap()`. Because `Unalign<T>` has the same size as `T`, the
Expand Down Expand Up @@ -432,8 +476,16 @@ const _: () = unsafe { unsafe_impl_shared_compatible!(T => T, Unalign<T>) };
// #[repr(transparent)]
// pub struct Wrapping<T>(pub T);
// ```
unsafe impl<T> TransmuteFrom<T, Safe, Safe> for Wrapping<T> {}

// SAFETY: By the preceding safety proof, `Wrapping<T>` and `T` have the
// same bit validity.
unsafe impl<T> TransmuteFrom<Wrapping<T>, Safe, Safe> for T {}

// SAFETY: By the preceding safety proof, `Wrapping<T>` and `T` have the
// same size in both cast directions.
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Wrapping<T>) };
const _: () = unsafe { unsafe_impl_transparent_wrapper_casts_and_size_eq!(pub T => Wrapping<T>) };

// SAFETY: By the preceding safety proof, `Wrapping<T>` and `T` have the same
// layout and bit validity. Since a `Wrapping<T>`'s `T` field is `pub`, given
Expand All @@ -454,8 +506,17 @@ const _: () = unsafe { unsafe_impl_shared_compatible!(T => T, Wrapping<T>) };
// `UnsafeCell<T>` has the same in-memory representation as its inner type
// `T`. A consequence of this guarantee is that it is possible to convert
// between `T` and `UnsafeCell<T>`.
unsafe impl<T: ?Sized> TransmuteFrom<T, Safe, Safe> for UnsafeCell<T> {}

// SAFETY: By the preceding safety proof, `UnsafeCell<T>` and `T` have the
// same bit validity.
unsafe impl<T: ?Sized> TransmuteFrom<UnsafeCell<T>, Safe, Safe> for T {}

// SAFETY: By the preceding safety proof, `UnsafeCell<T>` and `T` have the
// same size in both cast directions.
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => UnsafeCell<T>) };
const _: () =
unsafe { unsafe_impl_transparent_wrapper_casts_and_size_eq!(pub T: ?Sized => UnsafeCell<T>) };

// SAFETY:
// - `Cell<T>` has the same size as `T` [1].
Expand All @@ -476,11 +537,43 @@ const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => Uns
// `UnsafeCell<T>` has the same in-memory representation as its inner type
// `T`. A consequence of this guarantee is that it is possible to convert
// between `T` and `UnsafeCell<T>`.
unsafe impl<T: ?Sized> TransmuteFrom<T, Safe, Safe> for Cell<T> {}

// SAFETY: By the preceding safety proof, `Cell<T>` and `T` have the
// same bit validity.
unsafe impl<T: ?Sized> TransmuteFrom<Cell<T>, Safe, Safe> for T {}

// SAFETY: By the preceding safety proof, `Cell<T>` and `T` have the
// same size in both cast directions.
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => Cell<T>) };
const _: () =
unsafe { unsafe_impl_transparent_wrapper_casts_and_size_eq!(pub T: ?Sized => Cell<T>) };

impl_transitive_size_eq!(T: ?Sized => Cell<T> => T => UnsafeCell<T>);

// SAFETY: `Cell<T>` and `UnsafeCell<T>` have the same size as `T`, as justified
// above. Thus both conditional bounds apply: `T: TransmuteFrom<Cell<T>, Safe,
// Safe>` preserves bit validity, and `UnsafeCell<T>: TransmuteFrom<T, Safe,
// Safe>` preserves it again.
unsafe impl<T: ?Sized> TransmuteFrom<Cell<T>, Safe, Safe> for UnsafeCell<T>
where
T: TransmuteFrom<Cell<T>, Safe, Safe>,
UnsafeCell<T>: TransmuteFrom<T, Safe, Safe>,
{
}

impl_transitive_size_eq!(T: ?Sized => UnsafeCell<T> => T => Cell<T>);

impl_transitive_transmute_from!(T: ?Sized => Cell<T> => T => UnsafeCell<T>);
impl_transitive_transmute_from!(T: ?Sized => UnsafeCell<T> => T => Cell<T>);
// SAFETY: All three types have the same size, as justified above. Thus both
// conditional bounds apply: `T: TransmuteFrom<UnsafeCell<T>, Safe, Safe>`
// preserves bit validity, and `Cell<T>: TransmuteFrom<T, Safe, Safe>` preserves
// it again.
unsafe impl<T: ?Sized> TransmuteFrom<UnsafeCell<T>, Safe, Safe> for Cell<T>
where
T: TransmuteFrom<UnsafeCell<T>, Safe, Safe>,
Cell<T>: TransmuteFrom<T, Safe, Safe>,
{
}

// SAFETY: `MaybeUninit<T>` has no validity requirements. Currently this is not
// explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation
Expand Down
32 changes: 8 additions & 24 deletions zerocopy/src/util/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,26 +743,20 @@ macro_rules! define_cast {
};
}

/// Implements `TransmuteFrom` and `SizeEq` for `T` and `$wrapper<T>`.
/// Implements casts and `SizeEq` for `T` and `$wrapper<T>`.
///
/// # Safety
///
/// `T` and `$wrapper<T>` must have the same bit validity, and must have the
/// same size in the sense of `CastExact` (specifically, both a
/// `T`-to-`$wrapper<T>` cast and a `$wrapper<T>`-to-`T` cast must be
/// size-preserving).
macro_rules! unsafe_impl_for_transparent_wrapper {
/// `T` and `$wrapper<T>` must have the same size in the sense of `CastExact`
/// (specifically, both a `T`-to-`$wrapper<T>` cast and a `$wrapper<T>`-to-`T`
/// cast must be size-preserving).
macro_rules! unsafe_impl_transparent_wrapper_casts_and_size_eq {
($vis:vis T $(: ?$optbound:ident)? => $wrapper:ident<T>) => {{
crate::util::macros::__unsafe();

use crate::pointer::{TransmuteFrom, cast::{CastExact, TransitiveProject}, SizeEq, invariant::Safe};
use crate::pointer::{cast::{CastExact, TransitiveProject}, SizeEq};
use crate::wrappers::ReadOnly;

// SAFETY: The caller promises that `T` and `$wrapper<T>` have the same
// bit validity.
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<T, Safe, Safe> for $wrapper<T> {}
// SAFETY: See previous safety comment.
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<$wrapper<T>, Safe, Safe> for T {}
// SAFETY: The caller promises that a `T` to `$wrapper<T>` cast is
// size-preserving.
define_cast!(unsafe { $vis CastToWrapper<T $(: ?$optbound)? > = T => $wrapper<T> });
Expand Down Expand Up @@ -815,10 +809,10 @@ macro_rules! unsafe_impl_for_transparent_wrapper {
}};
}

macro_rules! impl_transitive_transmute_from {
macro_rules! impl_transitive_size_eq {
($($tyvar:ident $(: ?$optbound:ident)?)? => $t:ty => $u:ty => $v:ty) => {
const _: () = {
use crate::pointer::{TransmuteFrom, SizeEq, invariant::Safe};
use crate::pointer::SizeEq;
Comment on lines 814 to +815

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The macro impl_transitive_size_eq! currently relies on cast being imported in the scope where the macro is invoked. To make the macro fully self-contained and hygienic, we should explicitly import cast inside the local const _: () block.

Suggested change
const _: () = {
use crate::pointer::{TransmuteFrom, SizeEq, invariant::Safe};
use crate::pointer::SizeEq;
const _: () = {
use crate::pointer::{cast, SizeEq};


impl<$($tyvar $(: ?$optbound)?)?> SizeEq<$t> for $v
where
Expand All @@ -831,16 +825,6 @@ macro_rules! impl_transitive_transmute_from {
<$v as SizeEq<$u>>::CastFrom
>;
}

// SAFETY: Since `$u: TransmuteFrom<$t, Safe, Safe>`, it is sound to
// transmute a bit-valid `$t` to a bit-valid `$u`. Since `$v:
// TransmuteFrom<$u, Safe, Safe>`, it is sound to transmute that
// bit-valid `$u` to a bit-valid `$v`.
unsafe impl<$($tyvar $(: ?$optbound)?)?> TransmuteFrom<$t, Safe, Safe> for $v
where
$u: TransmuteFrom<$t, Safe, Safe>,
$v: TransmuteFrom<$u, Safe, Safe>,
{}
};
};
}
Expand Down
Loading