Introduce a function to align a slice to the right alignment
Closed this issue · 3 comments
Hello @Lokathor,
I wanted to switch from zerocopy to bytemuck for multiple reasons, and one of the missing features for both crates is the ability to realign a slice of type A
into a Vec
of type B
, which is allowed to allocate. What do you think about introducing this to this crate (under the allocation
feature) and introducing that for Box
?
This function would be preferable not to restrict the size (where the length of the input must be the same as the output Vec
). It would make this function useless for when you want to transpose differently sized types (e.g. u8
into u16
) like for the try_cast_vec
function.
Another solution would be to make the try_cast_vec
function change the length and capacity of the Vec
. This seems a lot better but does seem to be a breaking change in the sense that more results could return an Ok(Vec)
instead of an error and that the Vec
is no more of the same length than the input one.
// An idea of the possible function signature
fn try_cast_slice_realign_vec<A: Pod, B: Pod>(input: &[A]) -> Result<Vec<B>, PodCastError>;
// Another even better function signature which will allocate only if alignment is invalid
// Note that Cow is in the alloc Rust library
fn try_cast_slice_realign_cow<A: Pod, B: Pod>(input: &[A]) -> Result<Cow<[B]>, PodCastError>;
Could maybe be implemented this way:
let bytes = bytes_of(input);
let len = input.len();
let elem_size = mem::size_of::<B>();
// ensure that it is the alignment that is wrong
// and the length is valid
if len % elem_size == 0 && align_of::<A>() != align_of::<B>() {
let elems = len / elem_size;
let mut vec = Vec::<B>::with_capacity(elems);
unsafe {
let dst = vec.as_mut_ptr() as *mut u8;
ptr::copy_nonoverlapping(bytes.as_ptr(), dst, len);
vec.set_len(elems);
}
Ok(Cow::Owned(vec))
}
The capacity and alignment of the vec's allocation can't change during casting, it causes UB in the allocator.
I'm not sure I'm fully clear on the requirements here. Can't you just cast the slice, then gather the slice into a new vec once you've cast it?
let new_slice: &[u16] = cast_slice(old_slice);
let new_vec: Vec<_> = new_slice.iter().copied().collect();
What I would like to be able to do is to cast a slice of bytes into an aligned Vec
of T
even if the bytes are not correctly aligned to be freely cast. The easiest way to do that, in my mind, is to create an empty Vec
of T
with the right alignment for T
and enough capacity, and then copy the bytes into the Vec
directly. What do you think?
Ah, interesting. I follow now.
I'm sure we could make something like that.
The term "cast" doesn't quite fit, that's why i was confused, since you're doing a new allocation and a copy and all that, but you could turn a alice of pod into a vec of some other pod type and ignore the alignment of the source slice in the process.
This seems like a small enough request to handle it the next time i sit down to do Rust. Might have time tonight even.