This question already has an answer here:
I am attempting to figure the most Rust-like way of converting from a vector to array and back. These macros will work and can even be made generic with some unsafe blocks, but it all feels very un-Rust like.
I would appreciate any input and hold no punches, I think this code is far from nice or optimal. I have only played with Rust for a few weeks now and chasing releases and docs so really appreciate help.
macro_rules! convert_u8vec_to_array {
($container:ident, $size:expr) => {{
if $container.len() != $size {
None
} else {
use std::mem;
let mut arr : [_; $size] = unsafe { mem::uninitialized() };
for element in $container.into_iter().enumerate() {
let old_val = mem::replace(&mut arr[element.0],element.1);
unsafe { mem::forget(old_val) };
}
Some(arr)
}
}};
}
fn array_to_vec(arr: &[u8]) -> Vec<u8> {
let mut vector = Vec::new();
for i in arr.iter() {
vector.push(*i);
}
vector
}
fn vector_as_u8_4_array(vector: Vec<u8>) -> [u8;4] {
let mut arr = [0u8;4];
for i in (0..4) {
arr[i] = vector[i];
}
arr
}
The code seems fine to me, although there's a very important safety thing to note: there can be no panics while
arr
isn't fully initialised. Running destructors on uninitialised memory could easily lead be undefined behaviour, and, in particular, this means thatinto_iter
and thenext
method of it should never panic (I believe it is impossible for theenumerate
andmem::*
parts of the iterator to panic given the constraints of the code).That said, one can express the
replace
/forget
idiom with a single function:std::ptr::write
.Although, I would write it as:
Similarly, one can apply some iterator goodness to the
u8
specialised versions:Although the first is probably better written as
arr.to_vec()
, and the second asAlthough that function is unstable currently, and hence only usable on nightly.