42 lines
945 B
Rust
42 lines
945 B
Rust
|
use std::ops::ControlFlow;
|
||
|
|
||
|
use nom::{
|
||
|
error::{ErrorKind, ParseError},
|
||
|
Err, InputLength, Parser,
|
||
|
};
|
||
|
|
||
|
pub fn fold_till<I, O, E, St, P, F, G>(
|
||
|
mut p: P,
|
||
|
mut init: F,
|
||
|
mut acc: G,
|
||
|
) -> impl FnMut(I) -> nom::IResult<I, St, E>
|
||
|
where
|
||
|
I: InputLength,
|
||
|
E: ParseError<I>,
|
||
|
P: Parser<I, O, E>,
|
||
|
F: FnMut() -> St,
|
||
|
G: FnMut(St, O) -> ControlFlow<St, St>,
|
||
|
{
|
||
|
move |i| {
|
||
|
let mut res = init();
|
||
|
let mut input = i;
|
||
|
|
||
|
loop {
|
||
|
let len = input.input_len();
|
||
|
let (i, o) = p.parse(input)?;
|
||
|
|
||
|
if i.input_len() == len {
|
||
|
return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many0)));
|
||
|
}
|
||
|
|
||
|
match acc(res, o) {
|
||
|
ControlFlow::Continue(next) => {
|
||
|
res = next;
|
||
|
input = i;
|
||
|
}
|
||
|
ControlFlow::Break(res) => return Ok((i, res)),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|