read_exact and EOF


#1

I think the read_exact method on std::io::Read is missing a fairly important signal: 0 bytes were read into the buffer and an EOF was encountered.

For example, you might be reading a file of fixed-size records, and you want to either read an entire record, or know you’ve reached EOF and no data is left to read (note: you need to read from a stream to know whether you’re at EOF or not), or signal something like “incomplete record at end file”. Currently, read_exact will return UnexpectedEof in both of these last two cases, even though in the former case an EOF might not at all be unexpected.

Should an additional error code be added to indicate this?


#2

Another possibility would be to give UnexpectedEof a payload that records the number of bytes that were read before it hit EOF.

The downside to this, of course, would be that io::ErrorKind will suddenly go from one byte to two pointers.

Another other possibility would be to give read_exact a custom error type along the lines of:

enum ReadExactError { Partial(usize), Other(io::Error) }

#3

In the RFC discussion for read_exact most people seemed pretty adamant that they didn’t want to increase the size of ErrorKind. I also think we shouldn’t have a custom return type as that breaks chaining with try! etc.

I’d be ok with a Result<usize,io:Error> which is guaranteed to either return Ok(0) on immediate EOF, or Ok(buflen) when read exactly and Err(_) otherwise.


#4

Just to be clear, a custom error type would not break try!, provided you have impl From<ReadExactError> for io::Error somewhere. You could also make using the combinators relatively painless by having a shorthand into_io_error method. Both of these could just turn Partial into UnexpectedEof.

I’d personally be leery of having read_exact return “success”, despite not actually reading anything. read_exact should be a convenience method; if you have to wrap it in yet another wrapper to get the “obvious” behaviour, it’s not doing its job.

Also, for those wondering: RFC #980, and it contains the following:

In the same way, if this method fails, there is no way to determine how many bytes were read before it determined it couldn’t completely fill the buffer.

Situations that require lower level control can still use read directly.


#5

Alternatively: Result<bool,io::Error>, this would allow one to write:

while (try!(stream.read_exact(&mut buf)) {
    ...
}