use crate::{Captures, Needle};
use std::io;
pub trait UntilNeedleRead {
fn read_until_needle<N>(&mut self, needle: N) -> io::Result<Captures>
where
N: Needle;
fn split_read_until_needle<N>(
&mut self,
needle: N,
before: &mut Vec<u8>,
matched: &mut Vec<u8>,
) -> io::Result<usize>
where
N: Needle,
{
let captures = self.read_until_needle(needle)?;
let total_bytes_read = captures.total_bytes_read();
let (b, m) = captures.split();
before.extend_from_slice(&b);
matched.extend_from_slice(&m);
Ok(total_bytes_read)
}
}
impl<T: std::io::BufRead> UntilNeedleRead for T {
fn read_until_needle<N>(&mut self, needle: N) -> io::Result<Captures>
where
N: Needle,
{
let mut buf = Vec::new();
loop {
let available = self.fill_buf()?;
let len = available.len();
if len == 0 {
let len = buf.len();
return Ok(Captures::new(buf, len));
}
buf.extend_from_slice(available);
if let Some(range) = needle.findin(&buf) {
let used = len.saturating_sub(buf.len().saturating_sub(range.end));
self.consume(used);
buf.truncate(range.end);
return Ok(Captures::new(buf, range.start));
} else {
self.consume(len);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::{BufRead, Cursor, Read};
#[test]
fn test_bufread() {
let data = b"hello world";
let mut cur = Cursor::new(data);
assert_eq!(cur.fill_buf().unwrap(), data);
assert_eq!(cur.fill_buf().unwrap(), data);
let data = Vec::from(b"hello world");
let mut cur = Cursor::new(data);
assert_eq!(cur.fill_buf().unwrap(), b"hello world");
assert_eq!(cur.fill_buf().unwrap(), b"hello world");
cur.get_mut().extend_from_slice(b"!!!");
}
#[test]
fn test_read_until_needle() {
let data = b"hello world!!";
let mut cur = Cursor::new(data);
let cap = cur.read_until_needle(b"world").unwrap();
assert_eq!(cap.before(), b"hello ");
assert_eq!(cap.matched(), b"world");
assert_eq!(cap.total_bytes_read(), cur.position() as usize);
let mut remain = Vec::new();
cur.read_to_end(&mut remain).unwrap();
assert_eq!(remain, b"!!");
}
#[test]
fn test_split_read_until_needle() {
let data = b"hello world";
let mut cur = Cursor::new(data);
let mut before = Vec::new();
let mut matched = Vec::new();
assert_eq!(
cur.split_read_until_needle(b"hello", &mut before, &mut matched)
.unwrap(),
5
);
assert_eq!(before, b"");
assert_eq!(matched, b"hello");
before.clear();
matched.clear();
assert_eq!(
cur.split_read_until_needle(b"world", &mut before, &mut matched)
.unwrap(),
6
);
assert_eq!(before, b" ");
assert_eq!(matched, b"world");
before.clear();
matched.clear();
assert_eq!(
cur.split_read_until_needle(b"foo", &mut before, &mut matched)
.unwrap(),
0
);
assert_eq!(before, b"");
assert_eq!(matched, b"");
cur.set_position(0);
before.clear();
matched.clear();
assert_eq!(
cur.split_read_until_needle(b"world", &mut before, &mut matched)
.unwrap(),
11
);
assert_eq!(before, b"hello ");
assert_eq!(matched, b"world");
}
}