use crate::errors::ParseResult;
use crate::matcher::MatchSize;
use crate::recognizer::RecognizeSelf;
use crate::scanner::Scanner;
use std::marker::PhantomData;
#[derive(Debug, PartialEq)]
pub struct Peeking<'a, T, S, E> {
pub start: S,
pub end: E,
pub end_slice: usize,
pub data: &'a [T],
}
impl<'a, T, S, E> Peeking<'a, T, S, E>
where
S: MatchSize,
E: MatchSize,
{
pub fn peeked_slice(&self) -> &'a [T] {
&self.data[self.start.size()..self.end_slice - self.end.size()]
}
pub fn data(&self) -> &'a [T] {
self.data
}
}
#[derive(PartialEq, Debug)]
pub enum PeekResult<S, E> {
Found { end_slice: usize, start: S, end: E },
NotFound,
}
pub trait Peekable<'a, T, S, E> {
fn peek(&self, data: &Scanner<'a, T>) -> ParseResult<PeekResult<S, E>>;
}
pub fn peek<'a, T, S, E, P: Peekable<'a, T, S, E>>(
peekable: P,
scanner: &mut Scanner<'a, T>,
) -> ParseResult<Option<Peeking<'a, T, S, E>>> {
let source_cursor = scanner.current_position();
match peekable.peek(scanner)? {
PeekResult::Found {
end_slice,
start,
end,
} => {
let data = &scanner.data()[source_cursor..source_cursor + end_slice];
Ok(Some(Peeking {
start,
end,
end_slice,
data,
}))
}
PeekResult::NotFound => {
scanner.jump_to(source_cursor);
Ok(None)
}
}
}
pub struct Until<'a, T, V> {
element: V,
_marker: PhantomData<&'a T>,
}
impl<'a, T, V> Until<'a, T, V> {
pub fn new(element: V) -> Until<'a, T, V> {
Until {
element,
_marker: PhantomData,
}
}
}
impl<'a, T, V> Peekable<'a, T, V, V> for Until<'a, T, V>
where
V: RecognizeSelf<'a, T, V> + Clone,
{
fn peek(&self, data: &Scanner<'a, T>) -> ParseResult<PeekResult<V, V>> {
let remaining = &data.data()[data.current_position()..];
let mut scanner = Scanner::new(remaining);
while !scanner.is_empty() {
match self.element.clone().recognize_self(&mut scanner) {
Ok(Some(element)) => {
return Ok(PeekResult::Found {
end_slice: scanner.current_position() - self.element.size(),
start: element.clone(),
end: element.clone(),
});
}
Ok(None) => {
scanner.bump_by(1);
continue;
}
Err(_err) => {
scanner.bump_by(1);
continue;
}
}
}
Ok(PeekResult::NotFound)
}
}
#[derive(Default)]
pub struct UntilEnd<T>(PhantomData<T>);
#[cfg(test)]
mod tests {
use crate::bytes::token::Token;
use crate::peek::{Until, UntilEnd, peek};
#[test]
fn test_until() {
let data = b"abc|fdgf";
let mut scanner = crate::scanner::Scanner::new(data);
let token = Until::new(Token::Pipe);
let peeked = peek(token, &mut scanner)
.expect("failed to parse")
.expect("failed to peek");
assert_eq!(peeked.data(), "abc".as_bytes());
}
#[test]
fn test_until_end() {
let data = b"abc|fdgf";
let mut scanner = crate::scanner::Scanner::new(data);
let token = UntilEnd::default();
let peeked = peek(token, &mut scanner)
.expect("failed to parse")
.expect("failed to peek");
assert_eq!(peeked.data, "abc|fdgf".as_bytes());
}
}