Skip to content

Commit

Permalink
Initial commit of DstLayout::for_dst
Browse files Browse the repository at this point in the history
This will be used by the custom derive of `KnownLayout` to compute the
`DstLayout` for unsized types.

Makes progress on #29

Co-authored-by: Jack Wrenn <jswrenn@amazon.com>
  • Loading branch information
joshlf and jswrenn committed Nov 2, 2023
1 parent 3f9c8b4 commit 21cea7e
Show file tree
Hide file tree
Showing 6 changed files with 334 additions and 142 deletions.
3 changes: 3 additions & 0 deletions src/byteorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ use core::{
num::TryFromIntError,
};

// Ensures proc-macro derive works in the context of this crate.
use crate as zerocopy;

// We don't reexport `WriteBytesExt` or `ReadBytesExt` because those are only
// available with the `std` feature enabled, and zerocopy is `no_std` by
// default.
Expand Down
67 changes: 65 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@
#![cfg_attr(feature = "simd-nightly", feature(stdsimd))]
#![cfg_attr(
__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS,
feature(layout_for_ptr, strict_provenance)
feature(const_size_of_val_raw, layout_for_ptr, strict_provenance)
)]
#[macro_use]
mod macros;
Expand Down Expand Up @@ -427,6 +427,55 @@ impl DstLayout {
}
}

/// Constructs a `DstLayout` which describes a dynamically-sized type with
/// the given properties.
///
/// # Safety
///
/// Unsafe code may assume that the returned `DstLayout` is the correct
/// layout for the described type so long as:
/// - The type has the alignment `align`
/// - The type has at least one field
/// - The byte offset of the first byte of the trailing field is equal to
/// `trailing_field_offset`
/// - The trailing field's layout is correctly described by
/// `trailing_field_layout`
#[doc(hidden)]
#[inline]
pub const fn for_dst(
align: NonZeroUsize,
trailing_field_offset: usize,
trailing_field_layout: DstLayout,
) -> Option<DstLayout> {
Some(DstLayout {
// SAFETY: The caller has promised that this is the correct
// alignment.
_align: align,
_size_info: match trailing_field_layout._size_info {
SizeInfo::Sized { _size } => {
let without_padding = match trailing_field_offset.checked_add(_size) {
Some(without_padding) => without_padding,
None => return None,
};

let padding = util::core_layout::_padding_needed_for(without_padding, align);
// SAFETY: TODO
#[allow(clippy::arithmetic_side_effects)]
SizeInfo::Sized { _size: without_padding + padding }
}
SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) => {
let offset = match trailing_field_offset.checked_add(_offset) {
Some(offset) => offset,
None => return None,
};

// SAFETY: TODO
SizeInfo::SliceDst(TrailingSliceLayout { _offset: offset, _elem_size })
}
},
})
}

/// Validates that a cast is sound from a layout perspective.
///
/// Validates that the size and alignment requirements of a type with the
Expand Down Expand Up @@ -3684,6 +3733,20 @@ mod tests {
}
}

#[test]
fn test_dst_layout_for_dst() {
macro_rules! test {
($align:expr, $trailing_field_offset:expr, $trailing_field_layout:expr, $expect:expr) => {{
let align = NonZeroUsize::new($align).unwrap();
let layout =
DstLayout::for_dst(align, $trailing_field_offset, $trailing_field_layout);
assert_eq!(layout, $expect);
}};
}

// TODO: Write tests.
}

// This test takes a long time when running under Miri, so we skip it in
// that case. This is acceptable because this is a logic test that doesn't
// attempt to expose UB.
Expand Down Expand Up @@ -5366,7 +5429,7 @@ mod tests {
assert_impls!(Wrapping<NotZerocopy>: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);

assert_impls!(Unalign<u8>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(Unalign<NotZerocopy>: KnownLayout, Unaligned, !FromZeroes, !FromBytes, !AsBytes);
assert_impls!(Unalign<NotZerocopy>: Unaligned, !FromZeroes, !FromBytes, !AsBytes);

assert_impls!([u8]: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!([NotZerocopy]: !KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
Expand Down
Loading

0 comments on commit 21cea7e

Please sign in to comment.