Refactor read_until
Dependencies
- [2]
3SPNKI46Improve parsing. Add modules that were missed - [3]
ONQEIR5BWIP mime-type handling - [4]
DBKKKHC2Initial commit - [5]
AMTMTTJTUpgrade status parsing
Change contents
- file deletion: read_until.rs
//! adapted from the answer to this question: https://users.rust-lang.org/t/bufread-read-until-with-two-byte-delimiter/47239/6//! playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018use bstr::ByteSlice;use std::io;use std::io::BufRead;/// Find the delimiter in the excess and the buffer, and return:/// Whether it was located/// How much was read into the bufferfn step<const N: usize>(excess: &[u8], delimeter: &[u8; N], buf: &mut Vec<u8>) -> (bool, usize) {// find the whole delimiter in the excessif let Some(i) = excess.find(&delimeter) {buf.extend_from_slice(&excess[..i + N]);return (true, i + N);}// find the delimiter if it is partly in the excess and partly in the bufferfor n in 1..N {// the seam between buf and excess contains the delimterif buf.ends_with(&delimeter[..n]) && excess.starts_with(&delimeter[n..N]) {let used = N - n;// then extend buf to include what needed to be read past the splitbuf.extend_from_slice(&excess[..used]);return (true, used);}}buf.extend_from_slice(excess);(false, excess.len())}pub fn read_until<R, const N: usize>(reader: &mut R,delimeter: &[u8; N],buf: &mut Vec<u8>,) -> io::Result<usize>whereR: BufRead + ?Sized,{let mut read = 0;loop {// read aheadlet (done, used) = step(reader.fill_buf()?, delimeter, buf);reader.consume(used);// count the number of bytes consumedread += used;// done means we found it, used == 0 means eofif done || used == 0 {return Ok(read);}}}#[cfg(test)]mod test {use crate::read_until::read_until;use std::io::BufReader;#[test]fn read1() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebf";let mut bufread = BufReader::new(&mut buf0);read_until(&mut bufread, b"f", &mut buf1).unwrap();assert_eq!(buf1, exp);}#[test]fn read2() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebfdef";let mut bufread = BufReader::new(&mut buf0);read_until(&mut bufread, b"ef", &mut buf1).unwrap();assert_eq!(buf1, exp);}#[test]fn read3() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebfdef";let mut bufread = BufReader::new(&mut buf0);read_until(&mut bufread, b"def", &mut buf1).unwrap();assert_eq!(buf1, exp);}#[test]fn read4() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebfdef";let mut bufread = BufReader::new(&mut buf0);read_until(&mut bufread, b"fdef", &mut buf1).unwrap();assert_eq!(buf1, exp);}#[test]fn read5() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebfdef";let mut bufread = BufReader::new(&mut buf0);read_until(&mut bufread, b"bfdef", &mut buf1).unwrap();assert_eq!(buf1, exp);}#[test]fn read6() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebfdef";let mut bufread = BufReader::new(&mut buf0);read_until(&mut bufread, b"ebfdef", &mut buf1).unwrap();assert_eq!(buf1, exp);}} - replacement in src/main.rs at line 3
use read_until::read_until;use io::{BufReadExt, ReadExt}; - replacement in src/main.rs at line 7
io::{BufReader, Read, Result as ioResult, Write},io::{BufReader, Result as ioResult, Write}, - edit in src/main.rs at line 14
mod read_until; - replacement in src/main.rs at line 58
let body = read_response_string(&mut stream).expect("failed to read body");let body = stream.read_string().expect("failed to read body"); - replacement in src/main.rs at line 128
let status = io::read_n::<2>(stream)?;let status = status.map(|s| s.checked_sub(b'0').expect("bad status fragment"));let status = stream.read_n::<2>()?.map(|s| s.checked_sub(b'0').expect("bad status fragment")); - replacement in src/main.rs at line 132
let c = io::read_byte(stream)?;let c = stream.read_byte()?; - replacement in src/main.rs at line 140
read_until(&mut BufReader::new(&mut *stream), b"\r\n", &mut meta)?;BufReader::new(&mut *stream).read_until(b"\r\n", &mut meta)?; - edit in src/main.rs at line 153[3.5074]→[3.972:1039](∅→∅),[3.1039]→[3.5192:5278](∅→∅),[3.5192]→[3.5192:5278](∅→∅),[3.5633]→[3.5633:5636](∅→∅)
fn read_response_string(stream: &mut Stream) -> ioResult<String> {let mut body = String::new();stream.read_to_string(&mut body)?;Ok(body)} - replacement in src/io.rs at line 1
use std::io::{Read, Result};use std::io::{BufRead, Read, Result};pub trait ReadExt {fn read_byte(&mut self) -> Result<u8>;fn read_n<const N: usize>(&mut self) -> Result<[u8; N]>;fn read_string(&mut self) -> Result<String>;}pub trait BufReadExt {fn read_until<const N: usize>(&mut self,delimeter: &[u8; N],buf: &mut Vec<u8>,) -> Result<usize>;} - replacement in src/io.rs at line 17
pub(crate) fn read_byte(stream: &mut impl Read) -> Result<u8> {let [c] = read_n::<1>(stream)?;Ok(c)impl<R: Read> ReadExt for R {fn read_byte(&mut self) -> Result<u8> {let [c] = self.read_n::<1>()?;Ok(c)}fn read_n<const N: usize>(&mut self) -> Result<[u8; N]> {let mut buf = [0; N];self.read_exact(&mut buf)?;Ok(buf)}fn read_string(&mut self) -> Result<String> {let mut body = String::new();self.read_to_string(&mut body)?;Ok(body)} - edit in src/io.rs at line 34
mod read_until {//! adapted from the answer to this question: https://users.rust-lang.org/t/bufread-read-until-with-two-byte-delimiter/47239/6//! playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018use bstr::ByteSlice;use std::io::BufRead;use std::io::Result; - replacement in src/io.rs at line 42
pub(crate) fn read_n<const N: usize>(stream: &mut impl Read) -> Result<[u8; N]> {let mut buf = [0; N];stream.read_exact(&mut buf)?;Ok(buf)use super::BufReadExt;/// Find the delimiter in the excess and the buffer, and return:/// Whether it was located/// How much was read into the bufferfn step<const N: usize>(excess: &[u8],delimeter: &[u8; N],buf: &mut Vec<u8>,) -> (bool, usize) {// find the whole delimiter in the excessif let Some(i) = excess.find(&delimeter) {buf.extend_from_slice(&excess[..i + N]);return (true, i + N);}// find the delimiter if it is partly in the excess and partly in the bufferfor n in 1..N {// the seam between buf and excess contains the delimterif buf.ends_with(&delimeter[..n]) && excess.starts_with(&delimeter[n..N]) {let used = N - n;// then extend buf to include what needed to be read past the splitbuf.extend_from_slice(&excess[..used]);return (true, used);}}buf.extend_from_slice(excess);(false, excess.len())}impl<R: BufRead> BufReadExt for R {fn read_until<const N: usize>(&mut self,delimiter: &[u8; N],buf: &mut Vec<u8>,) -> Result<usize> {let mut read = 0;loop {// read aheadlet (done, used) = step(self.fill_buf()?, delimiter, buf);self.consume(used);// count the number of bytes consumedread += used;// done means we found it, used == 0 means eofif done || used == 0 {return Ok(read);}}}}#[cfg(test)]mod test {use super::BufReadExt;use std::io::BufReader;#[test]fn read1() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebf";let mut bufread = BufReader::new(&mut buf0);bufread.read_until(b"f", &mut buf1).unwrap();assert_eq!(buf1, exp);}#[test]fn read2() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebfdef";let mut bufread = BufReader::new(&mut buf0);bufread.read_until(b"ef", &mut buf1).unwrap();assert_eq!(buf1, exp);}#[test]fn read3() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebfdef";let mut bufread = BufReader::new(&mut buf0);bufread.read_until(b"def", &mut buf1).unwrap();assert_eq!(buf1, exp);}#[test]fn read4() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebfdef";let mut bufread = BufReader::new(&mut buf0);bufread.read_until(b"fdef", &mut buf1).unwrap();assert_eq!(buf1, exp);}#[test]fn read5() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebfdef";let mut bufread = BufReader::new(&mut buf0);bufread.read_until(b"bfdef", &mut buf1).unwrap();assert_eq!(buf1, exp);}#[test]fn read6() {let mut buf0: &[u8] = b"ebfdefghijkl";let mut buf1 = Vec::new();let exp = b"ebfdef";let mut bufread = BufReader::new(&mut buf0);bufread.read_until(b"ebfdef", &mut buf1).unwrap();assert_eq!(buf1, exp);}}