use crate::errors::{ParseError, ParseResult};
use crate::peek::{peek, Last, Peekable};
use crate::scanner::Scanner;
use crate::visitor::Visitor;
use std::fmt::Debug;
use std::marker::PhantomData;
#[derive(Debug)]
pub struct SeparatedList<T, V, S> {
pub data: Vec<V>,
separator: PhantomData<(S, T)>,
}
enum YieldResult<V> {
Last(V),
MaybeNext(V),
}
fn yield_element<'a, T, V, S>(scanner: &mut Scanner<'a, T>) -> ParseResult<YieldResult<V>>
where
V: Visitor<'a, T>,
S: Visitor<'a, T>,
{
let cursor = scanner.current_position();
let element = match scanner.visit::<V>() {
Ok(element) => element,
Err(err) => {
scanner.jump_to(cursor);
return Err(err);
}
};
if scanner.remaining().is_empty() {
return Ok(YieldResult::Last(element));
}
scanner.visit::<S>()?;
Ok(YieldResult::MaybeNext(element))
}
impl<'a, T, V, S> Visitor<'a, T> for SeparatedList<T, V, S>
where
V: Visitor<'a, T>,
S: Visitor<'a, T>,
{
fn accept(scanner: &mut Scanner<'a, T>) -> ParseResult<Self> {
let mut elements = vec![];
let cursor = scanner.current_position();
if scanner.remaining().is_empty() {
return Ok(SeparatedList {
data: elements,
separator: PhantomData,
});
}
loop {
if let Ok(result) = yield_element::<T, V, S>(scanner) {
let element: YieldResult<V> = result;
match element {
YieldResult::Last(element) => {
elements.push(element);
break;
}
YieldResult::MaybeNext(element) => {
elements.push(element);
}
}
} else {
scanner.jump_to(cursor);
return Err(ParseError::UnexpectedToken);
}
}
Ok(SeparatedList {
data: elements,
separator: PhantomData,
})
}
}
pub fn get_scanner_without_trailing_separator<'a, T, P1, P2>(
element: P1,
separator: P2,
scanner: &Scanner<'a, T>,
) -> ParseResult<Scanner<'a, T>>
where
P1: Peekable<'a, T>,
P2: Peekable<'a, T>,
{
let result_last_element = peek(Last::new(element), scanner)?;
let Some(result_last_element) = result_last_element else {
return Ok(Scanner::new(scanner.remaining()));
};
let result_last_separator = peek(Last::new(separator), &scanner)?;
let Some(result_last_separator) = result_last_separator else {
return Ok(Scanner::new(scanner.remaining()));
};
let mut end_slice = scanner.remaining().len();
if result_last_element.end_slice < result_last_separator.end_slice {
end_slice -= result_last_separator.end_slice - result_last_separator.peeked_slice().len();
}
let data_scanner = Scanner::new(&scanner.remaining()[..end_slice]);
Ok(data_scanner)
}
#[cfg(test)]
mod tests {
use crate::bytes::primitives::number::Number;
use crate::bytes::token::Token;
use crate::errors::ParseResult;
use crate::recognizer::recognize;
use crate::scanner::Scanner;
use crate::separated_list::SeparatedList;
use crate::visitor::Visitor;
struct SeparatorComma;
impl<'a> Visitor<'a, u8> for SeparatorComma {
fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
recognize(Token::Comma, scanner)?;
Ok(SeparatorComma)
}
}
#[test]
fn test_parse_number_list() {
let data = b"12,4,78,22";
let mut scanner = Scanner::new(data);
let result = scanner
.visit::<SeparatedList<u8, Number<usize>, SeparatorComma>>()
.expect("failed to parse");
assert_eq!(
result.data,
vec![Number(12), Number(4), Number(78), Number(22)]
);
assert_eq!(scanner.current_position(), 10);
let data = b"";
let mut scanner = Scanner::new(data);
let result = scanner
.visit::<SeparatedList<u8, Number<usize>, SeparatorComma>>()
.expect("failed to parse");
assert_eq!(result.data, vec![]);
}
}