128. slice::copy_within — Shift Bytes In-Place Without Fighting the Borrow Checker
You want to copy buf[2..5] over buf[0..3] — same buffer, no allocation. Reach for copy_from_slice and the borrow checker says no. copy_within is the one-call answer.
The two-borrow trap
The obvious code can’t compile — buf would be borrowed mutably and immutably at the same time:
| |
The usual workarounds are noisy. split_at_mut to carve the slice into two non-overlapping halves:
| |
…which only works when source and destination land on opposite sides of the split. Otherwise you allocate a throwaway Vec just to break the borrow:
| |
copy_within is the primitive
<[T]>::copy_within(src, dest) copies a range of elements to a destination index inside the same slice — one call, no allocation, no split:
| |
It’s memmove semantics, so overlapping source and destination just work — the elements that get overwritten don’t matter, the surviving order does:
| |
Try writing that with split_at_mut — you can’t, the source and destination overlap.
A real shape: drop the first N from a Vec
Removing the first n elements without reallocating is copy_within plus a truncate:
| |
Same allocation, same backing buffer — the values just shift down. Vec::drain(..n) reads cleaner for one-offs, but copy_within is what you want when you’re already holding &mut [T] and can’t reach for Vec methods (think ring buffers, fixed-size scratch arrays, no_std crates).
Constraints
T: Copy is required — the method does a memmove, it doesn’t run destructors or call Clone. Source and destination ranges must both fit inside the slice; otherwise it panics. The destination is a single index (where the copy starts), not a range — the length is taken from the source range.
When to reach for it
Any time you’d otherwise write split_at_mut just to satisfy the borrow checker, or allocate a temporary buffer to break a self-borrow. copy_within reads as what you actually meant: move these bytes over there, in place.
Stable since Rust 1.37. Works on [T], Vec<T>, and any DerefMut<Target = [T]>.