AOJXTWBZA2DQBFTJZX2YTGAKIB62SKTEVJ7RRIBJNDSMC75DDQVQC
//! 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);
}
}
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>;
}
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)
}
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;
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 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);
}
}