kalosm_sample/structured_parser/
index.rs

1use std::borrow::Cow;
2
3use crate::{CreateParserState, ParseResult, ParseStatus, Parser};
4
5/// The state of the [`IndexParser`] parser
6#[derive(Debug, Clone)]
7pub struct IndexParserState<PA> {
8    states: Vec<ParseResult<PA>>,
9}
10
11/// A parser that parses a sequence of parsers and returns the index of the first parser that succeeds
12#[derive(Debug, Clone)]
13pub struct IndexParser<S: Parser> {
14    parsers: Vec<S>,
15}
16
17impl<S: Parser> IndexParser<S> {
18    /// Create a new index parser
19    pub fn new(parsers: Vec<S>) -> Self {
20        Self { parsers }
21    }
22}
23
24impl<S: CreateParserState> CreateParserState for IndexParser<S> {
25    fn create_parser_state(&self) -> Self::PartialState {
26        IndexParserState {
27            states: self
28                .parsers
29                .iter()
30                .map(|s| Ok(s.create_parser_state()))
31                .collect(),
32        }
33    }
34}
35
36impl<S: Parser> Parser for IndexParser<S> {
37    type Output = (usize, S::Output);
38    type PartialState = IndexParserState<S::PartialState>;
39
40    fn parse<'a>(
41        &self,
42        state: &Self::PartialState,
43        input: &'a [u8],
44    ) -> ParseResult<ParseStatus<'a, Self::PartialState, Self::Output>> {
45        let mut states = state.states.clone();
46        let mut has_incomplete_option = false;
47        let mut required_next: Option<Cow<'static, str>> = None;
48        let last_index = self.parsers.len() - 1;
49        for (i, parser) in self.parsers.iter().enumerate() {
50            match &states[i] {
51                Ok(state) => {
52                    let result = parser.parse(state, input);
53                    match result {
54                        Ok(ParseStatus::Finished {
55                            result,
56                            remaining: r,
57                        }) => {
58                            return Ok(ParseStatus::Finished {
59                                result: (i, result),
60                                remaining: r,
61                            })
62                        }
63                        Ok(ParseStatus::Incomplete {
64                            new_state: s,
65                            required_next: new_required_next,
66                        }) => {
67                            states[i] = Ok(s);
68                            has_incomplete_option = true;
69                            match required_next {
70                                Some(r) => {
71                                    let mut common_bytes = 0;
72                                    for (byte1, byte2) in r.bytes().zip(new_required_next.bytes()) {
73                                        if byte1 != byte2 {
74                                            break;
75                                        }
76                                        common_bytes += 1;
77                                    }
78                                    required_next = Some(match (r, new_required_next) {
79                                        (Cow::Borrowed(required_next), _) => {
80                                            Cow::Borrowed(&required_next[common_bytes..])
81                                        }
82                                        (_, Cow::Borrowed(required_next)) => {
83                                            Cow::Borrowed(&required_next[common_bytes..])
84                                        }
85                                        (Cow::Owned(mut required_next), _) => {
86                                            required_next.truncate(common_bytes);
87                                            Cow::Owned(required_next)
88                                        }
89                                    });
90                                }
91                                None => {
92                                    required_next = Some(new_required_next);
93                                }
94                            }
95                        }
96                        Err(e) => {
97                            if !has_incomplete_option && i == last_index {
98                                return Err(e);
99                            }
100                            states[i] = Err(e);
101                        }
102                    }
103                }
104                Err(err) => {
105                    if !has_incomplete_option && i == last_index {
106                        return Err(err.clone());
107                    }
108                }
109            }
110        }
111        Ok(ParseStatus::Incomplete {
112            new_state: IndexParserState { states },
113            required_next: required_next.unwrap_or_default(),
114        })
115    }
116}