use crate::{InputToken, Parser};
pub fn count<P, IT, O>(parser: &P, count: usize) -> impl Parser<IT, Vec<O>>
where
P: Parser<IT, O>,
IT: InputToken,
{
move |input| {
let mut output = Vec::with_capacity(count);
for _ in 0..count {
match parser(input) {
Ok(token) => output.push(token),
Err(e) => return Err(e),
}
}
Ok(output)
}
}
#[cfg(test)]
mod tests {
use crate::input::Position;
use crate::*;
#[test]
fn count_zero_empty() {
let parser = is('h');
let mut input = Input::new_from_chars("".chars(), None);
let parser = count(&parser, 0);
let output = parser(&mut input);
assert_eq!(output, Ok(vec![]));
}
#[test]
fn count_zero_empty_shortcut() {
let parser = is('h').count(0);
let mut input = Input::new_from_chars("".chars(), None);
let output = parser(&mut input);
assert_eq!(output, Ok(vec![]));
}
#[test]
fn count_0_not_empty() {
let parser = is('h');
let mut input = Input::new_from_chars("jello".chars(), None);
let parser = count(&parser, 0);
let output = parser(&mut input);
assert_eq!(output, Ok(vec![]));
}
#[test]
fn count_0_not_empty_shortcut() {
let parser = is('h').count(0);
let mut input = Input::new_from_chars("jello".chars(), None);
let output = parser(&mut input);
assert_eq!(output, Ok(vec![]));
}
#[test]
fn count_all_same() {
let parser = is('h');
let repeat_count: usize = 500;
let tokens: Vec<_> = std::iter::repeat_n('h', repeat_count).collect();
let mut input = Input::new_from_chars(tokens, None);
let parser = count(&parser, repeat_count);
let output = parser(&mut input).unwrap();
assert_eq!(output.len(), repeat_count); assert!(output.iter().all(|x| *x == 'h')); assert!(end_of_input()(&mut input).is_ok()); }
#[test]
fn count_one_different() {
let parser = is('h');
let repeat_count: usize = 500;
let mut tokens: Vec<_> = std::iter::repeat_n('h', repeat_count).collect();
tokens.push('x');
let mut tail: Vec<_> = std::iter::repeat_n('h', repeat_count).collect();
tokens.append(&mut tail);
let mut input = Input::new_from_chars(tokens, None);
let parser = count(&parser, repeat_count);
let output = parser(&mut input).unwrap();
assert!(output.iter().all(|x| *x == 'h')); assert_eq!(input.consumed_count(), repeat_count); assert_eq!(any()(&mut input), Ok('x')); }
#[test]
fn count_not_enough() {
let parser = is('h');
let mut tokens: Vec<_> = std::iter::repeat_n('h', 3).collect();
tokens.push('x');
tokens.push('y');
let mut input = Input::new_from_chars(tokens, None);
let parser = count(&parser, 4); let output = parser(&mut input);
let mismatch = Mismatch::new('h', 'x');
assert_eq!(
output,
Err(Error::UnexpectedToken(
None,
Position::new(1, 4),
Some(mismatch)
))
);
}
#[test]
fn count_not_enough_shortcut() {
let parser = is('h').count(4);
let mut tokens: Vec<_> = std::iter::repeat_n('h', 3).collect();
tokens.push('x');
tokens.push('y');
let mut input = Input::new_from_chars(tokens, None);
let output = parser(&mut input);
let mismatch = Mismatch::new('h', 'x');
assert_eq!(
output,
Err(Error::UnexpectedToken(
None,
Position::new(1, 4),
Some(mismatch)
))
);
}
}