Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you copy between arrays of different sizes in Rust?

Tags:

arrays

rust

If I have two arrays of different sizes:

let mut array1 = [0; 8];
let array2 = [1, 2, 3, 4];

How would I copy array2 into the first 4 bytes of array1? I can take a mutable 4 byte slice of array1, but I'm not sure how or if I can assign into it.

like image 287
Paul D Avatar asked Aug 10 '14 03:08

Paul D


People also ask

How do you copy an array in Rust?

In this article, we will see how to solve Copy An Array in rust code with examples. let arr =["a","b","c"]; // ES6 way const copy = [... arr]; // older method const copy = Array. from(arr);

Do Rust arrays implement copy?

Arrays of any size implement the following traits if the element type allows it: Copy. Clone. Debug.

How do you find the size of an array in Rust?

The length of an array is the number of elements present in the array. We use the len() function to obtain this value.

How do you append to an array in Rust?

There is no way to do this in stable Rust; arrays cannot have values added or removed at runtime; their lengths are fixed at compile time.


3 Answers

Manually one can do

for (dst, src) in array1.iter_mut().zip(&array2) {
    *dst = *src
}

for a typical slice. However, there is a likely faster specialization in clone_from_slice:

dst[..4].clone_from_slice(&src)

A slightly older method is to use std::io::Write, which was implemented for &mut [u8].

use std::io::Write;
let _ = dst.write(&src)

This will write up to the end of dst and return how many values were written in a Result. If you use write_all, this will return an Err if not all bytes could be written.

like image 180
Veedrac Avatar answered Nov 26 '22 08:11

Veedrac


The most flexible way is to use iterators to handle each element successively:

for (place, data) in array1.iter_mut().zip(array2.iter()) {
    *place = *data
}

.mut_iter creates an Iterator that yields &mut u8, that is, mutable references pointing into the slice/array. iter does the same but with shared references. .zip takes two iterators and steps over them in lock-step, yielding the elements from both as a tuple (and stops as soon as either one stops).

If you need/want to do anything 'fancy' with the data before writing to place this is the approach to use.

However, the plain copying functionality is also provided as single methods,

  • .copy_from, used like array1.copy_from(array2).

  • std::slice::bytes::copy_memory, although you will need to trim the two arrays because copy_memory requires they are the same length:

    use std::cmp;
    use std::slice::bytes;
    
    let len = cmp::min(array1.len(), array2.len());
    bytes::copy_memory(array1.mut_slice_to(len), array2.slice_to(len));
    

    (If you know that array1 is always longer than array2 then bytes::copy_memory(array1.mut_slice_to(array2.len()), array2) should also work.)

At the moment, the bytes version optimises the best, down to a memcpy call, but hopefully rustc/LLVM improvements will eventually take them all to that.

like image 36
huon Avatar answered Nov 26 '22 06:11

huon


You could simply use copy_from_slice() and use Range & Co:

fn main() {
    let mut dest = [0; 8];
    let src = [1, 2, 3, 4];

    dest[..4].copy_from_slice(&src);

    assert_eq!(dest, [1, 2, 3, 4, 0, 0, 0, 0]);
}

Inverse case:

fn main() {
    let src = [1, 2, 3, 4, 5, 6, 7, 8];
    let mut dest = [0; 4];

    dest.copy_from_slice(&src[2..6]);

    assert_eq!(dest, [3, 4 ,5, 6]);
}

Combined case:

fn main() {
    let src = [1, 2, 3, 4, 5, 6, 7, 8];
    let mut dest = [0; 4];

    dest[1..3].copy_from_slice(&src[3..5]);

    assert_eq!(dest, [0, 4, 5, 0]);
}
like image 27
Stargateur Avatar answered Nov 26 '22 08:11

Stargateur