#[derive(Debug, PartialEq, Eq)]
pub enum Expect {
Value,
ValueOrEnd,
CommaOrEnd,
String,
Colon,
Eof,
}
impl core::fmt::Display for Expect {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use Expect::*;
match self {
Value => "value".fmt(f),
ValueOrEnd => "value or end of sequence".fmt(f),
CommaOrEnd => "comma or end of sequence".fmt(f),
String => "string".fmt(f),
Colon => "colon".fmt(f),
Eof => "end of file".fmt(f),
}
}
}
pub trait Lex: crate::Read {
fn eat_whitespace(&mut self) {
self.skip_until(|c| !matches!(c, b' ' | b'\t' | b'\r' | b'\n'))
}
fn ws_peek(&mut self) -> Option<u8> {
self.eat_whitespace();
self.peek_next()
}
fn null_or_bool(&mut self) -> Option<Option<bool>> {
Some(match self.take_next() {
Some(b'n') if self.strip_prefix(b"ull") => None,
Some(b't') if self.strip_prefix(b"rue") => Some(true),
Some(b'f') if self.strip_prefix(b"alse") => Some(false),
_ => return None,
})
}
fn discarded(&mut self) -> &mut Self {
self.take_next();
self
}
fn expect(&mut self, pf: impl FnOnce(&mut Self) -> Option<u8>, expect: u8) -> Option<()> {
if pf(self) == Some(expect) {
self.take_next().map(|_| ())
} else {
None
}
}
fn seq<E: From<Expect>, PF, F>(&mut self, end: u8, mut pf: PF, mut f: F) -> Result<(), E>
where
PF: FnMut(&mut Self) -> Option<u8>,
F: FnMut(u8, &mut Self) -> Result<(), E>,
{
let mut next = pf(self).ok_or(Expect::ValueOrEnd)?;
if next == end {
self.take_next();
return Ok(());
};
loop {
f(next, self)?;
next = pf(self).ok_or(Expect::CommaOrEnd)?;
if next == end {
self.take_next();
return Ok(());
} else if next == b',' {
self.take_next();
next = pf(self).ok_or(Expect::Value)?;
} else {
return Err(Expect::CommaOrEnd)?;
}
}
}
fn exactly_one<T, E: From<Expect>, PF, F>(&mut self, mut pf: PF, f: F) -> Result<T, E>
where
PF: FnMut(&mut Self) -> Option<u8>,
F: FnOnce(u8, &mut Self) -> Result<T, E>,
{
let next = pf(self).ok_or(Expect::Value)?;
let v = f(next, self)?;
match pf(self) {
None => Ok(v),
Some(_) => Err(Expect::Eof)?,
}
}
}
impl<T> Lex for T where T: crate::Read {}