I'm writing a network server (with a text-based protocol for now). I want to retrieve the next line from an io::Read
or io::BufRead
. Unfortunately, BufRead::read_line
potentially allocates an unlimited amount of memory if there is a lot of data retrieved without any \n
. I found Read::take
, which, in combination with Read::by_ref
(or prior borrowing), can be used to limit the maximum number of bytes during a read operation from a reader implementing Read
. But combining it with read_line
won't work, of course:
use std::io;
fn serve<R: io::BufRead, W: io::Write>(
&self,
mut reader: R,
mut writer: W,
) -> Result<(), Box<dyn std::error::Error>> {
writeln!(writer, "Welcome.")?;
let mut input = String::new();
loop {
input.clear();
// the following line does not compile
reader.by_ref().take(1024).read_line(&mut input)?;
let line = input.trim();
writeln!(writer, "You entered: {}", line)?;
}
Ok(())
}
That is because Read::take
will return an io::Take
, which implements io::Read
but not io::BufRead
. Also, take
might break between Unicode code-point boundaries.
I cannot convert the Read
into another (nested, temporary) BufRead
, as then bytes might remain in that (temporary) buffer.
So my question is: What is the idiomatic way to read a line from a reader that implements io::Read
or io::BufRead
when it is not ensured that a new-line character occurs after a certain amount of data has been read?
Writing my own implementation of read_line
with a maximum limit seems possible but requires to manage buffers. I would prefer a way to safely read lines without having to worry about handling buffers manually (preferrably by using only functions available in the standard library.
Many thanks for your help.