7

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.

malbarbo
  • 9,909
  • 1
  • 35
  • 53
Paul D
  • 263
  • 2
  • 4

3 Answers3

8

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.

Veedrac
  • 54,508
  • 14
  • 106
  • 164
6

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.

Peter Burns
  • 43,013
  • 7
  • 36
  • 56
huon
  • 83,735
  • 17
  • 214
  • 214
4

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]);
}
Stargateur
  • 20,831
  • 8
  • 51
  • 78