2

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.

cafce25
  • 15,907
  • 4
  • 25
  • 31
curious
  • 133
  • 7

1 Answers1

2

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!
    }
}
rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • Yes, there was no confusion about BufReader containing a 'type that implements read', hence why I wrote "does not implement the Read trait" in my original question. `Which makes sense because that direct read would mess up the buffered stream,` I understand why BufReader needs exclusive access to the underlying reader, but that isn't my problem. `r.get_mut().write(b"ping");` is indeed the solution, but it seems a bit kludgy to create a mutable reference to the underlying object each time I want to use it mutably. – curious Mar 15 '23 at 21:27
  • @curious: Yes, I admit it looks a bit kludgy. If you use that a lot, or if you want a `BufWriter` for it, it might make sense to create a _newtype_ wrapping `BufReader` and implement `BufRead` and `Write` for it. But for regular use, I think this is just _good enough_. – rodrigo Mar 15 '23 at 21:53