pod_collect_to_vec (#50)

* add the requested feature.

* maybe we need to be more aggressive than cargo clean is?
This commit is contained in:
Lokathor 2021-01-13 16:49:11 -07:00 committed by GitHub
parent df53958735
commit 7e76723b3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 3 deletions

View File

@ -65,10 +65,10 @@ jobs:
components: miri components: miri
- uses: actions/checkout@v2 - uses: actions/checkout@v2
# Note(Lokathor): We got some cached json errors, and so we cargo clean for this run. # 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 --no-default-features
- run: cargo miri test --verbose --all-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: sanitizer-test:
name: Test with -Zsanitizer=${{ matrix.sanitizer }} name: Test with -Zsanitizer=${{ matrix.sanitizer }}

View File

@ -9,6 +9,7 @@ use super::*;
use alloc::{ use alloc::{
alloc::{alloc_zeroed, Layout}, alloc::{alloc_zeroed, Layout},
boxed::Box, boxed::Box,
vec,
vec::Vec, vec::Vec,
}; };
use core::convert::TryInto; use core::convert::TryInto;
@ -112,7 +113,8 @@ pub fn try_zeroed_slice_box<T: Zeroable>(
// This will also not allocate. // This will also not allocate.
return Ok(Vec::new().into_boxed_slice()); 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::<T>().checked_mul(length).ok_or(())?; let layout_length = size_of::<T>().checked_mul(length).ok_or(())?;
assert!(layout_length != 0); assert!(layout_length != 0);
let layout = let layout =
@ -178,3 +180,33 @@ pub fn try_cast_vec<A: Pod, B: Pod>(
Ok(unsafe { Vec::from_raw_parts(ptr, length, capacity) }) 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<u32> = 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<A: Pod, B: Pod>(src: &[A]) -> Vec<B> {
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::<B>()
+ if src_size % size_of::<B>() != 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
}