Skip to content

Commit 55749cb

Browse files
joshlfjswrenn
authored andcommitted
Add KnownLayout::MaybeUninit type
Closes #1797
1 parent fa7d56d commit 55749cb

File tree

9 files changed

+1415
-1019
lines changed

9 files changed

+1415
-1019
lines changed

build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ fn main() {
8383
println!(
8484
"cargo:rustc-check-cfg=cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)"
8585
);
86+
println!("cargo:rustc-check-cfg=cfg(zerocopy_unstable)");
8687
println!("cargo:rustc-check-cfg=cfg(coverage_nightly)");
8788
}
8889

src/impls.rs

+16-14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
// This file may not be copied, modified, or distributed except according to
88
// those terms.
99

10+
use core::mem::MaybeUninit as CoreMaybeUninit;
11+
1012
use super::*;
1113

1214
safety_comment! {
@@ -630,14 +632,14 @@ safety_comment! {
630632
/// SAFETY:
631633
/// `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`:
632634
/// `MaybeUninit<T>` has no restrictions on its contents.
633-
unsafe_impl!(T => TryFromBytes for MaybeUninit<T>);
634-
unsafe_impl!(T => FromZeros for MaybeUninit<T>);
635-
unsafe_impl!(T => FromBytes for MaybeUninit<T>);
635+
unsafe_impl!(T => TryFromBytes for CoreMaybeUninit<T>);
636+
unsafe_impl!(T => FromZeros for CoreMaybeUninit<T>);
637+
unsafe_impl!(T => FromBytes for CoreMaybeUninit<T>);
636638
}
637639

638-
impl_for_transparent_wrapper!(T: Immutable => Immutable for MaybeUninit<T>);
639-
impl_for_transparent_wrapper!(T: Unaligned => Unaligned for MaybeUninit<T>);
640-
assert_unaligned!(MaybeUninit<()>, MaybeUninit<u8>);
640+
impl_for_transparent_wrapper!(T: Immutable => Immutable for CoreMaybeUninit<T>);
641+
impl_for_transparent_wrapper!(T: Unaligned => Unaligned for CoreMaybeUninit<T>);
642+
assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit<u8>);
641643

642644
impl_for_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>);
643645
impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T>);
@@ -1254,8 +1256,8 @@ mod tests {
12541256
ManuallyDrop<UnsafeCell<()>>,
12551257
ManuallyDrop<[UnsafeCell<u8>]>,
12561258
ManuallyDrop<[UnsafeCell<bool>]>,
1257-
MaybeUninit<NotZerocopy>,
1258-
MaybeUninit<UnsafeCell<()>>,
1259+
CoreMaybeUninit<NotZerocopy>,
1260+
CoreMaybeUninit<UnsafeCell<()>>,
12591261
Wrapping<UnsafeCell<()>>
12601262
);
12611263

