kalosm_sample/structured_parser/
one_line.rs

1use crate::{CreateParserState, ParseResult, ParseStatus, Parser};
2
3/// One line of text with some non-whitespace characters
4#[derive(Debug, Clone, Copy)]
5pub struct OneLine;
6
7/// The state of the [`OneLine`] parser
8#[derive(Debug, Clone)]
9pub struct OneLineState {
10    all_whitespace: bool,
11    bytes: Vec<u8>,
12}
13
14impl CreateParserState for OneLine {
15    fn create_parser_state(&self) -> <Self as Parser>::PartialState {
16        OneLineState {
17            all_whitespace: true,
18            bytes: Vec::new(),
19        }
20    }
21}
22
23/// An error that can occur when parsing a [`OneLine`]
24#[derive(Debug, Clone)]
25pub struct OneLineError;
26
27impl std::fmt::Display for OneLineError {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        write!(f, "OneLineError")
30    }
31}
32
33impl std::error::Error for OneLineError {}
34
35impl Parser for OneLine {
36    type Output = String;
37    type PartialState = OneLineState;
38
39    fn parse<'a>(
40        &self,
41        state: &Self::PartialState,
42        input: &'a [u8],
43    ) -> ParseResult<ParseStatus<'a, Self::PartialState, Self::Output>> {
44        if input.is_empty() {
45            return Ok(ParseStatus::Incomplete {
46                new_state: state.clone(),
47                required_next: Default::default(),
48            });
49        }
50        let mut state = state.clone();
51        let mut iter = input.iter();
52        while let Some(&c) = iter.next() {
53            if !c.is_ascii_alphanumeric() || matches!(c, b' ' | b'.' | b'\n') {
54                crate::bail!(OneLineError);
55            }
56            if state.all_whitespace {
57                let c = char::from(c);
58                if !c.is_whitespace() {
59                    state.all_whitespace = false;
60                }
61            }
62            if c == b'\n' {
63                if state.all_whitespace {
64                    crate::bail!(OneLineError);
65                } else {
66                    return Ok(ParseStatus::Finished {
67                        result: String::from_utf8_lossy(&state.bytes).to_string(),
68                        remaining: iter.as_slice(),
69                    });
70                }
71            }
72            state.bytes.push(c);
73        }
74        Ok(ParseStatus::Incomplete {
75            new_state: state,
76            required_next: Default::default(),
77        })
78    }
79}