How does `std::mem::swap` work?

The function does actually make a copy internally: here is its source extracted from the documentation:

pub fn swap<T>(x: &mut T, y: &mut T) {
    unsafe {
        // Give ourselves some scratch space to work with
        let mut t: T = uninitialized();

        // Perform the swap, `&mut` pointers never alias
        ptr::copy_nonoverlapping(&*x, &mut t, 1);
        ptr::copy_nonoverlapping(&*y, x, 1);
        ptr::copy_nonoverlapping(&t, y, 1);

        // y and t now point to the same thing,
        // but we need to completely forget `t`
        // because it's no longer relevant.
        forget(t);
    }
}

The previous answer is correct in semantics, but outdated in exact details.

Logically, swapping two values works by reading value A into a temporary location, copying B on top of A, then writing the temporary value back into B. There is a brief period where the same value exists twice in memory. This is why the implementation of these functions requires unsafe code, as only a human can guarantee that Rust's safety requirements are upheld.

As of Rust 1.43.0, mem::swap is implemented as:

pub fn swap<T>(x: &mut T, y: &mut T) {
    // SAFETY: the raw pointers have been created from safe mutable references satisfying all the
    // constraints on `ptr::swap_nonoverlapping_one`
    unsafe {
        ptr::swap_nonoverlapping_one(x, y);
    }
}

swap_nonoverlapping_one is private, but its implementation is:

pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
    // For types smaller than the block optimization below,
    // just swap directly to avoid pessimizing codegen.
    if mem::size_of::<T>() < 32 {
        let z = read(x);
        copy_nonoverlapping(y, x, 1);
        write(y, z);
    } else {
        swap_nonoverlapping(x, y, 1);
    }
}

You can see the documentation for ptr::copy_nonoverlapping and ptr::swap_nonoverlapping. The latter is basically a highly-optimized version of copying for larger values.

Tags:

Memory

Swap

Rust