std::io::Read on a [u8]

In a test, I'm trying to pass a fake std::io::Read to some code I'm testing.

However, I can't seem to figure out how to use an array or a slice as a Read. I can see there's an impl and the error message indicates that I'm doing something wrong, but I can't see what the problem is.

Here's a minimal reproduction of the problem:

use std::io::Read;

fn do_the_read<R: Read>(r: &mut R) {
  // Imagine this function does something...
}

fn main() {
  let mut data = [0, 1, 2];
  let mut slice: &mut [u8] = data.as_mut();
  do_the_read(&mut slice);
}

Error message is:

<anon>:10:3: 10:14 error: the trait bound `[u8]: std::io::Read` is not satisfied [E0277]
<anon>:10   do_the_read(&mut slice);
            ^~~~~~~~~~~
<anon>:10:3: 10:14 help: see the detailed explanation for E0277
<anon>:10:3: 10:14 help: the following implementations were found:
<anon>:10:3: 10:14 help:   <&'a [u8] as std::io::Read>
<anon>:10:3: 10:14 note: required by `do_the_read`
error: aborting due to previous error

Here's a playground link: Rust Playground

PS: It's weird to me that I've successfully written as much Rust code as I have but still can't figure out simple stuff like this! I still don't have a great intuition for how slices work (like what it means to pass a bare [u8] to a function, or how to convert between arrays and slices) so if you have any advice there it'd help too!

2 Likes

The most imporant observation here is that Read is implemented for &[u8], not [u8]. That means that if you want to pass this to your function, which expects &mut R where R: Read you need to pass &mut &[u8]. Also, you don't need mut on data. So, for example:

let data = [0, 1, 2];
do_the_read(&mut data.as_ref());

Or, with one more step:

let data = [0, 1, 2];
let mut slice: &[u8] = &data;
do_the_read(&mut slice);
5 Likes

Thanks for looking! Your second example looks very close like the code I wrote, except that your slice is &[u8] while mine was &mut [u8]. Is that difference enough to make it not count as a Read?

The Read instance (per documentation) is for &[u8], not &mut [u8]. These two types are unrelated and not in general interchangeable, although a &mut [u8] can be converted into a &[u8] this cannot be done in lvalue context.

1 Like

I see, thanks for explaining. I had been working from the mistaken intuition that a &mut X is like a &X with extras, so a subtype, but your comment made me face that intuition and see it's plainly wrong.

One thing to be aware is that reading from a slice will modify the slice (only pointer and length, not the content).
In most cases, I prefer a io::Cursor<&[u8]>. It's more flexible and less confusing.

4 Likes