Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert vectors to arrays and back [duplicate]

Tags:

rust

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
}
like image 274
dirvine Avatar asked Apr 21 '15 22:04

dirvine


People also ask

How do I copy a vector element to an array?

The elements of a vector are contiguous. Otherwise, you just have to copy each element: double arr[100]; std::copy(v. begin(), v.

How do you duplicate an array in C++?

In C++ an array can be copied manually (by hand) or by using the std::copy() function, from the C++ algorithm library. In computer programming, there is shallow copying and there is deep copying. Shallow copying is when two different array names (old and new), refer to the same content.


1 Answers

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 that into_iter and the next method of it should never panic (I believe it is impossible for the enumerate and mem::* 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.

for (idx, element) in $container.into_iter().enumerate() {
    ptr::write(&mut arr[idx], element);
}

Although, I would write it as:

for (place, element) in arr.iter_mut().zip($container.into_iter()) {
    ptr::write(place, element);
}

Similarly, one can apply some iterator goodness to the u8 specialised versions:

fn array_to_vec(arr: &[u8]) -> Vec<u8> {
     arr.iter().cloned().collect()
}
fn vector_as_u8_4_array(vector: Vec<u8>) -> [u8;4] {
    let mut arr = [0u8;4];
    for (place, element) in arr.iter_mut().zip(vector.iter()) {
        *place = *element;
    }
    arr
}

Although the first is probably better written as arr.to_vec(), and the second as

let mut arr = [0u8; 4];
std::slice::bytes::copy_memory(&vector, &mut arr);
arr

Although that function is unstable currently, and hence only usable on nightly.

like image 57
huon Avatar answered Oct 05 '22 14:10

huon