We have std::io::BufReader
and std::io::BufWriter
in the std. However, they cannot be easily composed to create a thing similar to BufWriter<BufReader<T>>
for some arbitrary T: Read + Write
, because BufReader<T>
does not implement Write
and BufWriter<T>
does not implement Read
. Further more, we cannot create a BufWriter<&mut T>
and a BufReader<&mut T>
at the same time since this violates the borrow check rules.
There are a few types in the std such as File
and TcpStream
that can be read and written through buffered readers and writers at the same time. Since &File
and &TcpStream
implement both Read
and Write
, we can create BufReader<&File>
and BufWriter<&File>
at the same time without violating borrow check rules. This approach introduces unnecessary unsafe
code in certain circumstances, though. For example, if I want to put a BufReader<&File>
and a BufWriter<&File>
, which read and write into the same underlying File
, into a single struct:
struct Foo {
reader: BufReader<&'static File>,
writer: BufWriter<&'static File>,
}
impl Foo {
fn new(f: File) -> Self {
let boxed_file = Box::leak(Box::new(f));
Self {
reader: BufReader::new(boxed_file),
writer: BufReader::new(boxed_file),
}
}
}
impl Drop for Foo {
fn drop(&mut self) {
self.writer.flush().unwrap();
let boxed_file = *self.reader.get_ref();
unsafe {
Box::from_raw(boxed_file as *const File as *mut File);
}
}
}
I come up with 2 approaches to support buffered reader and writer:
First, we can add a new struct named BufRw
or similar to the std, which behaves exactly as the simple combination of BufReader
and BufWriter
:
pub struct BufRw<T: Read + Write> { /* fields omitted */ }
impl<T: Read + Write> Read for BufRw<T> { /* omitted */ }
impl<T: Read + Write> Write for BufRw<T> { /* omitted */ }
impl<T: Read + Write> BufRead for BufRw<T> { /* omitted */ }
impl<T: Read + Write> Seek for BufRw<T> { /* omitted */ }
Second, we can let BufReader
and BufWriter
implement Write
and Read
, correspondingly:
impl<R: Write> Write for BufReader<R> { /* omitted */ }
impl<W: Read + Write> Read for BufWriter<W> { /* omitted */ }
So that BufReader
and BufWriter
can compose.
Do you think that supporting buffered reader + writer in std is a good idea? If so, which approach do you prefer?