Struct aoc_parse::ParseContext

source ·
pub struct ParseContext<'parse> { /* private fields */ }
Expand description

Contains the source text we’re parsing and tracks errors.

We track errors in the ParseContext, not Results, because often a parser produces both a successful match and the error that will later prove to be the best error message for the overall parse attempt.

The :wq example

For example, consider parser!(line(u32)+) parsing the following input:

1
2
3
4:wq
5

Clearly, someone accidentally typed :wq on line 4. But what will happen here is that line(u32)+ successfully matches the first 3 lines. If we don’t track the error we encountered when trying to parse 5:wq as a u32, but content ourselves with the successful match line(u32)+ produces, the best error message we can ultimately produce is something like “found extra text after a successful match at line 4, column 1”.

Here’s how we now handle these success-failures:

  • u32 returns success, matching 4.

  • line(u32) reports an error to the context (at line 4 column 2) and returns Reported, because u32 didn’t match the entire line.

  • line(u32)+ then discards the Reported error, backtracks, and returns a successful match for the first 3 lines.

  • The top-level parser sees that line(u32)+ didn’t match the entire input, and reports an error to the context at line 4 column 1. But we already have a previous error where we had got further, so this error is ignored.

  • The error at line 4 column 2 is taken from the context and returned to the user.

Rationale: Design alternatives

To implement this without ParseContext, we could have implemented a TigerResult<T, E> type that can be Ok(T), Err(E), or OkBut(T, E), the last containing both a success value and an excuse explaining why we did not succeed even more. The forwardmost error would be propagated there instead of being stored in the context. We would use TigerResult<T, ParseError> instead of Result<T, Reported> everywhere. Both ways have advantages. Both are pretty weird for Rust. The way of the context is something I’ve wanted to explore in Rust; and it lets us keep using the ? try operator.

Implementations§

Create a ParseContext to parse the given input.

Examples found in repository?
src/traits.rs (line 55)
54
55
56
57
58
59
60
61
62
63
64
65
66
67
    fn parse_raw(&self, s: &str) -> Result<Self::RawOutput> {
        let mut ctx = ParseContext::new(s);
        let mut it = match self.parse_iter(&mut ctx, 0) {
            Ok(iter) => iter,
            Err(Reported) => return Err(ctx.into_reported_error()),
        };
        while it.match_end() != s.len() {
            ctx.error_extra(it.match_end());
            if it.backtrack(&mut ctx).is_err() {
                return Err(ctx.into_reported_error());
            }
        }
        Ok(it.convert())
    }
More examples
Hide additional examples
src/parsers/lines.rs (line 109)
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
fn match_fully<'parse, R, P>(parser: &'parse P, source: &'parse str) -> Result<P::Iter<'parse>>
where
    R: Region,
    P: Parser,
{
    let mut context = ParseContext::new(source);
    let mut iter = match parser.parse_iter(&mut context, 0) {
        Ok(iter) => iter,
        Err(Reported) => return Err(context.into_reported_error()),
    };
    while iter.match_end() != source.len() {
        R::report_incomplete_match(&mut context, iter.match_end());
        if iter.backtrack(&mut context).is_err() {
            return Err(context.into_reported_error());
        }
    }
    Ok(iter)
}

The text being parsed.

Examples found in repository?
src/context.rs (line 116)
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
    pub fn error_expected(&mut self, start: usize, expected: &str) -> Reported {
        self.report(ParseError::new_expected(self.source(), start, expected))
    }

    /// Record an error when `FromStr::from_str` fails.
    pub fn error_from_str_failed(
        &mut self,
        start: usize,
        end: usize,
        type_name: &'static str,
        message: String,
    ) -> Reported {
        self.report(ParseError::new_from_str_failed(
            self.source(),
            start,
            end,
            type_name,
            message,
        ))
    }

    /// Record an "extra unparsed text after match" error.
    pub fn error_extra(&mut self, location: usize) -> Reported {
        self.report(ParseError::new_extra(self.source(), location))
    }
More examples
Hide additional examples
src/parsers/lines.rs (line 44)
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
    fn check_at_start(context: &mut ParseContext, start: usize) -> Result<(), Reported> {
        let source = context.source();
        if start == 0 || source[..start].ends_with('\n') {
            Ok(())
        } else {
            Err(context.report(ParseError::new_bad_line_start(source, start)))
        }
    }

    fn find_end(context: &mut ParseContext, start: usize) -> Result<(usize, usize), Reported> {
        let source = context.source();
        match source[start..].find('\n') {
            Some(offset) => Ok((start + offset, start + offset + 1)),
            None if start != source.len() => Ok((source.len(), source.len())),
            None => Err(context.error_expected(source.len(), "line")),
        }
    }

    fn report_incomplete_match(context: &mut ParseContext, end: usize) -> Reported {
        context.report(ParseError::new_line_extra(context.source(), end))
    }
}

