access_json/
query_parser.rs

1use crate::query::QueryElement;
2
3pub(crate) fn parse_query(input: &str) -> Result<Vec<QueryElement>, QueryParseErr> {
4    let mut output = Vec::new();
5    let mut parser = Parser::from(input);
6    while let Some(it) = parser.next()? {
7        output.push(it);
8    }
9    Ok(output)
10}
11
12/// An enum representing errors possible while parsing a query.
13///
14/// All ``usize`` fields in these errors represent the character index where the parser detected the failure.
15#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
16pub enum QueryParseErr {
17    /// Each parsable element must start with '.' or '['
18    BadCharacter(usize),
19    /// Need a field name; encountered a ".." in the query.
20    MissingField,
21    /// Need a number; encountered a "[]" in the query.
22    MissingNumber(usize),
23    /// Got some kind of non-decimal digit inside the brackets "[]".
24    BadArray(usize),
25    /// Got some kind of bad character (or whitespace) inside a '.'
26    BadField(usize),
27    /// Reached the end of the string while looking for a specific character (probably ']')
28    UnexpectedEOF(char),
29    /// Found a strange character at the given position.
30    Unexpected(usize, char),
31    /// Could not parse the number in your brackets to a usize. String is the IntError in question.
32    BadIndex(usize, String),
33}
34
35impl std::fmt::Display for QueryParseErr {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        write!(f, "{:?}", self)
38    }
39}
40
41impl std::error::Error for QueryParseErr {}
42
43struct Parser {
44    data: Vec<char>,
45    position: usize,
46}
47
48impl From<&str> for Parser {
49    fn from(input: &str) -> Parser {
50        Parser {
51            data: input.chars().collect(),
52            position: 0,
53        }
54    }
55}
56
57impl Parser {
58    fn peek(&self) -> Option<char> {
59        self.data.get(self.position).cloned()
60    }
61    fn advance(&mut self) -> Option<char> {
62        let found = self.peek();
63        self.position += 1;
64        found
65    }
66    fn consume(&mut self, expected: char) -> Result<(), QueryParseErr> {
67        match self.advance() {
68            None => Err(QueryParseErr::UnexpectedEOF(expected)),
69            Some(actual) => {
70                if actual == expected {
71                    Ok(())
72                } else {
73                    Err(QueryParseErr::Unexpected(self.position - 1, expected))
74                }
75            }
76        }
77    }
78    fn read_array(&mut self) -> Result<QueryElement, QueryParseErr> {
79        self.consume('[')?;
80        let mut digits = String::new();
81        let start = self.position;
82
83        while let Some(ch) = self.advance() {
84            if ch == ']' {
85                break;
86            } else if ch.is_digit(10) {
87                digits.push(ch);
88            } else {
89                return Err(QueryParseErr::BadArray(self.position - 1));
90            }
91        }
92
93        if digits.is_empty() {
94            Err(QueryParseErr::MissingNumber(start))
95        } else {
96            let num = digits
97                .parse::<usize>()
98                .map_err(|e| QueryParseErr::BadIndex(start, e.to_string()))?;
99            Ok(QueryElement::ArrayItem(num))
100        }
101    }
102    fn read_field(&mut self) -> Result<QueryElement, QueryParseErr> {
103        self.consume('.')?;
104        let mut id = String::new();
105        while let Some(ch) = self.peek() {
106            if ch == '.' || ch == '[' {
107                break;
108            } else if ch.is_whitespace() {
109                return Err(QueryParseErr::BadField(self.position - 1));
110            }
111            self.consume(ch)?;
112            id.push(ch);
113        }
114        if id.is_empty() {
115            Err(QueryParseErr::MissingField)
116        } else {
117            Ok(QueryElement::Field(id))
118        }
119    }
120    fn next(&mut self) -> Result<Option<QueryElement>, QueryParseErr> {
121        if let Some(ch) = self.peek() {
122            Ok(Some(if ch == '[' {
123                self.read_array()?
124            } else if ch == '.' {
125                self.read_field()?
126            } else {
127                return Err(QueryParseErr::BadCharacter(self.position));
128            }))
129        } else {
130            Ok(None)
131        }
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::parse_query;
138    use super::QueryParseErr;
139    use crate::query::QueryElement as Q;
140
141    #[test]
142    fn test_dots_happy() {
143        assert_eq!(
144            parse_query(".a.b.c").unwrap(),
145            vec![Q::field("a"), Q::field("b"), Q::field("c")]
146        )
147    }
148
149    #[test]
150    fn test_array_happy() {
151        assert_eq!(
152            parse_query("[0][7]").unwrap(),
153            vec![Q::array_item(0), Q::array_item(7)]
154        )
155    }
156
157    #[test]
158    fn test_parse_mixed() {
159        assert_eq!(
160            parse_query(".a.b[7].c.e[5]").unwrap(),
161            vec![
162                Q::field("a"),
163                Q::field("b"),
164                Q::array_item(7),
165                Q::field("c"),
166                Q::field("e"),
167                Q::array_item(5)
168            ]
169        )
170    }
171
172    #[test]
173    fn test_missing_field() {
174        assert_eq!(
175            parse_query(".a.b.").unwrap_err(),
176            QueryParseErr::MissingField
177        );
178    }
179
180    #[test]
181    fn test_bad_numbers() {
182        assert_eq!(
183            parse_query("[0][]").unwrap_err(),
184            QueryParseErr::MissingNumber(4)
185        )
186    }
187
188    #[test]
189    fn test_array_not_closed() {
190        assert_eq!(
191            parse_query("[").unwrap_err(),
192            QueryParseErr::MissingNumber(1)
193        )
194    }
195}