2

I have the following code:

use std::io::{Cursor, BufReader, Read};

fn main() {
    let string = String::from("Cello");
    let bytes = string.as_bytes();
    let cursor = Cursor::new(bytes);
    let mut reader = BufReader::new(cursor);
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    assert_eq!(4, buf.capacity());
    reader.read_exact(&mut buf);
    assert_eq!(4, buf.len()); //thread 'main' panicked at 'assertion failed: `(left == right)`
                              //left: `4`, right: `0`'
}

According to std::io::read_exact's documentation, it will "read the exact number of bytes required to fill buf". But in this case, despite having the capacity for 4 bytes, no bytes are read into the vec. What's going on?

Svetlin Zarev
  • 14,713
  • 4
  • 53
  • 82
abipip
  • 21
  • 2
  • 1
    I am noticing more and more questions where `Vec::with_capacity` is misunderstood in exactly this way. I was about to propose an improvement to the docs of `with_capacity`, only to find that the docs _already_ warn (in more than one place) that the returned vector is nothing other than empty. I guess the problem is that dynamic languages don't expose the concept of capacity, so the name of the method sounds like the "give me an uninitialized vector" that the OP was likely after. – user4815162342 Aug 30 '21 at 07:46
  • 1
    Please note that `read_exact` returns a `Result` which you should always check, propagate with `?` or `unwrap` to know whether or not it succeeded. The compiler gives you a warning about this. – trent Aug 30 '21 at 09:40

1 Answers1

8

The read_exact() method expects a &mut [u8] slice - i.e. it needs to know the buffer length. But you are passing a slice with length of 0 (the capacity of the buffer is distinct from its length):

// capacity = 4
// length = 0
let mut buf: Vec<u8> = Vec::with_capacity(4);

// the &mut [u8] slice has a length of 0
reader.read_exact(&mut buf);

As a result, the method tries to read 0 bytes. In order to fix the issue you have to pass a non-zero length buffer:

// capacity = 4
// length = 4
let mut buf: Vec<u8> = vec![0; 4];

// the &mut [u8] slice has a length of 4
reader.read_exact(&mut buf).expect("read failed");

and last but not least - .read_exact() can fail. If you do not check the returned Result you may end up with a buffer with invalid content.

Svetlin Zarev
  • 14,713
  • 4
  • 53
  • 82