use std::{
error::Error,
fmt::{self, Display, Formatter},
num::{ParseFloatError, ParseIntError},
result,
str::{Chars, FromStr},
};
#[derive(Debug, Copy, Clone)]
pub enum ParseError {
EmptyInput,
NoMatch,
}
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter) -> result::Result<(), fmt::Error> {
let msg = match *self {
Self::EmptyInput => "input is empty",
Self::NoMatch => "the input does not match",
};
f.write_str(msg)
}
}
impl Error for ParseError {}
pub struct StringReader<'a> {
input: Chars<'a>,
current: Option<char>,
}
impl<'a> StringReader<'a> {
pub fn new<T>(input: &'a T) -> Self
where
T: AsRef<str> + ?Sized,
{
let input = input.as_ref().chars();
let current = input.clone().next();
Self { input, current }
}
#[inline]
pub fn current_char(&self) -> Option<char> {
self.current
}
pub fn read_char(&mut self) -> Result<char, ParseError> {
let res = self.input.next().ok_or(ParseError::EmptyInput)?;
self.current = self.input.clone().next();
Ok(res)
}
pub fn match_char(&mut self, expected: char) -> Result<(), ParseError> {
let c = self.current_char().ok_or(ParseError::EmptyInput)?;
if c != expected {
return Err(ParseError::NoMatch);
}
self.skip_char();
Ok(())
}
pub fn skip_char(&mut self) {
self.input.next();
self.current = self.input.clone().next();
}
pub fn skip_whitespace(&mut self) {
let rest = self.input.as_str().trim_start();
self.input = rest.chars();
self.current = self.input.clone().next();
}
pub fn match_str(&mut self, val: &str) -> Result<(), ParseError> {
let input = self.input.as_str();
if input.starts_with(val) {
let (_, rest) = input.split_at(val.len());
self.input = rest.chars();
self.current = self.input.clone().next();
Ok(())
} else {
Err(ParseError::NoMatch)
}
}
pub fn read_until<F>(&mut self, cnd: F) -> &'a str
where
F: FnMut(char) -> bool,
{
let rest = self.input.as_str();
let index = rest.find(cnd).unwrap_or_else(|| rest.len());
self.split_to(index)
}
#[inline]
pub fn read_word(&mut self) -> &'a str {
self.skip_whitespace();
self.read_until(char::is_whitespace)
}
pub fn parse_word<T>(&mut self) -> Result<T, T::Err>
where
T: FromStr,
{
let (word, rest) = self.first_word();
let parsed = word.parse()?;
self.input = rest.chars();
self.current = self.input.clone().next();
Ok(parsed)
}
#[inline]
pub fn read_i8(&mut self) -> Result<i8, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_u8(&mut self) -> Result<u8, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_i16(&mut self) -> Result<i16, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_u16(&mut self) -> Result<u16, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_i32(&mut self) -> Result<i32, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_u32(&mut self) -> Result<u32, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_i64(&mut self) -> Result<i64, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_u64(&mut self) -> Result<u64, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_i128(&mut self) -> Result<i128, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_u128(&mut self) -> Result<u128, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_isize(&mut self) -> Result<isize, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_usize(&mut self) -> Result<usize, ParseIntError> {
self.parse_word()
}
#[inline]
pub fn read_f32(&mut self) -> Result<f32, ParseFloatError> {
self.parse_word()
}
#[inline]
pub fn read_f64(&mut self) -> Result<f64, ParseFloatError> {
self.parse_word()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.current_char().is_none()
}
#[inline]
pub fn as_str(&self) -> &'a str {
self.input.as_str()
}
fn first_word(&self) -> (&'a str, &'a str) {
let input = self.input.as_str().trim_start();
let index = input
.find(char::is_whitespace)
.unwrap_or_else(|| input.len());
input.split_at(index)
}
fn split_to(&mut self, index: usize) -> &'a str {
let rest = self.input.as_str();
let (word, rest) = rest.split_at(index);
self.input = rest.chars();
self.current = self.input.clone().next();
word
}
}
#[cfg(test)]
mod tests {
use super::StringReader;
#[test]
fn test_reader() {
let input = "Hello, World!!! 1234\n\tfoo-bar";
let mut reader = StringReader::new(input);
assert!(!reader.is_empty());
assert_eq!(reader.current_char(), Some('H'));
assert_eq!(reader.as_str(), input);
let word = reader.read_word();
assert_eq!(word, "Hello,");
assert_eq!(reader.as_str(), " World!!! 1234\n\tfoo-bar");
reader.skip_whitespace();
assert_eq!(reader.as_str(), "World!!! 1234\n\tfoo-bar");
let c = reader.read_char();
assert_eq!(c.ok(), Some('W'));
let res = reader.match_char('o');
assert!(res.is_ok());
let res = reader.match_char('R');
assert!(res.is_err());
let res = reader.match_str("RLD!!!");
assert!(res.is_err());
let res = reader.match_str("rld!!!");
assert!(res.is_ok());
assert_eq!(reader.as_str(), " 1234\n\tfoo-bar");
let n = reader.read_u32();
assert_eq!(n.ok(), Some(1234));
assert_eq!(reader.as_str(), "\n\tfoo-bar");
let n = reader.read_u32();
assert!(n.is_err());
assert_eq!(reader.as_str(), "\n\tfoo-bar");
let word = reader.read_word();
assert_eq!(word, "foo-bar");
assert_eq!(reader.as_str(), "");
assert!(reader.is_empty());
let word = reader.read_word();
assert_eq!(word, "");
let c = reader.read_char();
assert!(c.is_err());
assert!(reader.is_empty());
assert_eq!(reader.as_str(), "");
}
}