/// A "section" is a sequence of zero or more nonblank lines, starting either
/// at the beginning of the input or immediately after a newline; followed by
/// either a blank line or the end of input.
#[derive(Debug, Clone, Copy)]
pub struct Section;

impl Region for Section {
    fn check_at_start(context: &mut ParseContext, start: usize) -> Result<(), Reported> {
        let source = context.source();
        if start == 0 || &source[..start] == "\n" || source[..start].ends_with("\n\n") {
            Ok(())
        } else {
            Err(context.report(ParseError::new_bad_section_start(source, start)))
        }
    }

    fn find_end(context: &mut ParseContext, start: usize) -> Result<(usize, usize), Reported> {
        // FIXME BUG: unclear what this should do when looking at an empty
        // section at end of input. presumably not repeat forever. (why does
        // this not always hang forever if you try to use `sections`?)
        let source = context.source();
        match source[start..].find("\n\n") {
            // ending at a blank line
            Some(index) => Ok((start + index + 1, start + index + 2)),
            // ending at the end of `source`
            None if start < source.len() => Ok((source.len(), source.len())),
            // no end-of-section delimiter found
            None => Err(context.error_expected(source.len(), "section")),
        }
    }

    fn report_incomplete_match(context: &mut ParseContext, end: usize) -> Reported {
        context.report(ParseError::new_section_extra(context.source(), end))
    }
}

/// Match but don't convert; just return the ParseIter on success. Expects all
/// of `source` to be matched, otherwise it's an error.
fn match_fully<'parse, R, P>(parser: &'parse P, source: &'parse str) -> Result<P::Iter<'parse>>
where
    R: Region,
    P: Parser,
{
    let mut context = ParseContext::new(source);
    let mut iter = match parser.parse_iter(&mut context, 0) {
        Ok(iter) => iter,
        Err(Reported) => return Err(context.into_reported_error()),
    };
    while iter.match_end() != source.len() {
        R::report_incomplete_match(&mut context, iter.match_end());
        if iter.backtrack(&mut context).is_err() {
            return Err(context.into_reported_error());
        }
    }
    Ok(iter)
}

#[derive(Copy, Clone)]
pub struct RegionParser<R: Region, P> {
    parser: P,
    phantom: PhantomData<fn() -> R>,
}

impl<R, P> Parser for RegionParser<R, P>
where
    R: Region,
    P: Parser,
{
    type RawOutput = (P::Output,);
    type Output = P::Output;
    type Iter<'parse> = RegionParseIter<'parse, P>
    where
        R: 'parse,
        P: 'parse;

    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        R::check_at_start(context, start)?;
        let (inner_end, outer_end) = R::find_end(context, start)?;

        let source = context.source();
        let iter = match_fully::<R, P>(&self.parser, &source[start..inner_end])
            .map_err(|err| context.report(err.adjust_location(source, start)))?;

        Ok(RegionParseIter { iter, outer_end })
    }
src/parsers/string.rs (line 36)
29
30
31
32
33
34
35
36
37
38
39
40
    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        let iter = self.parser.parse_iter(context, start)?;
        Ok(StringParseIter {
            source: context.source(),
            start,
            iter,
        })
    }
src/parsers/exact.rs (line 19)
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<ExactParseIter, Reported> {
        if context.source()[start..].starts_with(self) {
            Ok(ExactParseIter {
                end: start + self.len(),
            })
        } else {
            Err(context.error_expected(start, &format!("{self:?}")))
        }
    }
}

impl Parser for char {
    type Output = ();
    type RawOutput = ();
    type Iter<'parse> = ExactParseIter;

    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<ExactParseIter, Reported> {
        if context.source()[start..].starts_with(*self) {
            Ok(ExactParseIter {
                end: start + self.len_utf8(),
            })
        } else {
            Err(context.error_expected(start, &format!("{self:?}")))
        }
    }
src/parsers/chars.rs (line 33)
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        match context.source()[start..].chars().next() {
            Some(c) if (self.predicate)(c) => Ok(CharParseIter {
                c,
                end: start + c.len_utf8(),
            }),
            _ => Err(context.error_expected(start, self.noun)),
        }
    }
}

