I am learning Rust by writing a simple ZIP handler. It works well, and I am happy with it. However, I want to return a Java like Stream for the extract_file() functionality.
Currently I am returning a Vec, which can be done by both STORE and DEFLATE pathways. (no compression and compressed).
However, I can't find a class or Trait that I can return for both these options where I don't pre-read the whole input data.
I am looking for a equivalent to Java's IO Streams:
Stream fileStream;
if (stored) {
return fileStream;
} else if (deflate) {
return DeflateStream(fileStream);
}
Any pointers?
CodePudding user response:
The std::io::Read
and std::io::Write
traits. They are implemented for files, TCP streams, and more. See std::io
's docs for more.
CodePudding user response:
Rust prefers to use the std::io::Read
and std::io::Write
traits for this. Additionally you will probably want to also add a requirement on std::io::Seek
so you can move your cursor within the byte stream.
Here is the general idea:
// Wrap around another Read type so we can use it as we parse
pub struct Deflater<R> {
stream: R,
}
impl<R> Deflater<R> {
pub fn new(stream: R) -> Self {
Deflater { stream }
}
}
// We provide our own Read implementation which can then refer to our inner Read type
impl<R: Read> Read for Deflater<R> {
fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
// Just defer to our inner read
self.stream.read(buffer)
}
}
As for your example, since we need to know a concrete type we have 2 approaches. We can either create an enum for it or use it as an anonymous trait.
fn box_approach<'a, R: 'a Read>(file_stream: R, stored: bool, deflate: bool) -> Box<dyn 'a Read> {
if stored {
return Box::new(file_stream)
} else if deflate {
return Box::new(Deflater::new(file_stream))
}
panic!("Must be either stored or deflate!")
}
fn enum_approach<R>(file_stream: R, stored: bool, deflate: bool) -> HandleStream<R> {
if stored {
return HandleStream::Stored(file_stream)
} else if deflate {
return HandleStream::Deflate(Deflater::new(file_stream))
}
panic!("Must be either stored or deflate!")
}
enum HandleStream<R> {
Stored(R),
Deflate(Deflater<R>),
}
impl<R: Read> Read for HandleStream<R> {
fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
match self {
HandleStream::Stored(stream) => stream.read(buffer),
HandleStream::Deflate(deflater) => deflater.read(buffer),
}
}
}