use std::io::{self, BufRead, BufReader, Read}; use std::str; struct CharBufReader { reader: BufReader, char_buffer: String, } impl CharBufReader { pub fn new(reader: BufReader) -> CharBufReader { CharBufReader { reader: reader, char_buffer: String::new(), } } pub fn fill_buf(&mut self) -> std::result::Result<&str, io::Error> { loop { let byte_buffer = self.reader.fill_buf()?; match str::from_utf8(byte_buffer) { Err(error) => { let n_valid = error.valid_up_to(); if n_valid == 0 { self.reader.consume(1); } else { match str::from_utf8(&byte_buffer[..n_valid]) { Err(_) => { self.reader.consume(1); }, Ok(chars) => { self.char_buffer.push_str(chars); self.reader.consume(n_valid); break; }, } } }, Ok(chars) => { self.char_buffer.push_str(chars); let n_to_consume = byte_buffer.len(); self.reader.consume(n_to_consume); break; } } } return Ok(&self.char_buffer); } pub fn consume(&mut self, amount: usize) { self.char_buffer.replace_range(..amount, ""); println!("consume {:?}", self.char_buffer); } } pub fn handle_input(input_stream: impl Read) -> std::result::Result<(), io::Error> { let reader = BufReader::new(input_stream); let mut reader = CharBufReader::new(reader); let string = reader.fill_buf()?; println!("top level {:?}", string); let n_to_consume = string.len(); reader.consume(n_to_consume); Ok(()) } #[cfg(test)] mod tests { use super::*; use std::io::Cursor; #[test] fn test_empty_input() { let buffer = Cursor::new(vec![]); let result = handle_input(buffer); assert!(result.is_ok()); } }