I have a vector of length L where L is cleanly divisible by N. I would like to convert it in-place (i.e. without copying) into a vector of length L/N of arrays of length N. Is this possible to do soundly if (and I realize this is a big if) the alignment checks out?

The main challenge here is the capacity. It's not enough for the length to be a multiple of `N`

, the capacity must also be a multiple of `N`

. However, if those are both the cases, then it can be done:

```
fn to_arr<const N: usize, T>(mut vec: Vec<T>) -> Vec<[T; N]> {
assert!(vec.len() % N == 0);
assert!(vec.capacity() % N == 0);
let len = vec.len() / N;
let cap = vec.capacity() / N;
let ptr = vec.as_mut_ptr();
std::mem::forget(vec);
unsafe {
Vec::from_raw_parts(ptr.cast(), len, cap)
}
}
```

You may find it more reliable to convert boxes instead, as there is no capacity to worry about:

```
fn to_arr_box<const N: usize, T>(b: Box<[T]>) -> Box<[[T; N]]> {
assert!(b.len() % N == 0);
let len = b.len() / N;
let ptr = Box::into_raw(b).cast::<[T; N]>();
unsafe {
Box::from_raw(std::ptr::slice_from_raw_parts_mut(ptr, len))
}
}
```

You can convert boxes to and from vectors, so it can also be used to convert vectors.

I think it’s generally preferable to do this as

```
let mut vec = ManuallyDrop::new(vec);
let ptr = vec.as_mut_ptr();
```

to avoid any potential issues that *moving* the `vec`

into the `mem::forget()`

call could cause. Miri doesn’t seem to mind, but better safe than sorry, and using `ManuallyDrop`

is also what the standard library's (unstable) `into_raw_parts`

uses.

On nightly you can use `array_chunks().collect()`

. It'll either keep the allocation or call realloc if it's not a multiple. Adding the appropriate assert will show that it doesn't realloc if capacity fits.

https://docs.rs/bytemuck/latest/bytemuck/allocation/fn.cast_vec.html is the pre-packaged way to do this, if you're okay with pulling in a crate.

Of course for T to [T; N] casts those bounds are a little over restrictive, so maybe the crate should add a version just for the array case some day.

That would be nice to have. It could be even more general as "anything that is laid out like a `[T; N]`

", to support cases like `#[repr(C)] struct Vec2<T> { x: T, y: T }`

, as well as `T`

itself.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.