Search code examples
rustio

In Rust, I want to read from a stream or file to fill a buffer, and detect EOF


In Rust, I want to read (using BufReader) into a buffer array to fill it. I want to read the exact number of bytes, except in case of EOF, where reading less is fine. I have implemented a helper method myself, as follows, and that works. However I wonder if there is no convenience method that already does exactly that.

pub fn read_fully<R: Read>(read: &mut R, buffer: &mut [u8]) -> Result<usize, Error> {
    let mut count: usize = 0;
    loop {
        let r = read.read(&mut buffer[count..])?;
        if r == 0 {
            return Ok(count);
        }
        count += r;
    }
}

With each existing method I found there seems to be a problem:

  • "read" may read less (e.g. for stdin).
  • "read_exact" doesn't work well with EOF.
  • "read_to_end" expects a Vec and not an array, and will read everything, possibly expanding the vector.

Solution

  • Here's how you can do it shorter and cleaner, but using an experimental API:

    #![feature(read_buf, core_io_borrowed_buf)]
    
    use std::io::{BorrowedBuf, Error, ErrorKind, Read};
    
    pub fn read_fully<R: Read>(read: &mut R, buffer: &mut [u8]) -> Result<usize, Error> {
        let mut buffer = BorrowedBuf::from(buffer);
        match read.read_buf_exact(buffer.unfilled()) {
            Ok(()) => {}
            Err(err) if err.kind() == ErrorKind::UnexpectedEof => {}
            Err(err) => return Err(err),
        }
        Ok(buffer.len())
    }
    

    At this point, you may want to just have a BorrowedCursor as a parameter:

    #![feature(read_buf, core_io_borrowed_buf)]
    
    use std::io::{BorrowedCursor, Error, ErrorKind, Read};
    
    pub fn read_fully<R: Read>(read: &mut R, buffer: BorrowedCursor<'_>) -> Result<(), Error> {
        match read.read_buf_exact(buffer) {
            Err(err) if err.kind() == ErrorKind::UnexpectedEof => Ok(()),
            v => v,
        }
    }
    

    This allows neat things like using an uninitialized buffer.