Skip to content

Commit d69cbfd

Browse files
authored
Add KnownLayout::size_for_metadata (#2674)
Computes the size of an object of type `Self` with the given pointer metadata. Makes progress towards #2541
1 parent f83ca64 commit d69cbfd

File tree

4 files changed

+39
-6
lines changed

4 files changed

+39
-6
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ zerocopy-derive = { version = "=0.8.26", path = "zerocopy-derive" }
9595
either = "=1.13.0"
9696
# FIXME(#381) Remove this dependency once we have our own layout gadgets.
9797
elain = "0.3.0"
98+
# More recent versions of `glob` have an MSRV higher than ours.
99+
glob = "=0.3.2"
98100
itertools = "0.11"
99101
rand = { version = "0.8.5", default-features = false, features = ["small_rng"] }
100102
rustversion = "1.0"

src/lib.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ pub unsafe trait KnownLayout {
821821
let meta = Self::pointer_to_metadata(ptr.as_ptr());
822822
// SAFETY: `size_for_metadata` promises to only return `None` if the
823823
// resulting size would not fit in a `usize`.
824-
meta.size_for_metadata(Self::LAYOUT)
824+
Self::size_for_metadata(meta)
825825
}
826826

827827
#[doc(hidden)]
@@ -831,6 +831,37 @@ pub unsafe trait KnownLayout {
831831
let meta = Self::PointerMetadata::from_elem_count(0);
832832
Self::raw_from_ptr_len(NonNull::dangling(), meta)
833833
}
834+
835+
/// Computes the size of an object of type `Self` with the given pointer
836+
/// metadata.
837+
///
838+
/// # Safety
839+
///
840+
/// `size_for_metadata` promises to return `None` if and only if the
841+
/// resulting size would not fit in a `usize`. Note that the returned size
842+
/// could exceed the actual maximum valid size of an allocated object,
843+
/// `isize::MAX`.
844+
///
845+
/// # Examples
846+
///
847+
/// ```
848+
/// use zerocopy::KnownLayout;
849+
///
850+
/// assert_eq!(u8::size_for_metadata(()), Some(1));
851+
/// assert_eq!(u16::size_for_metadata(()), Some(2));
852+
/// assert_eq!(<[u8]>::size_for_metadata(42), Some(42));
853+
/// assert_eq!(<[u16]>::size_for_metadata(42), Some(84));
854+
///
855+
/// // This size exceeds the maximum valid object size (`isize::MAX`):
856+
/// assert_eq!(<[u8]>::size_for_metadata(usize::MAX), Some(usize::MAX));
857+
///
858+
/// // This size, if computed, would exceed `usize::MAX`:
859+
/// assert_eq!(<[u16]>::size_for_metadata(usize::MAX), None);
860+
/// ```
861+
#[inline(always)]
862+
fn size_for_metadata(meta: Self::PointerMetadata) -> Option<usize> {
863+
meta.size_for_metadata(Self::LAYOUT)
864+
}
834865
}
835866

836867
/// Efficiently produces the [`TrailingSliceLayout`] of `T`.

src/ref.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ where
479479
#[inline]
480480
pub fn from_bytes_with_elems(source: B, count: usize) -> Result<Ref<B, T>, CastError<B, T>> {
481481
static_assert_dst_is_not_zst!(T);
482-
let expected_len = match count.size_for_metadata(T::LAYOUT) {
482+
let expected_len = match T::size_for_metadata(count) {
483483
Some(len) => len,
484484
None => return Err(SizeError::new(source).into()),
485485
};
@@ -533,7 +533,7 @@ where
533533
count: usize,
534534
) -> Result<(Ref<B, T>, B), CastError<B, T>> {
535535
static_assert_dst_is_not_zst!(T);
536-
let expected_len = match count.size_for_metadata(T::LAYOUT) {
536+
let expected_len = match T::size_for_metadata(count) {
537537
Some(len) => len,
538538
None => return Err(SizeError::new(source).into()),
539539
};
@@ -579,7 +579,7 @@ where
579579
count: usize,
580580
) -> Result<(B, Ref<B, T>), CastError<B, T>> {
581581
static_assert_dst_is_not_zst!(T);
582-
let expected_len = match count.size_for_metadata(T::LAYOUT) {
582+
let expected_len = match T::size_for_metadata(count) {
583583
Some(len) => len,
584584
None => return Err(SizeError::new(source).into()),
585585
};

src/util/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ pub(crate) unsafe fn new_box<T>(
323323
where
324324
T: ?Sized + crate::KnownLayout,
325325
{
326-
let size = match meta.size_for_metadata(T::LAYOUT) {
326+
let size = match T::size_for_metadata(meta) {
327327
Some(size) => size,
328328
None => return Err(AllocError),
329329
};
@@ -515,7 +515,7 @@ mod len_of {
515515
// This can return `None` if the metadata describes an object
516516
// which can't fit in an `isize`.
517517
Some(meta) => {
518-
let size = match meta.size_for_metadata(T::LAYOUT) {
518+
let size = match T::size_for_metadata(meta) {
519519
Some(size) => size,
520520
None => return Err(MetadataCastError::Size),
521521
};

0 commit comments

Comments
 (0)