impl<'parse> ParseIter<'parse> for CharParseIter {
    type RawOutput = (char,);
    fn match_end(&self) -> usize {
        self.end
    }
    fn backtrack(&mut self, _context: &mut ParseContext<'parse>) -> Result<(), Reported> {
        Err(Reported)
    }
    fn convert(&self) -> (char,) {
        (self.c,)
    }
}

impl Parser for CharOfParser {
    type Output = usize;
    type RawOutput = (usize,);
    type Iter<'parse> = BasicParseIter<usize>;
    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        if let Some(c) = context.source()[start..].chars().next() {
            // Note: `self.options.find(c)` would give the wrong answer here: we
            // want the number of characters before `c`, not bytes.
            for (i, x) in self.options.chars().enumerate() {
                if c == x {
                    return Ok(BasicParseIter {
                        value: i,
                        end: start + c.len_utf8(),
                    });
                }
            }
        }
        Err(context.error_expected(start, &format!("one of {:?}", self.options)))
    }
src/parsers/regex.rs (line 58)
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        match (self.regex)().find(&context.source()[start..]) {
            None => Err(context.error_expected(start, any::type_name::<T>())),
            Some(m) => match (self.parse_fn)(m.as_str()) {
                Ok(value) => Ok(BasicParseIter {
                    end: start + m.end(),
                    value,
                }),
                Err(err) => Err(context.error_from_str_failed(
                    start,
                    start + m.end(),
                    any::type_name::<T>(),
                    format!("{err}"),
                )),
            },
        }
    }

Extract the error. Use this only after receiving Reported from an operation on the context.

Panics

If no error has been reported on this context.

Examples found in repository?
src/traits.rs (line 58)
54
55
56
57
58
59
60
61
62
63
64
65
66
67
    fn parse_raw(&self, s: &str) -> Result<Self::RawOutput> {
        let mut ctx = ParseContext::new(s);
        let mut it = match self.parse_iter(&mut ctx, 0) {
            Ok(iter) => iter,
            Err(Reported) => return Err(ctx.into_reported_error()),
        };
        while it.match_end() != s.len() {
            ctx.error_extra(it.match_end());
            if it.backtrack(&mut ctx).is_err() {
                return Err(ctx.into_reported_error());
            }
        }
        Ok(it.convert())
    }
More examples
Hide additional examples
src/parsers/lines.rs (line 112)
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
fn match_fully<'parse, R, P>(parser: &'parse P, source: &'parse str) -> Result<P::Iter<'parse>>
where
    R: Region,
    P: Parser,
{
    let mut context = ParseContext::new(source);
    let mut iter = match parser.parse_iter(&mut context, 0) {
        Ok(iter) => iter,
        Err(Reported) => return Err(context.into_reported_error()),
    };
    while iter.match_end() != source.len() {
        R::report_incomplete_match(&mut context, iter.match_end());
        if iter.backtrack(&mut context).is_err() {
            return Err(context.into_reported_error());
        }
    }
    Ok(iter)
}

Record an error.

Currently a ParseContext only tracks the foremost error. That is, if err.location is farther forward than any other error we’ve encountered, we store it. Otherwise discard it.

Nontrivial patterns try several different things. If anything succeeds, we get a match. We only fail if every branch leads to failure. This means that by the time matching fails, we have an abundance of different error messages. Generally the error we want is the one where we progressed as far as possible through the input string before failing.

Examples found in repository?
src/context.rs (line 116)
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
    pub fn error_expected(&mut self, start: usize, expected: &str) -> Reported {
        self.report(ParseError::new_expected(self.source(), start, expected))
    }

    /// Record an error when `FromStr::from_str` fails.
    pub fn error_from_str_failed(
        &mut self,
        start: usize,
        end: usize,
        type_name: &'static str,
        message: String,
    ) -> Reported {
        self.report(ParseError::new_from_str_failed(
            self.source(),
            start,
            end,
            type_name,
            message,
        ))
    }

    /// Record an "extra unparsed text after match" error.
    pub fn error_extra(&mut self, location: usize) -> Reported {
        self.report(ParseError::new_extra(self.source(), location))
    }
