aoc_parse/parsers/
exact.rs

1//! Parser that matches a particular exact string.
2
3use crate::{ParseContext, ParseIter, Parser, Reported, Result};
4
5pub struct ExactParseIter {
6    end: usize,
7}
8
9impl Parser for str {
10    type Output = ();
11    type RawOutput = ();
12    type Iter<'parse> = ExactParseIter;
13
14    fn parse_iter<'parse>(
15        &'parse self,
16        context: &mut ParseContext<'parse>,
17        start: usize,
18    ) -> Result<ExactParseIter, Reported> {
19        if context.source()[start..].starts_with(self) {
20            Ok(ExactParseIter {
21                end: start + self.len(),
22            })
23        } else {
24            Err(context.error_expected(start, &format!("{self:?}")))
25        }
26    }
27}
28
29impl Parser for char {
30    type Output = ();
31    type RawOutput = ();
32    type Iter<'parse> = ExactParseIter;
33
34    fn parse_iter<'parse>(
35        &'parse self,
36        context: &mut ParseContext<'parse>,
37        start: usize,
38    ) -> Result<ExactParseIter, Reported> {
39        if context.source()[start..].starts_with(*self) {
40            Ok(ExactParseIter {
41                end: start + self.len_utf8(),
42            })
43        } else {
44            Err(context.error_expected(start, &format!("{self:?}")))
45        }
46    }
47}
48
49impl<'parse> ParseIter<'parse> for ExactParseIter {
50    type RawOutput = ();
51    fn match_end(&self) -> usize {
52        self.end
53    }
54    fn backtrack(&mut self, _context: &mut ParseContext<'parse>) -> Result<(), Reported> {
55        Err(Reported)
56    }
57    fn convert(&self) {}
58}
59
60#[cfg(test)]
61mod tests {
62    use crate::testing::*;
63
64    #[test]
65    fn test_string_lifetime() {
66        // A string that is locally scoped can serve as a constant for a
67        // parser. No reason why not. The parser lifetime is limited to the
68        // lifetime of the string.
69        let x = format!("{} {}!", "hello", "world");
70        let p: &str = &x;
71        assert_parse_eq(&p, "hello world!", ());
72    }
73
74    #[test]
75    fn test_exact_char_errors() {
76        let p = '\n';
77        assert_parse_error(&p, "q", r#"expected '\n' at"#);
78        assert_parse_error(&p, "", r#"expected '\n' at end"#);
79    }
80}