Skip to content

[WIP] Generalize SizeEq to SizeCompat #2472

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

Open
wants to merge 1 commit into
base: Ib4bc62202e0b3b09d155333b525087f7aa8f02c2
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
57 changes: 33 additions & 24 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ const _: () = unsafe {
*byte.unaligned_as_ref() < 2
})
};
impl_size_eq!(bool, u8);

impl_size_compat!(bool, u8);

// SAFETY:
// - `Immutable`: `char` self-evidently does not contain any `UnsafeCell`s.
Expand Down Expand Up @@ -140,7 +141,7 @@ const _: () = unsafe {
});
};

impl_size_eq!(char, Unalign<u32>);
impl_size_compat!(char, Unalign<u32>);

// SAFETY: Per the Reference [1], `str` has the same layout as `[u8]`.
// - `Immutable`: `[u8]` does not contain any `UnsafeCell`s.
Expand Down Expand Up @@ -173,14 +174,13 @@ const _: () = unsafe {
})
};

impl_size_eq!(str, [u8]);
impl_size_compat!(str, [u8]);

macro_rules! unsafe_impl_try_from_bytes_for_nonzero {
($($nonzero:ident[$prim:ty]),*) => {
$(
unsafe_impl!(=> TryFromBytes for $nonzero; |n| {
impl_size_eq!($nonzero, Unalign<$prim>);

impl_size_compat!($nonzero, Unalign<$prim>);
let n = n.transmute::<Unalign<$prim>, invariant::Valid, _>();
$nonzero::new(n.read_unaligned().into_inner()).is_some()
});
Expand Down Expand Up @@ -396,63 +396,72 @@ mod atomics {
($($($tyvar:ident)? => $atomic:ty [$prim:ty]),*) => {{
crate::util::macros::__unsafe();

use core::cell::UnsafeCell;
use crate::pointer::{PtrInner, SizeEq, TransmuteFrom, invariant::Valid};
use core::{cell::UnsafeCell};
use crate::pointer::{TransmuteFrom, PtrInner, SizeCompat, invariant::Valid};

$(
// SAFETY: The caller promised that `$atomic` and `$prim` have
// the same size and bit validity.
// SAFETY: The caller promised that `$atomic` and `$prim`
// have the same size and bit validity. As a result of size
// equality, both impls of `SizeCompat::cast_from_raw`
// preserve referent size exactly.
unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for $prim {}
// SAFETY: The caller promised that `$atomic` and `$prim` have
// the same size and bit validity.
// SAFETY: The caller promised that `$atomic` and `$prim`
// have the same size and bit validity. As a result of size
// equality, both impls of `SizeCompat::cast_from_raw`
// preserve referent size exactly.
unsafe impl<$($tyvar)?> TransmuteFrom<$prim, Valid, Valid> for $atomic {}

// SAFETY: The caller promised that `$atomic` and `$prim` have
// the same size.
unsafe impl<$($tyvar)?> SizeEq<$atomic> for $prim {
// SAFETY: See inline safety comment.
unsafe impl<$($tyvar)?> SizeCompat<$atomic> for $prim {
#[inline]
fn cast_from_raw(a: PtrInner<'_, $atomic>) -> PtrInner<'_, $prim> {
// SAFETY: The caller promised that `$atomic` and
// `$prim` have the same size. Thus, this cast preserves
// SAFETY: The caller promised that `$atomic` and `$prim`
// have the same size. Thus, this cast preserves
// address, referent size, and provenance.
unsafe { cast!(a) }
}
}
// SAFETY: See previous safety comment.
unsafe impl<$($tyvar)?> SizeEq<$prim> for $atomic {
unsafe impl<$($tyvar)?> SizeCompat<$prim> for $atomic {
#[inline]
fn cast_from_raw(p: PtrInner<'_, $prim>) -> PtrInner<'_, $atomic> {
// SAFETY: See previous safety comment.
unsafe { cast!(p) }
}
}
// SAFETY: The caller promised that `$atomic` and `$prim` have
// the same size. `UnsafeCell<T>` has the same size as `T` [1].

// SAFETY: The caller promised that `$atomic` and `$prim`
// have the same size. `UnsafeCell<T>` has the same size as
// `T` [1]. Thus, this cast preserves address, referent
// size, and provenance.
//
// [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.UnsafeCell.html#memory-layout:
//
// `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<$($tyvar)?> SizeEq<$atomic> for UnsafeCell<$prim> {
unsafe impl<$($tyvar)?> SizeCompat<$atomic> for UnsafeCell<$prim> {
#[inline]
fn cast_from_raw(a: PtrInner<'_, $atomic>) -> PtrInner<'_, UnsafeCell<$prim>> {
// SAFETY: See previous safety comment.
unsafe { cast!(a) }
}
}
// SAFETY: See previous safety comment.
unsafe impl<$($tyvar)?> SizeEq<UnsafeCell<$prim>> for $atomic {
unsafe impl<$($tyvar)?> SizeCompat<UnsafeCell<$prim>> for $atomic {
#[inline]
fn cast_from_raw(p: PtrInner<'_, UnsafeCell<$prim>>) -> PtrInner<'_, $atomic> {
// SAFETY: See previous safety comment.
unsafe { cast!(p) }
}
}

// SAFETY: The caller promised that `$atomic` and `$prim` have
// the same bit validity. `UnsafeCell<T>` has the same bit
// validity as `T` [1].
// SAFETY: The caller promised that `$atomic` and `$prim`
// have the same bit validity. `UnsafeCell<T>` has the same
// bit validity as `T` [1]. `UnsafeCell<T>` also has the
// same size as `T` [1], and so both impls of
// `SizeCompat::cast_from_raw` preserve referent size
// exactly.
//
// [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.UnsafeCell.html#memory-layout:
//
Expand Down
6 changes: 3 additions & 3 deletions src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,15 +612,15 @@ pub(crate) use cast_from_raw::cast_from_raw;
mod cast_from_raw {
use crate::{pointer::PtrInner, *};

/// Implements [`<Dst as SizeEq<Src>>::cast_from_raw`][cast_from_raw].
/// Implements [`<Dst as SizeCompat<Src>>::cast_from_raw`][cast_from_raw].
///
/// # PME
///
/// Generates a post-monomorphization error if it is not possible to satisfy
/// the soundness conditions of [`SizeEq::cast_from_raw`][cast_from_raw]
/// the soundness conditions of [`SizeCompat::cast_from_raw`][cast_from_raw]
/// for `Src` and `Dst`.
///
/// [cast_from_raw]: crate::pointer::SizeEq::cast_from_raw
/// [cast_from_raw]: crate::pointer::SizeCompat::cast_from_raw
//
// TODO(#1817): Support Sized->Unsized and Unsized->Sized casts
pub(crate) fn cast_from_raw<Src, Dst>(src: PtrInner<'_, Src>) -> PtrInner<'_, Dst>
Expand Down
8 changes: 4 additions & 4 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
pointer::{
inner::PtrInner,
invariant::*,
transmute::{MutationCompatible, SizeEq, TransmuteFromPtr},
transmute::{MutationCompatible, SizeCompat, TransmuteFromPtr},
},
AlignmentError, CastError, CastType, KnownLayout, SizeError, TryFromBytes, ValidityError,
};
Expand Down Expand Up @@ -388,10 +388,10 @@ mod _conversions {
pub(crate) fn transmute<U, V, R>(self) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)>
where
V: Validity,
U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, R> + SizeEq<T> + ?Sized,
U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, R> + SizeCompat<T> + ?Sized,
{
// SAFETY:
// - `SizeEq::cast_from_raw` promises to preserve address,
// - `SizeCompat::cast_from_raw` promises to preserve address,
// provenance, and the number of bytes in the referent
// - If aliasing is `Shared`, then by `U: TransmuteFromPtr<T>`, at
// least one of the following holds:
Expand All @@ -402,7 +402,7 @@ mod _conversions {
// operate on these references simultaneously
// - By `U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V>`, it is
// sound to perform this transmute.
unsafe { self.transmute_unchecked(|ptr| SizeEq::cast_from_raw(ptr).as_non_null()) }
unsafe { self.transmute_unchecked(|ptr| SizeCompat::cast_from_raw(ptr).as_non_null()) }
}

#[doc(hidden)]
Expand Down
Loading
Loading