extern crate memchr;
use std::io;
use std::io::prelude::*;
use std::str;
struct Guard<'a> {
buf: &'a mut Vec<u8>,
len: usize,
}
impl Drop for Guard<'_> {
fn drop(&mut self) {
unsafe {
self.buf.set_len(self.len);
}
}
}
pub(crate) unsafe fn append_to_string<F>(buf: &mut String, f: F) -> io::Result<usize>
where
F: FnOnce(&mut Vec<u8>) -> io::Result<usize>,
{
let mut g = Guard {
len: buf.len(),
buf: buf.as_mut_vec(),
};
let ret = f(g.buf);
if str::from_utf8(&g.buf[g.len..]).is_err() {
ret.and_then(|_| {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"stream did not contain valid UTF-8",
))
})
} else {
g.len = g.buf.len();
ret
}
}
pub(crate) fn read_until<R: BufRead + ?Sized>(
r: &mut R,
delim: u8,
buf: &mut Vec<u8>,
) -> io::Result<usize> {
let mut read = loop {
let mut first = [0u8; 1];
match r.read(&mut first) {
Ok(n) => {
buf.extend_from_slice(&first[..n]);
break n;
}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(error) => return Err(error),
}
};
loop {
let (done, used) = {
let available = match r.fill_buf() {
Ok(n) => n,
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
};
match memchr::memrchr(delim, available) {
Some(mut i) => {
i += 1; buf.splice(..0, available[i..].iter().cloned());
(true, available.len() - i)
}
None => {
buf.splice(..0, available.iter().cloned());
(false, available.len())
}
}
};
r.consume(used);
read += used;
if done || used == 0 {
return Ok(read);
}
}
}