How to "memcpy" bytes in stable rust

A FAQ is how to copy data from one slice to another in the best way.

Update in March 2017:

Since Rust 1.9.0 we have the slice method .copy_from_slice() which makes memcpy readily available on all slices of T: Copy types. Note that the input and output must be sliced to equal lengths.

For T: Clone types we have .clone_from_slice().

The information below is obsolete.


There is some API to copy between slices:

  1. std::slice::bytes::copy_memory
  2. [T]::clone_from_slice
  3. std::ptr::copy_nonoverlapping

Unfortunately these are either unstable (1 & 2) or unsafe (3).

However, the I/O traits are implemented for Vec<u8>, &[u8] and &mut [u8], so the trait Write actually offers a stable and safe API to copy from one buffer to another, and it just uses a std::ptr::copy_nonoverlapping in the implementation.

(The following code in playpen)

use std::io::Write;

/// Copy data in `from` into `to`, until the shortest
/// of the two slices.
///
/// Return the number of bytes written.
fn byte_copy(from: &[u8], mut to: &mut [u8]) -> usize {
    to.write(from).unwrap()
}

The fact remains that users keep asking for the best way to copy from one slice or vec to another. We might want to consider stabilizing clone_from_slice for this purpose. To work around this for non-bytes the user typically has to use a for loop, and that is also a bit complicated to do efficiently (see how to "zip" two slices).

5 Likes

Interestingly, this is a place where I've been using arrayref, so long as I have a static number of elements to copy:

array_mut_ref![to; 0; 32] = *array_ref![from; 0; 32];

It's a nice trick, and would be nicer with a nicer API from arrayref. I dream of one day submitting an RFC for a pretty syntax for borrowing array references from slices (as arrayref does). But I would want to wait for RFC 495 before proposing this, since that RFC will allow arrayref to be implemented without using unsafe (which will be nice).

Addendum:

  • using write_all from Write for Vec<u8> is stable and safe way to do Vec::push_all (not yet stable) for byte elements

  • clone_from_slice is on its way to stabilization (Tracking Issue)

  • copy_memory has been marked deprecated

1 Like