@@ -1297,9 +1299,9 @@ mod tests {
12971299
Option<FnManyArgs>,
12981300
Option<extern "C" fn()>,
12991301
Option<ECFnManyArgs>,
1300-
MaybeUninit<u8>,
1301-
MaybeUninit<NotZerocopy>,
1302-
MaybeUninit<UnsafeCell<()>>,
1302+
CoreMaybeUninit<u8>,
1303+
CoreMaybeUninit<NotZerocopy>,
1304+
CoreMaybeUninit<UnsafeCell<()>>,
13031305
ManuallyDrop<UnsafeCell<()>>,
13041306
ManuallyDrop<[UnsafeCell<u8>]>,
13051307
ManuallyDrop<[UnsafeCell<bool>]>,
@@ -1761,9 +1763,9 @@ mod tests {
17611763
assert_impls!(ManuallyDrop<[UnsafeCell<u8>]>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable);
17621764
assert_impls!(ManuallyDrop<[UnsafeCell<bool>]>: KnownLayout, TryFromBytes, FromZeros, IntoBytes, Unaligned, !Immutable, !FromBytes);
17631765

1764-
assert_impls!(MaybeUninit<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, Unaligned, !IntoBytes);
1765-
assert_impls!(MaybeUninit<NotZerocopy>: KnownLayout, TryFromBytes, FromZeros, FromBytes, !Immutable, !IntoBytes, !Unaligned);
1766-
assert_impls!(MaybeUninit<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, Unaligned, !Immutable, !IntoBytes);
1766+
assert_impls!(CoreMaybeUninit<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, Unaligned, !IntoBytes);
1767+
assert_impls!(CoreMaybeUninit<NotZerocopy>: KnownLayout, TryFromBytes, FromZeros, FromBytes, !Immutable, !IntoBytes, !Unaligned);
1768+
assert_impls!(CoreMaybeUninit<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, Unaligned, !Immutable, !IntoBytes);
17671769

17681770
assert_impls!(Wrapping<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
17691771
// This test is important because it allows us to test our hand-rolled

src/lib.rs

+46-6
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ use core::{
349349
fmt::{self, Debug, Display, Formatter},
350350
hash::Hasher,
351351
marker::PhantomData,
352-
mem::{self, ManuallyDrop, MaybeUninit},
352+
mem::{self, ManuallyDrop, MaybeUninit as CoreMaybeUninit},
353353
num::{
354354
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
355355
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
@@ -724,6 +724,22 @@ pub unsafe trait KnownLayout {
724724
/// This is `()` for sized types and `usize` for slice DSTs.
725725
type PointerMetadata: PointerMetadata;
726726

727+
/// A maybe-uninitialized analog of `Self`
728+
///
729+
/// # Safety
730+
///
731+
/// Users may assume that:
732+
/// - `Self` and `Self::MaybeUninit` have the same:
733+
/// - Fixed prefix size
734+
/// - Alignment
735+
/// - (For DSTs) trailing slice element size
736+
/// - It is valid to perform an `as` cast from `*mut Self` and `*mut
737+
/// Self::MaybeUninit`, and this operation preserves referent size (ie,
738+
/// `size_of_val_raw`).
739+
#[cfg(zerocopy_unstable)]
740+
#[doc(hidden)]
741+
type MaybeUninit: ?Sized + KnownLayout<PointerMetadata = Self::PointerMetadata>;
742+
727743
/// The layout of `Self`.
728744
///
729745
/// # Safety
@@ -856,6 +872,17 @@ unsafe impl<T> KnownLayout for [T] {
856872

857873
type PointerMetadata = usize;
858874

875+
// SAFETY: `CoreMaybeUninit<T>` has the same size and alignment as `T`.
876+
// Consequently, `[CoreMaybeUninit<T>]` has the same size and alignment as
877+
// `[T]`, becuase `CoreMaybeUninit<T>` has the same size and alignment as
878+
// `T` [1].
879+
//
880+
// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
881+
//
882+
// `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as
883+
// `T`
884+
type MaybeUninit = [CoreMaybeUninit<T>];
885+
859886
const LAYOUT: DstLayout = DstLayout::for_slice::<T>();
860887

861888
// SAFETY: `.cast` preserves address and provenance. The returned pointer
@@ -908,7 +935,7 @@ impl_known_layout!(
908935
T => Option<T>,
909936
T: ?Sized => PhantomData<T>,
910937
T => Wrapping<T>,
911-
T => MaybeUninit<T>,
938+
T => CoreMaybeUninit<T>,
912939
T: ?Sized => *const T,
913940
T: ?Sized => *mut T
914941
);
@@ -941,6 +968,19 @@ safety_comment! {
941968
unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] UnsafeCell<T>);
942969
}
943970

971+
safety_comment! {
972+
/// SAFETY:
973+
/// - By invariant on `KnownLayout::MaybeUninit`, `T` and `T::MaybeUninit`
974+
/// have the same:
975+
/// - Fixed prefix size
976+
/// - Alignment
977+
/// - (For DSTs) trailing slice element size
978+
/// - By invariant on `KnownLayout`, it is valid to perform an `as` cast
979+
/// from `*mut T` and `*mut T::MaybeUninit`, and this operation preserves
980+
/// referent size (ie, `size_of_val_raw`).
981+
unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T::MaybeUninit)] MaybeUninit<T>);
982+
}
983+
944984
/// Analyzes whether a type is [`FromZeros`].
945985
///
946986
/// This derive analyzes, at compile time, whether the annotated type satisfies
@@ -2539,7 +2579,7 @@ pub unsafe trait TryFromBytes {
25392579
where
25402580
Self: Sized,
25412581
{
2542-
let candidate = match MaybeUninit::<Self>::read_from_bytes(source) {
2582+
let candidate = match CoreMaybeUninit::<Self>::read_from_bytes(source) {
25432583
Ok(candidate) => candidate,
25442584
Err(e) => {
25452585
return Err(TryReadError::Size(e.with_dst()));
@@ -2600,7 +2640,7 @@ pub unsafe trait TryFromBytes {
26002640
where
26012641
Self: Sized,
26022642
{
2603-
let (candidate, suffix) = match MaybeUninit::<Self>::read_from_prefix(source) {
2643+
let (candidate, suffix) = match CoreMaybeUninit::<Self>::read_from_prefix(source) {
26042644
Ok(candidate) => candidate,
26052645
Err(e) => {
26062646
return Err(TryReadError::Size(e.with_dst()));
@@ -2662,7 +2702,7 @@ pub unsafe trait TryFromBytes {
26622702
where
26632703
Self: Sized,
26642704
{
2665-
let (prefix, candidate) = match MaybeUninit::<Self>::read_from_suffix(source) {
2705+
let (prefix, candidate) = match CoreMaybeUninit::<Self>::read_from_suffix(source) {
26662706
Ok(candidate) => candidate,
26672707
Err(e) => {
26682708
return Err(TryReadError::Size(e.with_dst()));
@@ -2735,7 +2775,7 @@ fn swap<T, U>((t, u): (T, U)) -> (U, T) {
27352775
#[inline(always)]
27362776
unsafe fn try_read_from<S, T: TryFromBytes>(
27372777
source: S,
2738-
mut candidate: MaybeUninit<T>,
2778+
mut candidate: CoreMaybeUninit<T>,
27392779
) -> Result<T, TryReadError<S, T>> {
27402780
// We use `from_mut` despite not mutating via `c_ptr` so that we don't need
27412781
// to add a `T: Immutable` bound.

src/util/macros.rs

+3
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,8 @@ macro_rules! impl_known_layout {
530530

531531
type PointerMetadata = ();
532532

533+
type MaybeUninit = core::mem::MaybeUninit<Self>;
534+
533535
const LAYOUT: crate::DstLayout = crate::DstLayout::for_type::<$ty>();
534536

535537
// SAFETY: `.cast` preserves address and provenance.
@@ -572,6 +574,7 @@ macro_rules! unsafe_impl_known_layout {
572574
fn only_derive_is_allowed_to_implement_this_trait() {}
573575

574576
type PointerMetadata = <$repr as KnownLayout>::PointerMetadata;
577+
type MaybeUninit = <$repr as KnownLayout>::MaybeUninit;
575578

576579
const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
577580

src/util/mod.rs

+16
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,22 @@ pub(crate) unsafe fn copy_unchecked(src: &[u8], dst: &mut [u8]) {
683683
};
684684
}
685685

686+
/// Unsafely transmutes the given `src` into a type `Dst`.
687+
///
688+
/// # Safety
689+
///
690+
/// TODO. Same as it ever was.
691+
#[inline(always)]
692+
pub(crate) const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst {
693+
static_assert!(Src, Dst => core::mem::size_of::<Src>() >= core::mem::size_of::<Dst>());
694+
#[repr(C)]
695+
union Transmute<Src, Dst> {
696+
src: ManuallyDrop<Src>,
697+
dst: ManuallyDrop<Dst>,
698+
}
699+
unsafe { ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) }
700+
}
701+
686702
/// Since we support multiple versions of Rust, there are often features which
687703
/// have been stabilized in the most recent stable release which do not yet
688704
/// exist (stably) on our MSRV. This module provides polyfills for those

0 commit comments

Comments
 (0)