More examples
Hide additional examples
src/parsers/lines.rs (line 48)
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
    fn check_at_start(context: &mut ParseContext, start: usize) -> Result<(), Reported> {
        let source = context.source();
        if start == 0 || source[..start].ends_with('\n') {
            Ok(())
        } else {
            Err(context.report(ParseError::new_bad_line_start(source, start)))
        }
    }

    fn find_end(context: &mut ParseContext, start: usize) -> Result<(usize, usize), Reported> {
        let source = context.source();
        match source[start..].find('\n') {
            Some(offset) => Ok((start + offset, start + offset + 1)),
            None if start != source.len() => Ok((source.len(), source.len())),
            None => Err(context.error_expected(source.len(), "line")),
        }
    }

    fn report_incomplete_match(context: &mut ParseContext, end: usize) -> Reported {
        context.report(ParseError::new_line_extra(context.source(), end))
    }
}

/// A "section" is a sequence of zero or more nonblank lines, starting either
/// at the beginning of the input or immediately after a newline; followed by
/// either a blank line or the end of input.
#[derive(Debug, Clone, Copy)]
pub struct Section;

impl Region for Section {
    fn check_at_start(context: &mut ParseContext, start: usize) -> Result<(), Reported> {
        let source = context.source();
        if start == 0 || &source[..start] == "\n" || source[..start].ends_with("\n\n") {
            Ok(())
        } else {
            Err(context.report(ParseError::new_bad_section_start(source, start)))
        }
    }

    fn find_end(context: &mut ParseContext, start: usize) -> Result<(usize, usize), Reported> {
        // FIXME BUG: unclear what this should do when looking at an empty
        // section at end of input. presumably not repeat forever. (why does
        // this not always hang forever if you try to use `sections`?)
        let source = context.source();
        match source[start..].find("\n\n") {
            // ending at a blank line
            Some(index) => Ok((start + index + 1, start + index + 2)),
            // ending at the end of `source`
            None if start < source.len() => Ok((source.len(), source.len())),
            // no end-of-section delimiter found
            None => Err(context.error_expected(source.len(), "section")),
        }
    }

    fn report_incomplete_match(context: &mut ParseContext, end: usize) -> Reported {
        context.report(ParseError::new_section_extra(context.source(), end))
    }
}

/// Match but don't convert; just return the ParseIter on success. Expects all
/// of `source` to be matched, otherwise it's an error.
fn match_fully<'parse, R, P>(parser: &'parse P, source: &'parse str) -> Result<P::Iter<'parse>>
where
    R: Region,
    P: Parser,
{
    let mut context = ParseContext::new(source);
    let mut iter = match parser.parse_iter(&mut context, 0) {
        Ok(iter) => iter,
        Err(Reported) => return Err(context.into_reported_error()),
    };
    while iter.match_end() != source.len() {
        R::report_incomplete_match(&mut context, iter.match_end());
        if iter.backtrack(&mut context).is_err() {
            return Err(context.into_reported_error());
        }
    }
    Ok(iter)
}

#[derive(Copy, Clone)]
pub struct RegionParser<R: Region, P> {
    parser: P,
    phantom: PhantomData<fn() -> R>,
}

impl<R, P> Parser for RegionParser<R, P>
where
    R: Region,
    P: Parser,
{
    type RawOutput = (P::Output,);
    type Output = P::Output;
    type Iter<'parse> = RegionParseIter<'parse, P>
    where
        R: 'parse,
        P: 'parse;

    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        R::check_at_start(context, start)?;
        let (inner_end, outer_end) = R::find_end(context, start)?;

        let source = context.source();
        let iter = match_fully::<R, P>(&self.parser, &source[start..inner_end])
            .map_err(|err| context.report(err.adjust_location(source, start)))?;

        Ok(RegionParseIter { iter, outer_end })
    }

Record a foo expected error.

Examples found in repository?
src/parsers/exact.rs (line 24)
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<ExactParseIter, Reported> {
        if context.source()[start..].starts_with(self) {
            Ok(ExactParseIter {
                end: start + self.len(),
            })
        } else {
            Err(context.error_expected(start, &format!("{self:?}")))
        }
    }
}

impl Parser for char {
    type Output = ();
    type RawOutput = ();
    type Iter<'parse> = ExactParseIter;

    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<ExactParseIter, Reported> {
        if context.source()[start..].starts_with(*self) {
            Ok(ExactParseIter {
                end: start + self.len_utf8(),
            })
        } else {
            Err(context.error_expected(start, &format!("{self:?}")))
        }
    }
More examples
Hide additional examples
src/parsers/lines.rs (line 57)
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
    fn find_end(context: &mut ParseContext, start: usize) -> Result<(usize, usize), Reported> {
        let source = context.source();
        match source[start..].find('\n') {
            Some(offset) => Ok((start + offset, start + offset + 1)),
            None if start != source.len() => Ok((source.len(), source.len())),
            None => Err(context.error_expected(source.len(), "line")),
        }
    }

