How can I wrap the read portion of a struct which implements both Read and Write in a BufReader?

149 Views Asked by At

I am trying to read a line from a rustls::StreamOwned object. My first instinct was to wrap it in a BufReader, but the problem is that I need to be able to interleave my read_line() calls with write() calls, and I cannot use the underlying stream while BufReader has a mutable reference to it. What is the idiomatic way to solve this problem?

Sample Code:

let stream: rustls::StreamOwned = //blah
let r = BufReader::new(stream) // Can't pass a reference here since &rustls::StreamOwned doesn't implement the read trait
loop {
    let line: String;
    r.read_line(&line);
    stream.write(b"ping"); // Will fail to compile since r still owns the stream
}

Similar Question:

How to use a file with a BufReader and still be able to write to it?

The difference is that the reference type of the type I am dealing with does not implement the Read trait, so I cannot simply pass a reference to the BufReader.

1

There are 1 best solutions below

2
rodrigo On

The solution to your problem comes from the realization that BufReader does not contain a Read value, but a generic type that implements Read. In your case that is a literal StreamOwned, the actual type is not lost because you use a BufReader, or should I say a BufReader<StreamOwned>.

And you can access the inner value with BufReader::get_mut(). There is a note in the documentation that says:

It is inadvisable to directly read from the underlying reader.

Which makes sense because that direct read would mess up the buffered stream, but it says nothing about using other non-read features of the contained object, as in your case the writing half of the stream.

TL;DR: write something like (mocked playground):

fn main() {
    let stream = StreamOwned;
    let mut r = BufReader::new(stream);
    loop {
        let mut line = String::new();
        r.read_line(&mut line);
        r.get_mut().write(b"ping"); // now it compiles!
    }
}