use crate::{Read, Write};
use core::{convert::AsRef, fmt};
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
ExpectedDigit,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::ExpectedDigit => "expected digit".fmt(f),
}
}
}
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Parts {
pub zero: bool,
pub dot: bool,
pub exp: bool,
}
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Num<R = u8> {
read: R,
parts: Parts,
}
impl Num {
pub fn signed_digits() -> Self {
Self::default().map_read(|_| b'e')
}
pub fn unsigned_digits() -> Self {
Self::default().map_read(|_| b'.')
}
fn num_part(&mut self, c: u8) -> bool {
let Parts { zero, dot, exp } = &mut self.parts;
match (self.read, c) {
(0, b'-') => (),
(0 | b'-', b'0') if !*dot && !*exp => *zero = true,
(_, b'0'..=b'9') if !*zero || *dot || *exp => (),
(b'0'..=b'9', b'.') if !*dot && !*exp => *dot = true,
(b'0'..=b'9', b'e' | b'E') if !*exp => *exp = true,
(b'e' | b'E', b'+' | b'-') => (),
_ => return false,
};
self.read = c;
true
}
pub fn validate(self) -> Result<Parts, Error> {
self.read
.is_ascii_digit()
.then(|| self.parts)
.ok_or(Error::ExpectedDigit)
}
}
impl<R> Num<R> {
pub fn unvalidated(self) -> (R, Parts) {
(self.read, self.parts)
}
fn map_read<R2>(self, f: impl FnOnce(R) -> R2) -> Num<R2> {
let read = f(self.read);
let parts = self.parts;
Num { read, parts }
}
}
impl Parts {
pub fn is_int(&self) -> bool {
!self.dot && !self.exp
}
}
impl<B: AsRef<[u8]>> Num<B> {
pub fn validated(self) -> Result<(B, Parts), Error> {
let Self { read, parts } = self;
let valid = read.as_ref().last().map_or(false, u8::is_ascii_digit);
valid.then(|| (read, parts)).ok_or(Error::ExpectedDigit)
}
}
pub trait Lex: Read {
fn num_ignore(&mut self) -> Num {
self.num_ignore_with(Num::default())
}
fn num_ignore_with(&mut self, mut num: Num) -> Num {
self.skip_until(|c| !num.num_part(c));
num
}
}
impl<T> Lex for T where T: Read {}
pub trait LexWrite: Lex + Write {
type Num: AsRef<str> + AsRef<[u8]>;
fn num_bytes(&mut self) -> Num<Self::Bytes> {
self.num_bytes_with(Num::default())
}
fn num_bytes_with(&mut self, mut num: Num) -> Num<Self::Bytes> {
let mut read = Default::default();
self.write_until(&mut read, |c| !num.num_part(c));
num.map_read(|_| read)
}
fn num_string(&mut self) -> Num<Self::Num> {
self.num_string_with(Num::default())
}
fn num_string_with(&mut self, num: Num) -> Num<Self::Num>;
}
impl<'a> LexWrite for crate::SliceLexer<'a> {
type Num = &'a str;
fn num_string_with(&mut self, num: Num) -> Num<Self::Num> {
self.num_bytes_with(num)
.map_read(|read| core::str::from_utf8(read).unwrap())
}
}
#[cfg(feature = "alloc")]
impl<E, I: Iterator<Item = Result<u8, E>>> LexWrite for crate::IterLexer<E, I> {
type Num = alloc::string::String;
fn num_string_with(&mut self, num: Num) -> Num<Self::Num> {
self.num_bytes_with(num)
.map_read(|read| alloc::string::String::from_utf8(read).unwrap())
}
}