    fn report_incomplete_match(context: &mut ParseContext, end: usize) -> Reported {
        context.report(ParseError::new_line_extra(context.source(), end))
    }
}

/// A "section" is a sequence of zero or more nonblank lines, starting either
/// at the beginning of the input or immediately after a newline; followed by
/// either a blank line or the end of input.
#[derive(Debug, Clone, Copy)]
pub struct Section;

impl Region for Section {
    fn check_at_start(context: &mut ParseContext, start: usize) -> Result<(), Reported> {
        let source = context.source();
        if start == 0 || &source[..start] == "\n" || source[..start].ends_with("\n\n") {
            Ok(())
        } else {
            Err(context.report(ParseError::new_bad_section_start(source, start)))
        }
    }

    fn find_end(context: &mut ParseContext, start: usize) -> Result<(usize, usize), Reported> {
        // FIXME BUG: unclear what this should do when looking at an empty
        // section at end of input. presumably not repeat forever. (why does
        // this not always hang forever if you try to use `sections`?)
        let source = context.source();
        match source[start..].find("\n\n") {
            // ending at a blank line
            Some(index) => Ok((start + index + 1, start + index + 2)),
            // ending at the end of `source`
            None if start < source.len() => Ok((source.len(), source.len())),
            // no end-of-section delimiter found
            None => Err(context.error_expected(source.len(), "section")),
        }
    }
src/parsers/chars.rs (line 38)
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        match context.source()[start..].chars().next() {
            Some(c) if (self.predicate)(c) => Ok(CharParseIter {
                c,
                end: start + c.len_utf8(),
            }),
            _ => Err(context.error_expected(start, self.noun)),
        }
    }
}

impl<'parse> ParseIter<'parse> for CharParseIter {
    type RawOutput = (char,);
    fn match_end(&self) -> usize {
        self.end
    }
    fn backtrack(&mut self, _context: &mut ParseContext<'parse>) -> Result<(), Reported> {
        Err(Reported)
    }
    fn convert(&self) -> (char,) {
        (self.c,)
    }
}

impl Parser for CharOfParser {
    type Output = usize;
    type RawOutput = (usize,);
    type Iter<'parse> = BasicParseIter<usize>;
    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        if let Some(c) = context.source()[start..].chars().next() {
            // Note: `self.options.find(c)` would give the wrong answer here: we
            // want the number of characters before `c`, not bytes.
            for (i, x) in self.options.chars().enumerate() {
                if c == x {
                    return Ok(BasicParseIter {
                        value: i,
                        end: start + c.len_utf8(),
                    });
                }
            }
        }
        Err(context.error_expected(start, &format!("one of {:?}", self.options)))
    }
src/parsers/regex.rs (line 59)
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        match (self.regex)().find(&context.source()[start..]) {
            None => Err(context.error_expected(start, any::type_name::<T>())),
            Some(m) => match (self.parse_fn)(m.as_str()) {
                Ok(value) => Ok(BasicParseIter {
                    end: start + m.end(),
                    value,
                }),
                Err(err) => Err(context.error_from_str_failed(
                    start,
                    start + m.end(),
                    any::type_name::<T>(),
                    format!("{err}"),
                )),
            },
        }
    }

Record an error when FromStr::from_str fails.

Examples found in repository?
src/parsers/regex.rs (lines 65-70)
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        match (self.regex)().find(&context.source()[start..]) {
            None => Err(context.error_expected(start, any::type_name::<T>())),
            Some(m) => match (self.parse_fn)(m.as_str()) {
                Ok(value) => Ok(BasicParseIter {
                    end: start + m.end(),
                    value,
                }),
                Err(err) => Err(context.error_from_str_failed(
                    start,
                    start + m.end(),
                    any::type_name::<T>(),
                    format!("{err}"),
                )),
            },
        }
    }

Record an “extra unparsed text after match” error.

Examples found in repository?
src/traits.rs (line 61)
54
55
56
57
58
59
60
61
62
63
64
65
66
67
    fn parse_raw(&self, s: &str) -> Result<Self::RawOutput> {
        let mut ctx = ParseContext::new(s);
        let mut it = match self.parse_iter(&mut ctx, 0) {
            Ok(iter) => iter,
            Err(Reported) => return Err(ctx.into_reported_error()),
        };
        while it.match_end() != s.len() {
            ctx.error_extra(it.match_end());
            if it.backtrack(&mut ctx).is_err() {
                return Err(ctx.into_reported_error());
            }
        }
        Ok(it.convert())
    }

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.