intuicio_parser/
optional.rs

1use crate::{
2    ParseResult, Parser, ParserExt, ParserHandle, ParserNoValue, ParserOutput, ParserRegistry,
3};
4
5pub mod shorthand {
6    use super::*;
7
8    pub fn opt(parser: ParserHandle) -> ParserHandle {
9        OptionalParser::new(parser).into_handle()
10    }
11}
12
13#[derive(Clone)]
14pub struct OptionalParser(ParserHandle);
15
16impl OptionalParser {
17    pub fn new(parser: ParserHandle) -> Self {
18        Self(parser)
19    }
20}
21
22impl Parser for OptionalParser {
23    fn parse<'a>(&self, registry: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
24        match self.0.parse(registry, input) {
25            Ok(result) => Ok(result),
26            Err(_) => Ok((input, ParserOutput::new(ParserNoValue).ok().unwrap())),
27        }
28    }
29
30    fn extend(&self, parser: ParserHandle) {
31        self.0.extend(parser);
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use crate::{
38        optional::OptionalParser,
39        shorthand::{lit, opt},
40        ParserNoValue, ParserRegistry,
41    };
42
43    fn is_async<T: Send + Sync>() {}
44
45    #[test]
46    fn test_optional() {
47        is_async::<OptionalParser>();
48
49        let registry = ParserRegistry::default();
50        let sentence = opt(lit("foo"));
51        let (rest, value) = sentence.parse(&registry, "foobar").unwrap();
52        assert_eq!(rest, "bar");
53        assert!(value.consume::<String>().is_ok());
54        let (rest, value) = sentence.parse(&registry, "barfoo").unwrap();
55        assert_eq!(rest, "barfoo");
56        assert!(value.consume::<ParserNoValue>().is_ok());
57    }
58}