tree_builder/
public_parsers.rs

1use core::ops::RangeFrom;
2use nom::error::ParseError;
3use nom::IResult;
4use nom::{AsChar, InputIter, InputTake, Slice};
5
6/// Recognizes one character and checks if it satisfies a predicate. The parser will
7/// return the same type with the input.
8pub fn satisfy_one<F, I, Error: ParseError<I>>(cond: F) -> impl Fn(I) -> IResult<I, I, Error>
9where
10    I: Slice<RangeFrom<usize>> + InputIter + InputTake,
11    <I as InputIter>::Item: AsChar,
12    F: Fn(char) -> bool,
13{
14    move |input: I| {
15        if input.iter_elements().next().is_none() {
16            return Err(nom::Err::Error(Error::from_error_kind(
17                input,
18                nom::error::ErrorKind::Eof,
19            )));
20        }
21        match input.take(1usize).iter_elements().nth(0).map(|a| {
22            if cond(a.as_char()) {
23                (input.take(1), true)
24            } else {
25                (input.take(1), false)
26            }
27        }) {
28            Some((slice, matched)) => {
29                if matched {
30                    Ok((input.slice(1usize..), slice))
31                } else {
32                    Err(nom::Err::Error(Error::from_error_kind(
33                        input,
34                        nom::error::ErrorKind::Satisfy,
35                    )))
36                }
37            }
38            _ => Err(nom::Err::Error(Error::from_error_kind(
39                input,
40                nom::error::ErrorKind::Eof,
41            ))),
42        }
43    }
44}
45
46#[cfg(test)]
47mod test {
48    use crate::public_parsers::satisfy_one;
49
50    #[test]
51    fn satisfy_one_test() {
52        let input = "";
53        match satisfy_one::<_, _, (&str, nom::error::ErrorKind)>(|_| true)(input) {
54            Ok(_) => panic!("Wrong behavior, should return error with ErrorKind EOF"),
55            Err(nom::Err::Error((_, code))) => match code {
56                nom::error::ErrorKind::Eof => (),
57                _ => panic!("Wrong behavior, should return error with ErrorKind EOF"),
58            },
59            Err(_) => panic!("?? What are these error types"),
60        }
61    }
62}