Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is an idiomatic way to fill a user-supplied buffer when reading bytes?

Tags:

io

rust

Read::read returns the number of bytes that it actually read, which can be less than the requested buffer. In many cases, it is acceptable to make multiple calls to read in order to completely fill the buffer.

I have this code, but it seems pretty ungainly:

use std::io::{self, Read};

fn read_complete<R>(mut rdr: R, buf: &mut [u8]) -> io::Result<()>
    where R: Read
{
    let mut total_read = 0;

    loop {
        let window = &mut buf[total_read..];
        let bytes_read = try!(rdr.read(window));

        // Completely filled the buffer
        if window.len() == bytes_read {
            return Ok(());
        }

        // Unable to read anything
        if bytes_read == 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "Unable to read complete buffer"));
        }

        // Partial read, continue
        total_read += bytes_read;
    }
}

fn main() {}

Is there a function in the standard library that will abstract this work away for me?

like image 653
Shepmaster Avatar asked Jul 12 '15 22:07

Shepmaster


2 Answers

This answer applies to versions of Rust before 1.6.0

Not as far as I know.

Looking at the byteorder crate's source, there's a read_all method defined there, too:

fn read_full<R: io::Read + ?Sized>(rdr: &mut R, buf: &mut [u8]) -> Result<()> {
    let mut nread = 0usize;
    while nread < buf.len() {
        match rdr.read(&mut buf[nread..]) {
            Ok(0) => return Err(Error::UnexpectedEOF),
            Ok(n) => nread += n,
            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {},
            Err(e) => return Err(From::from(e))
        }
    }
    Ok(())
}

Note that this deals with interrupted IO operations.

There's also a proposed RFC, that was submitted several months ago, went to final comment period, then changed enough that it was taken out of final comment period and is waiting for another go-around.

It turns out that this is unexpectedly complicated. :P

like image 110
DK. Avatar answered Nov 16 '22 19:11

DK.


Since the RFC mentioned in the other answer is accepted, implemented, and available in Rust 1.6.0, you can just use the Reader::read_exact() method:

try!(r.read_exact(&mut buf))

Or, using the ? operator introduced in Rust 1.13.0:

r.read_exact(&mut buf)?
like image 35
Sergey Bugaev Avatar answered Nov 16 '22 17:11

Sergey Bugaev