kalosm_sample/structured_parser/index.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 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 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
use std::borrow::Cow;
use crate::{CreateParserState, ParseResult, ParseStatus, Parser};
/// The state of the [`IndexParser`] parser
#[derive(Debug, Clone)]
pub struct IndexParserState<PA> {
states: Vec<ParseResult<PA>>,
}
/// A parser that parses a sequence of parsers and returns the index of the first parser that succeeds
#[derive(Debug, Clone)]
pub struct IndexParser<S: Parser> {
parsers: Vec<S>,
}
impl<S: Parser> IndexParser<S> {
/// Create a new index parser
pub fn new(parsers: Vec<S>) -> Self {
Self { parsers }
}
}
impl<S: CreateParserState> CreateParserState for IndexParser<S> {
fn create_parser_state(&self) -> Self::PartialState {
IndexParserState {
states: self
.parsers
.iter()
.map(|s| Ok(s.create_parser_state()))
.collect(),
}
}
}
impl<S: Parser> Parser for IndexParser<S> {
type Output = (usize, S::Output);
type PartialState = IndexParserState<S::PartialState>;
fn parse<'a>(
&self,
state: &Self::PartialState,
input: &'a [u8],
) -> ParseResult<ParseStatus<'a, Self::PartialState, Self::Output>> {
let mut states = state.states.clone();
let mut has_incomplete_option = false;
let mut required_next: Option<Cow<'static, str>> = None;
let last_index = self.parsers.len() - 1;
for (i, parser) in self.parsers.iter().enumerate() {
match &states[i] {
Ok(state) => {
let result = parser.parse(state, input);
match result {
Ok(ParseStatus::Finished {
result,
remaining: r,
}) => {
return Ok(ParseStatus::Finished {
result: (i, result),
remaining: r,
})
}
Ok(ParseStatus::Incomplete {
new_state: s,
required_next: new_required_next,
}) => {
states[i] = Ok(s);
has_incomplete_option = true;
match required_next {
Some(r) => {
let mut common_bytes = 0;
for (byte1, byte2) in r.bytes().zip(new_required_next.bytes()) {
if byte1 != byte2 {
break;
}
common_bytes += 1;
}
required_next = Some(match (r, new_required_next) {
(Cow::Borrowed(required_next), _) => {
Cow::Borrowed(&required_next[common_bytes..])
}
(_, Cow::Borrowed(required_next)) => {
Cow::Borrowed(&required_next[common_bytes..])
}
(Cow::Owned(mut required_next), _) => {
required_next.truncate(common_bytes);
Cow::Owned(required_next)
}
});
}
None => {
required_next = Some(new_required_next);
}
}
}
Err(e) => {
if !has_incomplete_option && i == last_index {
return Err(e);
}
states[i] = Err(e);
}
}
}
Err(err) => {
if !has_incomplete_option && i == last_index {
return Err(err.clone());
}
}
}
}
Ok(ParseStatus::Incomplete {
new_state: IndexParserState { states },
required_next: required_next.unwrap_or_default(),
})
}
}