#[derive(Debug)]
pub(crate) struct Scanner<'a> {
buf: &'a [u8],
pos: usize,
}
impl<'a> Scanner<'a> {
pub fn new(input: &'a str) -> Self {
if !input.as_bytes().is_ascii() {
panic!("Scanner only supports ASCII input");
}
Scanner {
buf: input.as_bytes(),
pos: 0,
}
}
pub fn pop(&mut self) -> Option<char> {
while self.pos < self.buf.len() {
let b = self.buf[self.pos];
self.pos += 1;
if b != b'\'' {
return Some(b as char);
}
}
None
}
pub fn peek(&self) -> Option<char> {
let mut i = self.pos;
while i < self.buf.len() {
let b = self.buf[i];
if b != b'\'' {
return Some(b as char);
}
i += 1;
}
None
}
pub fn cursor(&self) -> usize {
self.pos
}
pub fn is_done(&self) -> bool {
self.peek().is_none()
}
}
impl Iterator for Scanner<'_> {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
self.pop()
}
}
#[cfg(test)]
mod tests {
use std::hint::black_box;
use super::*;
#[test]
#[should_panic(expected = "Scanner only supports ASCII input")]
fn invalid_non_ascii_input() {
let scanner = Scanner::new("£");
black_box(scanner);
}
#[test]
fn cursor_given_empty() {
let scanner = Scanner::new("");
assert_eq!(scanner.cursor(), 0);
}
#[test]
fn cursor_given_not_done() {
let mut scanner = Scanner::new("abc");
assert_eq!(scanner.pop(), Some('a'));
assert_eq!(scanner.cursor(), 1);
}
#[test]
fn cursor_given_done() {
let mut scanner = Scanner::new("abc");
assert_eq!(scanner.pop(), Some('a'));
assert_eq!(scanner.pop(), Some('b'));
assert_eq!(scanner.pop(), Some('c'));
assert_eq!(scanner.cursor(), 3);
}
#[test]
fn is_done_given_done() {
let scanner = Scanner::new("");
assert!(scanner.is_done());
}
#[test]
fn is_done_given_not_done() {
let scanner = Scanner::new("a");
assert!(!scanner.is_done());
}
#[test]
fn peek_given_not_done() {
let mut scanner = Scanner::new("abc");
assert_eq!(scanner.pop(), Some('a'));
assert_eq!(scanner.peek(), Some('b'));
}
#[test]
fn peek_given_done() {
let mut scanner = Scanner::new("abc");
assert_eq!(scanner.pop(), Some('a'));
assert_eq!(scanner.pop(), Some('b'));
assert_eq!(scanner.pop(), Some('c'));
assert_eq!(scanner.peek(), None);
}
#[test]
fn pop_given_not_done() {
let mut scanner = Scanner::new("abc");
assert_eq!(scanner.pop(), Some('a'));
}
#[test]
fn pop_given_done() {
let mut scanner = Scanner::new("a");
assert_eq!(scanner.pop(), Some('a'));
assert_eq!(scanner.pop(), None);
}
}