feat: add TransparentWrapperAlloc trait (#111)

* feat: add TransparentWrapperAlloc trait

* implements wrap_vec and peel_vec

* fix: review comments

* remote asserts as they don't do anything
* avoid issue with stacked borrows
This commit is contained in:
Edward 2022-06-29 01:55:31 +02:00 committed by GitHub
parent e8cd71df54
commit abe55e525e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 0 deletions

View File

@ -297,3 +297,57 @@ pub fn pod_collect_to_vec<
dst_bytes[..src_size].copy_from_slice(src_bytes); dst_bytes[..src_size].copy_from_slice(src_bytes);
dst dst
} }
/// An extension trait for `TransparentWrapper` and alloc types.
pub trait TransparentWrapperAlloc<Inner: ?Sized>: TransparentWrapper<Inner> {
/// Convert a vec of the inner type into a vec of the wrapper type.
fn wrap_vec(s: Vec<Inner>) -> Vec<Self>
where
Self: Sized,
Inner: Sized
{
let mut s = core::mem::ManuallyDrop::new(s);
let length = s.len();
let capacity = s.capacity();
let ptr = s.as_mut_ptr();
unsafe {
// SAFETY:
// * ptr comes from Vec (and will not be double-dropped)
// * the two types have the identical representation
// * the len and capacity fields are valid
Vec::from_raw_parts(
ptr as *mut Self,
length,
capacity
)
}
}
/// Convert a vec of the wrapper type into a vec of the inner type.
fn peel_vec(s: Vec<Self>) -> Vec<Inner>
where
Self: Sized,
Inner: Sized
{
let mut s = core::mem::ManuallyDrop::new(s);
let length = s.len();
let capacity = s.capacity();
let ptr = s.as_mut_ptr();
unsafe {
// SAFETY:
// * ptr comes from Vec (and will not be double-dropped)
// * the two types have the identical representation
// * the len and capacity fields are valid
Vec::from_raw_parts(
ptr as *mut Inner,
length,
capacity
)
}
}
}
impl<I: ?Sized, T: TransparentWrapper<I>> TransparentWrapperAlloc<I> for T {}

View File

@ -61,4 +61,21 @@ fn test_transparent_wrapper() {
Foreign::default(), Foreign::default(),
])); ]));
// counterpart? // counterpart?
#[cfg(feature = "extern_crate_alloc")]
{
use bytemuck::allocation::TransparentWrapperAlloc;
let a: Vec<Foreign> = vec![Foreign::default(); 2];
let b: Vec<Wrapper> = Wrapper::wrap_vec(a);
assert_eq!(
bytemuck::cast_slice::<Wrapper, u8>(b.as_slice()), &[0u8, 0]
);
let c: Vec<Foreign> = Wrapper::peel_vec(b);
assert_eq!(
bytemuck::cast_slice::<Wrapper, u8>(Wrapper::wrap_slice(c.as_slice())), &[0, 0]
);
}
} }