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
3 changes: 3 additions & 0 deletions src/byteorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,9 @@ example of how it can be used for parsing UDP packets.
impl_or_verify!(O => Unaligned for $name<O>);
};

#[cfg(not(any(feature = "derive", test)))]
impl_initialize_into_bytes!(O => $name<O>);

impl<O> Default for $name<O> {
#[inline(always)]
fn default() -> $name<O> {
Expand Down
155 changes: 112 additions & 43 deletions src/impls.rs

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,13 @@ impl DstLayout {
}
}

/*pub enum Fields {
Primitive,
Struct { fields: &'static [(usize, DstLayout)] },
Union { fields: &'static [(usize, DstLayout)] },
Enum,
}*/

pub(crate) use cast_from::CastFrom;
mod cast_from {
use crate::*;
Expand Down
23 changes: 22 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5496,6 +5496,27 @@ fn mut_from_prefix_suffix<T: FromBytes + IntoBytes + KnownLayout + ?Sized>(
Ok((slf.recall_validity::<_, (_, (_, _))>().as_mut(), prefix_suffix.as_mut()))
}

/// # Safety
///
/// TODO
pub unsafe trait InitializeIntoBytes {
#[doc(hidden)]
fn only_derive_is_allowed_to_implement_this_trait()
where
Self: Sized;

#[doc(hidden)]
fn initialize_padding(
ptr: Ptr<'_, Self, (invariant::Exclusive, invariant::Unaligned, invariant::AsInitialized)>,
);

/// Produce an [`IntoBytes`] reference to `Self` by initializing its
/// padding.
fn initialize_into_bytes(&mut self) -> &(impl IntoBytes + Immutable + ?Sized) {
&42
}
}

/// Analyzes whether a type is [`IntoBytes`].
///
/// This derive analyzes, at compile time, whether the annotated type satisfies
Expand Down Expand Up @@ -5676,7 +5697,7 @@ pub use zerocopy_derive::IntoBytes;
not(no_zerocopy_diagnostic_on_unimplemented_1_78_0),
diagnostic::on_unimplemented(note = "Consider adding `#[derive(IntoBytes)]` to `{Self}`")
)]
pub unsafe trait IntoBytes {
pub unsafe trait IntoBytes: InitializeIntoBytes {
// The `Self: Sized` bound makes it so that this function doesn't prevent
// `IntoBytes` from being object safe. Note that other `IntoBytes` methods
// prevent object safety, but those provide a benefit in exchange for object
Expand Down
2 changes: 1 addition & 1 deletion src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ mod def {
/// Note that this method does not consume `self`. The caller should
/// watch out for `unsafe` code which uses the returned value in a way
/// that violates the safety invariants of `self`.
pub(crate) fn as_inner(&self) -> PtrInner<'a, T> {
pub fn as_inner(&self) -> PtrInner<'a, T> {
self.ptr
}
}
Expand Down
81 changes: 79 additions & 2 deletions src/util/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,18 @@ macro_rules! unsafe_impl {
unsafe_impl!(@method $trait $(; |$candidate| $is_bit_valid)?);
}
}};
(@method InitializeIntoBytes ; |$slf:ident| $initialize_padding:expr) => {
#[allow(clippy::missing_inline_in_public_items, dead_code)]
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
fn only_derive_is_allowed_to_implement_this_trait() {}

#[allow(unused_mut)]
#[inline(always)]
fn initialize_padding($slf: Ptr<'_, Self, (invariant::Exclusive, invariant::Unaligned, invariant::AsInitialized)>)
{
$initialize_padding
}
};
(@method TryFromBytes ; |$candidate:ident| $is_bit_valid:expr) => {
#[allow(clippy::missing_inline_in_public_items, dead_code)]
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
Expand Down Expand Up @@ -174,6 +185,7 @@ macro_rules! impl_for_transmute_from {
$(#[$attr:meta])*
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)?
=> $trait:ident for $ty:ty [$repr:ty]
$(|$slf:ident| $b:block)*
) => {
const _: () = {
$(#[$attr])*
Expand Down Expand Up @@ -214,12 +226,20 @@ macro_rules! impl_for_transmute_from {
$(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)?
$trait for $ty [$repr]
);

impl_for_transmute_from!(
@initialize_into_bytes
$(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)?
$trait for $ty [$repr]
$(|$slf| $b)*
);
}
};
};
(@assert_is_supported_trait TryFromBytes) => {};
(@assert_is_supported_trait FromZeros) => {};
(@assert_is_supported_trait FromBytes) => {};
(@assert_is_supported_trait InitializeIntoBytes) => {};
(@assert_is_supported_trait IntoBytes) => {};
(
@is_bit_valid
Expand All @@ -242,7 +262,29 @@ macro_rules! impl_for_transmute_from {
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
$trait:ident for $ty:ty [$repr:ty]
) => {
// Trait other than `TryFromBytes`; no `is_bit_valid` impl.
// Other trait; no additional items.
};
(
@initialize_into_bytes
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
InitializeIntoBytes for $ty:ty [$repr:ty]
) => {
#[inline(always)]
fn initialize_padding(ptr: Ptr<'_, Self, (invariant::Exclusive, invariant::Unaligned, invariant::AsInitialized)>)
{
let ptr = ptr.transmute::<$repr, _, (_, (_, _))>();
// SAFETY: This macro ensures that `$repr` and `Self` have the same
// size and bit validity. Thus, a bit-valid instance of `$repr` is
// also a bit-valid instance of `Self`.
<$repr as InitializeIntoBytes>::initialize_padding(ptr)
}
};
(
@initialize_into_bytes
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
$trait:ident for $ty:ty [$repr:ty] $(|$slf:ident| $b:block)*
) => {
// Other trait; no additional items.
};
}

Expand Down Expand Up @@ -525,6 +567,36 @@ macro_rules! unsafe_impl_known_layout {
}};
}

macro_rules! impl_initialize_into_bytes {
($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
$(impl_initialize_into_bytes!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)*
};
($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
$(impl_initialize_into_bytes!(@inner , $tyvar $(: ?$optbound)? => $ty);)*
};
($($(#[$attrs:meta])* $ty:ty),*) => { $(impl_initialize_into_bytes!(@inner , => $(#[$attrs])* $ty);)* };
(@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $(#[$attrs:meta])* $ty:ty) => {
const _: () = {
#[allow(non_local_definitions)]
$(#[$attrs])*
// SAFETY: TODO
unsafe impl<$($tyvar $(: ?$optbound)?)? $(, const $constvar : $constty)?> InitializeIntoBytes for $ty
where
Self: IntoBytes
{
#[allow(clippy::missing_inline_in_public_items)]
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {}

#[inline(always)]
fn initialize_padding(_: Ptr<'_, Self, (invariant::Exclusive, invariant::Unaligned, invariant::AsInitialized)>) {
// By invariant on `Self: IntoBytes`, values of type `Self` never contain padding.
}
}
};
};
}

/// Uses `align_of` to confirm that a type or set of types have alignment 1.
///
/// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for
Expand Down Expand Up @@ -740,14 +812,19 @@ macro_rules! unsafe_impl_for_transparent_wrapper {
($vis:vis T $(: ?$optbound:ident)? => $wrapper:ident<T>) => {{
crate::util::macros::__unsafe();

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

// SAFETY: The caller promises that `T` and `$wrapper<T>` have the same
// bit validity.
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<T, Valid, Valid> for $wrapper<T> {}
// SAFETY: See previous safety comment.
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<$wrapper<T>, Valid, Valid> for T {}
// SAFETY: See previous safety comment.
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<T, AsInitialized, AsInitialized> for $wrapper<T> {}
// SAFETY: See previous safety comment.
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<$wrapper<T>, AsInitialized, AsInitialized> 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
20 changes: 20 additions & 0 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,26 @@ mod len_of {

pub(crate) use len_of::MetadataOf;

#[doc(hidden)]
#[inline(always)]
pub const fn sort_fields<const N: usize>(mut arr: [(usize, usize); N]) -> [(usize, usize); N] {
let mut i = 0;
while i < N {
let mut j = 0;
while j + 1 < N - i {
if arr[j].0 > arr[j + 1].0 {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
j += 1;
}
i += 1;
}

arr
}

/// Since we support multiple versions of Rust, there are often features which
/// have been stabilized in the most recent stable release which do not yet
/// exist (stably) on our MSRV. This module provides polyfills for those
Expand Down
33 changes: 32 additions & 1 deletion src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
use core::{fmt, hash::Hash};

use super::*;
use crate::pointer::{invariant::Valid, SizeEq, TransmuteFrom};
use crate::pointer::{
invariant::{AsInitialized, Valid},
SizeEq, TransmuteFrom,
};

/// A type with no alignment requirement.
///
Expand Down Expand Up @@ -153,6 +156,14 @@ const _: () = unsafe {
);
impl_or_verify!(T: FromZeros => FromZeros for Unalign<T>);
impl_or_verify!(T: FromBytes => FromBytes for Unalign<T>);
impl_or_verify!(
T: InitializeIntoBytes => InitializeIntoBytes for Unalign<T>;
|c| {
let _ = c;
// TODO
//T::initialize_padding(c.transmute::<T, pointer::invariant::Valid, (pointer::BecauseMutationCompatible, _)>()
}
);
impl_or_verify!(T: IntoBytes => IntoBytes for Unalign<T>);
};

Expand Down Expand Up @@ -636,6 +647,14 @@ mod read_only_def {
}

impl<T: ?Sized> ReadOnly<T> {
/// TODO
#[inline(always)]
pub fn from_mut(t: &mut T) -> &mut ReadOnly<T> {
let ptr = crate::Ptr::from_mut(t).transmute::<Self, _, _>();
let ptr = unsafe { ptr.assume_alignment() };
ptr.as_mut()
}

#[inline(always)]
pub(crate) fn as_mut(r: &mut ReadOnly<T>) -> &mut T {
// SAFETY: `r: &mut ReadOnly`, so this doesn't violate the invariant
Expand Down Expand Up @@ -675,6 +694,10 @@ const _: () = unsafe {
);
unsafe_impl!(T: ?Sized + FromZeros => FromZeros for ReadOnly<T>);
unsafe_impl!(T: ?Sized + FromBytes => FromBytes for ReadOnly<T>);
unsafe_impl!(T: ?Sized + InitializeIntoBytes => InitializeIntoBytes for ReadOnly<T>; |slf| {
// TODO: Fix alignment.
T::initialize_padding(slf.transmute());
});
unsafe_impl!(T: ?Sized + IntoBytes => IntoBytes for ReadOnly<T>);
};

Expand Down Expand Up @@ -713,6 +736,14 @@ unsafe impl<T: ?Sized> TransmuteFrom<T, Valid, Valid> for ReadOnly<T> {}
// it has the same bit validity as `T`.
unsafe impl<T: ?Sized> TransmuteFrom<ReadOnly<T>, Valid, Valid> for T {}

// SAFETY: `ReadOnly<T>` is a `#[repr(transparent)]` wrapper around `T`, and so
// it has the same bit validity as `T`.
unsafe impl<T: ?Sized> TransmuteFrom<T, AsInitialized, AsInitialized> for ReadOnly<T> {}

// SAFETY: `ReadOnly<T>` is a `#[repr(transparent)]` wrapper around `T`, and so
// it has the same bit validity as `T`.
unsafe impl<T: ?Sized> TransmuteFrom<ReadOnly<T>, AsInitialized, AsInitialized> for T {}

impl<'a, T: ?Sized + Immutable> From<&'a T> for &'a ReadOnly<T> {
#[inline(always)]
fn from(t: &'a T) -> &'a ReadOnly<T> {
Expand Down
Loading
Loading