Blocking read until newline from `Box<dyn Read>`
In my project, [cambridge-asm](https://github.com/SaadiSave/cambridge-asm), the I/O is abstracted over the Read/Write traits (because the interpreter must work with WebAssembly at [https://saadisave.github.io/cambridge-asm-web/](https://saadisave.github.io/cambridge-asm-web/)).
This is how the I/O struct is declared ([cambridge-asm/src/exec/mod.rs:62](https://github.com/SaadiSave/cambridge-asm/blob/main/cambridge-asm/src/exec/mod.rs#L62)):
pub struct Io { pub read: Box<dyn Read>, pub write: Box<dyn Write>, }
It is boxed instead of generics because my fundamental unit of execution is a function pointer with the type `fn(&mut Context, &Op) -> Result` ([cambridge-asm/src/exec/inst.rs:12](https://github.com/SaadiSave/cambridge-asm/blob/main/cambridge-asm/src/exec/inst.rs#L12)) and it just seems too difficult to use this simple model of execution when `Context` is generic (which will happen if `Io` becomes `Io<I, O>` because `Context` contains the `Io` struct).
Now, in one instruction, RIN, I need to read a line from `Io::read`. This read must be blocking, because if the underlying struct is an input stream, e.g. `Stdin`, the program should block until a newline character appears in the stream.
Currently, I use the following implementation ([cambridge-asm/src/exec/io.rs:146](https://github.com/SaadiSave/cambridge-asm/blob/main/cambridge-asm/src/exec/io.rs#L146)):
fn read_line(reader: &mut impl std::io::Read, buf: &mut Vec<u8>) -> std::io::Result<()> { const CR: u8 = 0xD; const LF: u8 = 0xA;
let mut prev = 0; let mut arr_buf = [0; 1]; loop { reader.read_exact(&mut arr_buf)?;
buf.extend_from_slice(&arr_buf);
let current = arr_buf[0];
if current == LF || [prev, current] == [CR, LF] { break; }
prev = arr_buf[0]; }
Ok(()) }
Could anyone suggest a better implementation? There are only three requirements:
1. The ouput of the read must be as bytes. The buffer need not be preallocated like my function; it may be returned as a `Vec<u8>`. 2. CRLF need not be supported, just LF is fine. 3. The function must block
I am also open to any suggestions about any better ways of handling abstract I/O or better execution models.