Description
Currently the GzDecoder
new
method eagerly attempts to read the header information in the constructor. It has match
statements for if the io should be non-blocking, but in general this will never happen. I think it would be more proper to follow the usual pattern of constructors in Rust not doing work by trying to read the underlying stream, and instead lazily determine the state when a read is requested.
The case where this eager reading behavior is a problem is when there are multiple fifo stream being initialized. The first decoder created will block on trying to read from the underlying stream before any work as been done, preventing the rest of the application from working. I don't think it is technically incorrect, but in general Rust prefers being lazy with computation especially when it has side effects.
The current workaround that I have to use to avoid generating read
syscalls during construction is pretty hacky:
enum LazyGzipReader {
Uninitialized(File),
Initialized(MultiGzDecoder<BufReader<File>>),
}
impl Read for LazyGzipReader {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self {
LazyGzipReader::Uninitialized(file) => {
*self = LazyGzipReader::Initialized(MultiGzDecoder::new(BufReader::new(
file.try_clone()?,
)));
self.read(buf)
}
LazyGzipReader::Initialized(reader) => reader.read(buf),
}
}
}