Skip to content

Commit 31c878b

Browse files
committed
[wip] Introduce InitializeIntoBytes
Supports viewing types with padding as `&impl IntoBytes` by first zeroizing padding. gherrit-pr-id: G156cc6c0b2e4340c970ae4e097c7f6afdb38158e
1 parent bc52522 commit 31c878b

14 files changed

Lines changed: 517 additions & 88 deletions

File tree

src/byteorder.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,9 @@ example of how it can be used for parsing UDP packets.
505505
impl_or_verify!(O => Unaligned for $name<O>);
506506
};
507507

508+
#[cfg(not(any(feature = "derive", test)))]
509+
impl_initialize_into_bytes!(O => $name<O>);
510+
508511
impl<O> Default for $name<O> {
509512
#[inline(always)]
510513
fn default() -> $name<O> {

src/impls.rs

Lines changed: 112 additions & 43 deletions
Large diffs are not rendered by default.

src/layout.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,13 @@ impl DstLayout {
750750
}
751751
}
752752

753+
/*pub enum Fields {
754+
Primitive,
755+
Struct { fields: &'static [(usize, DstLayout)] },
756+
Union { fields: &'static [(usize, DstLayout)] },
757+
Enum,
758+
}*/
759+
753760
pub(crate) use cast_from::CastFrom;
754761
mod cast_from {
755762
use crate::*;

src/lib.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5496,6 +5496,27 @@ fn mut_from_prefix_suffix<T: FromBytes + IntoBytes + KnownLayout + ?Sized>(
54965496
Ok((slf.recall_validity::<_, (_, (_, _))>().as_mut(), prefix_suffix.as_mut()))
54975497
}
54985498

5499+
/// # Safety
5500+
///
5501+
/// TODO
5502+
pub unsafe trait InitializeIntoBytes {
5503+
#[doc(hidden)]
5504+
fn only_derive_is_allowed_to_implement_this_trait()
5505+
where
5506+
Self: Sized;
5507+
5508+
#[doc(hidden)]
5509+
fn initialize_padding(
5510+
ptr: Ptr<'_, Self, (invariant::Exclusive, invariant::Unaligned, invariant::AsInitialized)>,
5511+
);
5512+
5513+
/// Produce an [`IntoBytes`] reference to `Self` by initializing its
5514+
/// padding.
5515+
fn initialize_into_bytes(&mut self) -> &(impl IntoBytes + Immutable + ?Sized) {
5516+
&42
5517+
}
5518+
}
5519+
54995520
/// Analyzes whether a type is [`IntoBytes`].
55005521
///
55015522
/// This derive analyzes, at compile time, whether the annotated type satisfies
@@ -5676,7 +5697,7 @@ pub use zerocopy_derive::IntoBytes;
56765697
not(no_zerocopy_diagnostic_on_unimplemented_1_78_0),
56775698
diagnostic::on_unimplemented(note = "Consider adding `#[derive(IntoBytes)]` to `{Self}`")
56785699
)]
5679-
pub unsafe trait IntoBytes {
5700+
pub unsafe trait IntoBytes: InitializeIntoBytes {
56805701
// The `Self: Sized` bound makes it so that this function doesn't prevent
56815702
// `IntoBytes` from being object safe. Note that other `IntoBytes` methods
56825703
// prevent object safety, but those provide a benefit in exchange for object

src/pointer/ptr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ mod def {
9696
/// Note that this method does not consume `self`. The caller should
9797
/// watch out for `unsafe` code which uses the returned value in a way
9898
/// that violates the safety invariants of `self`.
99-
pub(crate) fn as_inner(&self) -> PtrInner<'a, T> {
99+
pub fn as_inner(&self) -> PtrInner<'a, T> {
100100
self.ptr
101101
}
102102
}

src/util/macros.rs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,18 @@ macro_rules! unsafe_impl {
128128
unsafe_impl!(@method $trait $(; |$candidate| $is_bit_valid)?);
129129
}
130130
}};
131+
(@method InitializeIntoBytes ; |$slf:ident| $initialize_padding:expr) => {
132+
#[allow(clippy::missing_inline_in_public_items, dead_code)]
133+
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
134+
fn only_derive_is_allowed_to_implement_this_trait() {}
131135

136+
#[allow(unused_mut)]
137+
#[inline(always)]
138+
fn initialize_padding($slf: Ptr<'_, Self, (invariant::Exclusive, invariant::Unaligned, invariant::AsInitialized)>)
139+
{
140+
$initialize_padding
141+
}
142+
};
132143
(@method TryFromBytes ; |$candidate:ident| $is_bit_valid:expr) => {
133144
#[allow(clippy::missing_inline_in_public_items, dead_code)]
134145
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
@@ -174,6 +185,7 @@ macro_rules! impl_for_transmute_from {
174185
$(#[$attr:meta])*
175186
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)?
176187
=> $trait:ident for $ty:ty [$repr:ty]
188+
$(|$slf:ident| $b:block)*
177189
) => {
178190
const _: () = {
179191
$(#[$attr])*
@@ -214,12 +226,20 @@ macro_rules! impl_for_transmute_from {
214226
$(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)?
215227
$trait for $ty [$repr]
216228
);
229+
230+
impl_for_transmute_from!(
231+
@initialize_into_bytes
232+
$(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)?
233+
$trait for $ty [$repr]
234+
$(|$slf| $b)*
235+
);
217236
}
218237
};
219238
};
220239
(@assert_is_supported_trait TryFromBytes) => {};
221240
(@assert_is_supported_trait FromZeros) => {};
222241
(@assert_is_supported_trait FromBytes) => {};
242+
(@assert_is_supported_trait InitializeIntoBytes) => {};
223243
(@assert_is_supported_trait IntoBytes) => {};
224244
(
225245
@is_bit_valid
@@ -242,7 +262,29 @@ macro_rules! impl_for_transmute_from {
242262
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
243263
$trait:ident for $ty:ty [$repr:ty]
244264
) => {
245-
// Trait other than `TryFromBytes`; no `is_bit_valid` impl.
265+
// Other trait; no additional items.
266+
};
267+
(
268+
@initialize_into_bytes
269+
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
270+
InitializeIntoBytes for $ty:ty [$repr:ty]
271+
) => {
272+
#[inline(always)]
273+
fn initialize_padding(ptr: Ptr<'_, Self, (invariant::Exclusive, invariant::Unaligned, invariant::AsInitialized)>)
274+
{
275+
let ptr = ptr.transmute::<$repr, _, (_, (_, _))>();
276+
// SAFETY: This macro ensures that `$repr` and `Self` have the same
277+
// size and bit validity. Thus, a bit-valid instance of `$repr` is
278+
// also a bit-valid instance of `Self`.
279+
<$repr as InitializeIntoBytes>::initialize_padding(ptr)
280+
}
281+
};
282+
(
283+
@initialize_into_bytes
284+
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
285+
$trait:ident for $ty:ty [$repr:ty] $(|$slf:ident| $b:block)*
286+
) => {
287+
// Other trait; no additional items.
246288
};
247289
}
248290

@@ -525,6 +567,36 @@ macro_rules! unsafe_impl_known_layout {
525567
}};
526568
}
527569

570+
macro_rules! impl_initialize_into_bytes {
571+
($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
572+
$(impl_initialize_into_bytes!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)*
573+
};
574+
($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
575+
$(impl_initialize_into_bytes!(@inner , $tyvar $(: ?$optbound)? => $ty);)*
576+
};
577+
($($(#[$attrs:meta])* $ty:ty),*) => { $(impl_initialize_into_bytes!(@inner , => $(#[$attrs])* $ty);)* };
578+
(@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $(#[$attrs:meta])* $ty:ty) => {
579+
const _: () = {
580+
#[allow(non_local_definitions)]
581+
$(#[$attrs])*
582+
// SAFETY: TODO
583+
unsafe impl<$($tyvar $(: ?$optbound)?)? $(, const $constvar : $constty)?> InitializeIntoBytes for $ty
584+
where
585+
Self: IntoBytes
586+
{
587+
#[allow(clippy::missing_inline_in_public_items)]
588+
#[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
589+
fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {}
590+
591+
#[inline(always)]
592+
fn initialize_padding(_: Ptr<'_, Self, (invariant::Exclusive, invariant::Unaligned, invariant::AsInitialized)>) {
593+
// By invariant on `Self: IntoBytes`, values of type `Self` never contain padding.
594+
}
595+
}
596+
};
597+
};
598+
}
599+
528600
/// Uses `align_of` to confirm that a type or set of types have alignment 1.
529601
///
530602
/// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for
@@ -740,14 +812,19 @@ macro_rules! unsafe_impl_for_transparent_wrapper {
740812
($vis:vis T $(: ?$optbound:ident)? => $wrapper:ident<T>) => {{
741813
crate::util::macros::__unsafe();
742814

743-
use crate::pointer::{TransmuteFrom, cast::{CastExact, TransitiveProject}, SizeEq, invariant::Valid};
815+
use crate::pointer::{TransmuteFrom, cast::{CastExact, TransitiveProject}, SizeEq, invariant::{AsInitialized, Valid}};
744816
use crate::wrappers::ReadOnly;
745817

746818
// SAFETY: The caller promises that `T` and `$wrapper<T>` have the same
747819
// bit validity.
748820
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<T, Valid, Valid> for $wrapper<T> {}
749821
// SAFETY: See previous safety comment.
750822
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<$wrapper<T>, Valid, Valid> for T {}
823+
// SAFETY: See previous safety comment.
824+
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<T, AsInitialized, AsInitialized> for $wrapper<T> {}
825+
// SAFETY: See previous safety comment.
826+
unsafe impl<T $(: ?$optbound)?> TransmuteFrom<$wrapper<T>, AsInitialized, AsInitialized> for T {}
827+
751828
// SAFETY: The caller promises that a `T` to `$wrapper<T>` cast is
752829
// size-preserving.
753830
define_cast!(unsafe { $vis CastToWrapper<T $(: ?$optbound)? > = T => $wrapper<T> });

src/util/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,26 @@ mod len_of {
656656

657657
pub(crate) use len_of::MetadataOf;
658658

659+
#[doc(hidden)]
660+
#[inline(always)]
661+
pub const fn sort_fields<const N: usize>(mut arr: [(usize, usize); N]) -> [(usize, usize); N] {
662+
let mut i = 0;
663+
while i < N {
664+
let mut j = 0;
665+
while j + 1 < N - i {
666+
if arr[j].0 > arr[j + 1].0 {
667+
let temp = arr[j];
668+
arr[j] = arr[j + 1];
669+
arr[j + 1] = temp;
670+
}
671+
j += 1;
672+
}
673+
i += 1;
674+
}
675+
676+
arr
677+
}
678+
659679
/// Since we support multiple versions of Rust, there are often features which
660680
/// have been stabilized in the most recent stable release which do not yet
661681
/// exist (stably) on our MSRV. This module provides polyfills for those

src/wrappers.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
use core::{fmt, hash::Hash};
1010

1111
use super::*;
12-
use crate::pointer::{invariant::Valid, SizeEq, TransmuteFrom};
12+
use crate::pointer::{
13+
invariant::{AsInitialized, Valid},
14+
SizeEq, TransmuteFrom,
15+
};
1316

1417
/// A type with no alignment requirement.
1518
///
@@ -153,6 +156,14 @@ const _: () = unsafe {
153156
);
154157
impl_or_verify!(T: FromZeros => FromZeros for Unalign<T>);
155158
impl_or_verify!(T: FromBytes => FromBytes for Unalign<T>);
159+
impl_or_verify!(
160+
T: InitializeIntoBytes => InitializeIntoBytes for Unalign<T>;
161+
|c| {
162+
let _ = c;
163+
// TODO
164+
//T::initialize_padding(c.transmute::<T, pointer::invariant::Valid, (pointer::BecauseMutationCompatible, _)>()
165+
}
166+
);
156167
impl_or_verify!(T: IntoBytes => IntoBytes for Unalign<T>);
157168
};
158169

@@ -636,6 +647,14 @@ mod read_only_def {
636647
}
637648

638649
impl<T: ?Sized> ReadOnly<T> {
650+
/// TODO
651+
#[inline(always)]
652+
pub fn from_mut(t: &mut T) -> &mut ReadOnly<T> {
653+
let ptr = crate::Ptr::from_mut(t).transmute::<Self, _, _>();
654+
let ptr = unsafe { ptr.assume_alignment() };
655+
ptr.as_mut()
656+
}
657+
639658
#[inline(always)]
640659
pub(crate) fn as_mut(r: &mut ReadOnly<T>) -> &mut T {
641660
// SAFETY: `r: &mut ReadOnly`, so this doesn't violate the invariant
@@ -675,6 +694,10 @@ const _: () = unsafe {
675694
);
676695
unsafe_impl!(T: ?Sized + FromZeros => FromZeros for ReadOnly<T>);
677696
unsafe_impl!(T: ?Sized + FromBytes => FromBytes for ReadOnly<T>);
697+
unsafe_impl!(T: ?Sized + InitializeIntoBytes => InitializeIntoBytes for ReadOnly<T>; |slf| {
698+
// TODO: Fix alignment.
699+
T::initialize_padding(slf.transmute());
700+
});
678701
unsafe_impl!(T: ?Sized + IntoBytes => IntoBytes for ReadOnly<T>);
679702
};
680703

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

739+
// SAFETY: `ReadOnly<T>` is a `#[repr(transparent)]` wrapper around `T`, and so
740+
// it has the same bit validity as `T`.
741+
unsafe impl<T: ?Sized> TransmuteFrom<T, AsInitialized, AsInitialized> for ReadOnly<T> {}
742+
743+
// SAFETY: `ReadOnly<T>` is a `#[repr(transparent)]` wrapper around `T`, and so
744+
// it has the same bit validity as `T`.
745+
unsafe impl<T: ?Sized> TransmuteFrom<ReadOnly<T>, AsInitialized, AsInitialized> for T {}
746+
716747
impl<'a, T: ?Sized + Immutable> From<&'a T> for &'a ReadOnly<T> {
717748
#[inline(always)]
718749
fn from(t: &'a T) -> &'a ReadOnly<T> {

0 commit comments

Comments
 (0)