Refactor read_until

CandyCorvid
Jul 13, 2023, 10:31 AM
AOJXTWBZA2DQBFTJZX2YTGAKIB62SKTEVJ7RRIBJNDSMC75DDQVQC

Dependencies

Change contents

  • file deletion: read_until.rs (----------)
    [3.15][3.17:54](),[3.54][3.55:55]()
    //! 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=2018
    use 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 buffer
    fn step<const N: usize>(excess: &[u8], delimeter: &[u8; N], buf: &mut Vec<u8>) -> (bool, usize) {
    // find the whole delimiter in the excess
    if 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 buffer
    for n in 1..N {
    // the seam between buf and excess contains the delimter
    if 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 split
    buf.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>
    where
    R: BufRead + ?Sized,
    {
    let mut read = 0;
    loop {
    // read ahead
    let (done, used) = step(reader.fill_buf()?, delimeter, buf);
    reader.consume(used);
    // count the number of bytes consumed
    read += used;
    // done means we found it, used == 0 means eof
    if 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
    [3.3684][3.3684:3712]()
    use read_until::read_until;
    [3.3684]
    [2.6831]
    use io::{BufReadExt, ReadExt};
  • replacement in src/main.rs at line 7
    [3.3767][3.51:105]()
    io::{BufReader, Read, Result as ioResult, Write},
    [3.3767]
    [3.3807]
    io::{BufReader, Result as ioResult, Write},
  • edit in src/main.rs at line 14
    [3.127][3.127:143]()
    mod read_until;
  • replacement in src/main.rs at line 58
    [2.7673][2.7673:7761]()
    let body = read_response_string(&mut stream).expect("failed to read body");
    [2.7673]
    [2.7761]
    let body = stream.read_string().expect("failed to read body");
  • replacement in src/main.rs at line 128
    [3.525][3.525:652]()
    let status = io::read_n::<2>(stream)?;
    let status = status.map(|s| s.checked_sub(b'0').expect("bad status fragment"));
    [3.525]
    [3.4768]
    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
    [3.4769][3.653:689]()
    let c = io::read_byte(stream)?;
    [3.4769]
    [3.4801]
    let c = stream.read_byte()?;
  • replacement in src/main.rs at line 140
    [3.4960][3.4960:5032]()
    read_until(&mut BufReader::new(&mut *stream), b"\r\n", &mut meta)?;
    [3.4960]
    [3.717]
    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
    [2.9554][2.9555:9584]()
    use std::io::{Read, Result};
    [2.9554]
    [2.9584]
    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
    [2.9585][2.9585:9695]()
    pub(crate) fn read_byte(stream: &mut impl Read) -> Result<u8> {
    let [c] = read_n::<1>(stream)?;
    Ok(c)
    [2.9585]
    [2.9695]
    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
    [2.9697]
    [2.9697]
    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=2018
    use bstr::ByteSlice;
    use std::io::BufRead;
    use std::io::Result;
  • replacement in src/io.rs at line 42
    [2.9698][2.9698:9852]()
    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)
    [2.9698]
    [2.9852]
    use super::BufReadExt;
    /// Find the delimiter in the excess and the buffer, and return:
    /// Whether it was located
    /// How much was read into the buffer
    fn step<const N: usize>(
    excess: &[u8],
    delimeter: &[u8; N],
    buf: &mut Vec<u8>,
    ) -> (bool, usize) {
    // find the whole delimiter in the excess
    if 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 buffer
    for n in 1..N {
    // the seam between buf and excess contains the delimter
    if 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 split
    buf.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 ahead
    let (done, used) = step(self.fill_buf()?, delimiter, buf);
    self.consume(used);
    // count the number of bytes consumed
    read += used;
    // done means we found it, used == 0 means eof
    if 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);
    }
    }