diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 74bcdaa..802348a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -65,10 +65,10 @@ jobs: components: miri - uses: actions/checkout@v2 # Note(Lokathor): We got some cached json errors, and so we cargo clean for this run. - - run: cargo clean + - run: rm -fr target - run: cargo miri test --verbose --no-default-features - run: cargo miri test --verbose --all-features - - run: cd derive && cargo clean && cargo miri test --verbose --all-features + - run: cd derive && rm -fr target && cargo miri test --verbose --all-features sanitizer-test: name: Test with -Zsanitizer=${{ matrix.sanitizer }} diff --git a/src/allocation.rs b/src/allocation.rs index 07de49f..33f796c 100644 --- a/src/allocation.rs +++ b/src/allocation.rs @@ -9,6 +9,7 @@ use super::*; use alloc::{ alloc::{alloc_zeroed, Layout}, boxed::Box, + vec, vec::Vec, }; use core::convert::TryInto; @@ -112,7 +113,8 @@ pub fn try_zeroed_slice_box( // This will also not allocate. return Ok(Vec::new().into_boxed_slice()); } - // For Pod types, the layout of the array/slice is equivalent to repeating the type. + // For Pod types, the layout of the array/slice is equivalent to repeating the + // type. let layout_length = size_of::().checked_mul(length).ok_or(())?; assert!(layout_length != 0); let layout = @@ -178,3 +180,33 @@ pub fn try_cast_vec( Ok(unsafe { Vec::from_raw_parts(ptr, length, capacity) }) } } + +/// This "collects" a slice of pod data into a vec of a different pod type. +/// +/// Unlike with [`cast_slice`] and [`cast_slice_mut`], this will always work. +/// +/// The output vec will be of a minimal size/capacity to hold the slice given. +/// +/// ```rust +/// # use bytemuck::*; +/// let halfwords: [u16; 4] = [5, 6, 7, 8]; +/// let vec_of_words: Vec = pod_collect_to_vec(&halfwords); +/// if cfg!(target_endian = "little") { +/// assert_eq!(&vec_of_words[..], &[0x0006_0005, 0x0008_0007][..]) +/// } else { +/// assert_eq!(&vec_of_words[..], &[0x0005_0006, 0x0007_0008][..]) +/// } +/// ``` +pub fn pod_collect_to_vec(src: &[A]) -> Vec { + let src_size = size_of_val(src); + // Note(Lokathor): dst_count is rounded up so that the dest will always be at + // least as many bytes as the src. + let dst_count = src_size / size_of::() + + if src_size % size_of::() != 0 { 1 } else { 0 }; + let mut dst = vec![B::zeroed(); dst_count]; + + let src_bytes: &[u8] = cast_slice(src); + let dst_bytes: &mut [u8] = cast_slice_mut(&mut dst[..]); + dst_bytes[..src_size].copy_from_slice(src_bytes); + dst +}