use crate::error::Result;
use std::{
slice, borrow::Cow,
io::{ BufRead, BufReader, Cursor }
};
#[derive(Debug, PartialEq, Eq)]
pub enum MatchConfig {
Required,
Trim
}
pub fn memreader<T>(data: T) -> impl BufRead where T: AsRef<[u8]> {
BufReader::new(Cursor::new(data))
}
pub trait BufReadExt where Self: BufRead {
fn peek_one(&mut self) -> Result<Option<u8>> {
let buf = self.fill_buf()?;
Ok(buf.first().copied())
}
fn read_one(&mut self) -> Result<Option<u8>> {
if self.fill_buf()?.is_empty() {
return Ok(None);
}
let mut byte = 0;
self.read_exact(slice::from_mut(&mut byte))?;
Ok(Some(byte))
}
fn read_word<T, F>(&mut self, delimiter: T, flags: F) -> Result<Vec<u8>>
where T: AsRef<[u8]>, F: AsRef<[MatchConfig]>
{
let delimiter = delimiter.as_ref();
let flags = flags.as_ref();
let mut line = Vec::new();
'read_loop: while !line.ends_with(delimiter) {
match self.read_one()? {
Some(next) => line.push(next),
None => break 'read_loop
}
}
if flags.contains(&MatchConfig::Required) && !line.ends_with(delimiter) {
return Err(einval!("Unexpected early EOF"));
}
if flags.contains(&MatchConfig::Trim) && line.ends_with(delimiter) {
let len_without_delimiter = line.len() - delimiter.len();
line.resize(len_without_delimiter, 0);
}
Ok(line)
}
fn read_all<T>(&mut self, flags: T) -> Result<Vec<u8>> where T: AsRef<[MatchConfig]> {
let flags = flags.as_ref();
let mut buf = Vec::new();
self.read_to_end(&mut buf)?;
if flags.contains(&MatchConfig::Required) && buf.is_empty() {
return Err(einval!("Unexpected early EOF"));
}
Ok(buf)
}
}
impl<T> BufReadExt for T where T: BufRead {
}
pub trait SliceU8Ext where Self: AsRef<[u8]> {
fn as_ascii_lowercase(&self) -> Cow<[u8]> {
let slice = self.as_ref();
match slice.iter().all(|b| b.is_ascii_lowercase()) {
true => Cow::Borrowed(slice),
false => Cow::Owned(slice.to_ascii_lowercase())
}
}
}
impl<T> SliceU8Ext for T where T: AsRef<[u8]> {
}