Error on a concrete mem::swap wrapper!

Hello everyone!
I'm doing this

fn swap_slice_u8(a: &mut [u8], b: &mut [u8]) {
    std::mem::swap(a, b);
}

And getting this error message:

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
   --> src/main.rs:2:5
    |
2   |     std::mem::swap(a, b);
    |     ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `std::mem::swap`

But as far as i know/believe, references to slices are Sized.
Any tips?


UPDATE: i can do this instead to compile:

fn swap_slice_u8<'a>(mut a: &'a mut [u8], mut b: &'a mut [u8]) {
    std::mem::swap(&mut a, &mut b);
}

But this way only references to slices are swaped not the slices itself!


UPDATE#2: BTW it was a silly question as now i can figure out the problem!

swap is defined like this:

pub fn swap<T>(x: &mut T, y: &mut T)

In your call, T is therefore [u8] and not &mut [u8], which is not Sized. In general, each [u8] represents a fixed portion of memory with an unknown (at compile-time) length. If a and b have different lengths, swapping them would be impossible, as the larger one won't fit inside the space of the smaller.

You can write something like this, which will swap the first n items, where n is the length of the shorter slice:

pub fn swap_slice_u8(a: &mut [u8], b: &mut [u8]) {
    for (a_n, b_n) in a.iter_mut().zip(b.iter_mut()) {
        std::mem::swap(a_n, b_n);
    }
}
1 Like

Thanks for workaround!

Alternately, if you do know the size of the slices at compile time, you can write something like this:

pub fn swap_slice_u8<const N: usize>(
    a: &mut [u8],
    b: &mut [u8],
) -> Result<(), std::array::TryFromSliceError> {
    let a_arr: &mut [u8; N] = a.try_into()?;
    let b_arr: &mut [u8; N] = b.try_into()?;
    std::mem::swap(a_arr, b_arr);
    Ok(())
}

fn main() {
    let mut v1 = vec![2,3,4];
    let mut v2 = vec![11,13,17];

    swap_slice_u8::<3>(&mut v1, &mut v2).unwrap();

    dbg!((v1, v2));
}
1 Like

Very nice!

There’s also <[T]>::swap_with_slice, which is likely more efficient than the swap_slice_u8 function in the first answer. If you want to support different-length slices the same way, you can limit both arguments to &mut foo[..n] where n = a.len().min(b.len()).

4 Likes

Nice and neat!
Let me choose this as the short and precise answer!
Thanks to @2e71828 for workarounds and initial answers!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.