quoted_string_parser/
parser.rs

1use crate::pest::Parser;
2
3/// Parser for text that meets the "quoted-string" grammar.
4///```rust
5/// use quoted_string_parser::{QuotedStringParser, QuotedStringParseLevel};
6///
7/// // two qdtexts separated by a whitespace
8/// assert!(QuotedStringParser::validate(
9///   QuotedStringParseLevel::QuotedString, "\"Hello world\""));
10///
11/// // one quoted-pair
12/// assert!(QuotedStringParser::validate(
13///   QuotedStringParseLevel::QuotedString, "\"\\\u{7f}\""));
14///```
15///
16/// QuotedStringParser derives from [Parser](https://docs.rs/pest/latest/pest/trait.Parser.html),
17/// if you need more control over the parser itself you can use any
18/// of the operations defined in the [pest](https://docs.rs/pest/latest/pest/)
19/// crate. Check the documentation for more information.
20#[derive(Parser)]
21#[grammar = "quoted_string.pest"]
22pub struct QuotedStringParser;
23
24impl QuotedStringParser {
25    /// Validate that the input meets the grammar
26    pub fn validate(lvl: QuotedStringParseLevel, input: &str) -> bool {
27        let rule = match lvl {
28            QuotedStringParseLevel::QuotedString => Rule::quoted_string,
29            QuotedStringParseLevel::QuotedText => Rule::quoted_text,
30        };
31        QuotedStringParser::parse(rule, input).is_ok()
32    }
33}
34
35/// Defines the level at which the grammar should be applied.
36pub enum QuotedStringParseLevel {
37    /// The whole quoted-string grammar.
38    QuotedString,
39    /// Only sequences of qdtext / quoted-pair values. Some protocols
40    /// like Stun only checks sequences of qdtext and quoted-pairs
41    /// without the double quotes and their surrounding whitespaces.
42    QuotedText,
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use crate::pest::Parser;
49
50    #[test]
51    fn valid_quoted_string() {
52        // Empty quoted string ""
53        QuotedStringParser::parse(Rule::quoted_string, "\"\"")
54            .expect("Could not parse QuotedString");
55
56        // qdtext
57        QuotedStringParser::parse(Rule::quoted_string, "\"\u{21}\"")
58            .expect("Could not parse QuotedString");
59        QuotedStringParser::parse(Rule::quoted_string, "\"\u{23}\"")
60            .expect("Could not parse QuotedString");
61        QuotedStringParser::parse(Rule::quoted_string, "\"\u{5b}\"")
62            .expect("Could not parse QuotedString");
63        QuotedStringParser::parse(Rule::quoted_string, "\"\u{5d}\"")
64            .expect("Could not parse QuotedString");
65        QuotedStringParser::parse(Rule::quoted_string, "\"\u{7e}\"")
66            .expect("Could not parse QuotedString");
67
68        // qdtext (utf8_non_ascii)
69        QuotedStringParser::parse(Rule::quoted_string, "\"\u{c0}\u{80}\"")
70            .expect("Could not parse QuotedString");
71        QuotedStringParser::parse(Rule::quoted_string, "\"\u{df}\u{bf}\"")
72            .expect("Could not parse QuotedString");
73        QuotedStringParser::parse(Rule::quoted_string, "\"\u{e0}\u{80}\u{bf}\"")
74            .expect("Could not parse QuotedString");
75        QuotedStringParser::parse(Rule::quoted_string, "\"\u{ef}\u{80}\u{bf}\"")
76            .expect("Could not parse QuotedString");
77        QuotedStringParser::parse(Rule::quoted_string, "\"\u{f0}\u{80}\u{81}\u{bf}\"")
78            .expect("Could not parse QuotedString");
79        QuotedStringParser::parse(Rule::quoted_string, "\"\u{f7}\u{80}\u{81}\u{bf}\"")
80            .expect("Could not parse QuotedString");
81        QuotedStringParser::parse(Rule::quoted_string, "\"\u{f8}\u{80}\u{81}\u{82}\u{bf}\"")
82            .expect("Could not parse QuotedString");
83        QuotedStringParser::parse(Rule::quoted_string, "\"\u{fb}\u{80}\u{81}\u{82}\u{bf}\"")
84            .expect("Could not parse QuotedString");
85        QuotedStringParser::parse(
86            Rule::quoted_string,
87            "\"\u{fc}\u{80}\u{81}\u{82}\u{83}\u{bf}\"",
88        )
89        .expect("Could not parse QuotedString");
90        QuotedStringParser::parse(
91            Rule::quoted_string,
92            "\"\u{fd}\u{80}\u{81}\u{82}\u{83}\u{bf}\"",
93        )
94        .expect("Could not parse QuotedString");
95
96        // quoted-pair
97        QuotedStringParser::parse(Rule::quoted_string, "\"\\\u{00}\"")
98            .expect("Could not parse QuotedString");
99        QuotedStringParser::parse(Rule::quoted_string, "\"\\\u{09}\"")
100            .expect("Could not parse QuotedString");
101        QuotedStringParser::parse(Rule::quoted_string, "\"\\\u{0b}\"")
102            .expect("Could not parse QuotedString");
103        QuotedStringParser::parse(Rule::quoted_string, "\"\\\u{0c}\"")
104            .expect("Could not parse QuotedString");
105        QuotedStringParser::parse(Rule::quoted_string, "\"\\\u{0e}\"")
106            .expect("Could not parse QuotedString");
107        QuotedStringParser::parse(Rule::quoted_string, "\"\\\u{7f}\"")
108            .expect("Could not parse QuotedString");
109
110        // quoted-string with series of qdtext and quoted-pair
111        QuotedStringParser::parse(Rule::quoted_string, "\"\\abcdfg\\h\"")
112            .expect("Could not parse QuotedString");
113        QuotedStringParser::parse(
114            Rule::quoted_string,
115            "\"\\abfg\\h\u{fd}\u{80}\u{81}\u{82}\u{83}\u{bf}\"",
116        )
117        .expect("Could not parse QuotedString");
118
119        // quoted string with CRLF and whitespaces
120        QuotedStringParser::parse(Rule::quoted_string, "\"hello world\"")
121            .expect("Could not parse QuotedString");
122        QuotedStringParser::parse(Rule::quoted_string, "\" \u{0d}\u{0a}   hello\"")
123            .expect("Could not parse QuotedString");
124    }
125
126    #[test]
127    fn invalid_quoted_string() {
128        // qdtext (miss one ut8 cont. character)
129        QuotedStringParser::parse(Rule::quoted_string, "\"\u{c0}\"")
130            .expect_err("Parse should have failed");
131        QuotedStringParser::parse(Rule::quoted_string, "\"\u{e0}\u{80}\"")
132            .expect_err("Parse should have failed");
133        QuotedStringParser::parse(Rule::quoted_string, "\"\u{f7}\u{80}\u{81}\"")
134            .expect_err("Parse should have failed");
135        QuotedStringParser::parse(Rule::quoted_string, "\"\u{f8}\u{80}\u{81}\u{82}\"")
136            .expect_err("Parse should have failed");
137        QuotedStringParser::parse(Rule::quoted_string, "\"\u{fd}\u{80}\u{81}\u{82}\u{83}\"")
138            .expect_err("Parse should have failed");
139
140        // qdtext (miss two ut8 cont. character)
141        QuotedStringParser::parse(Rule::quoted_string, "\"\u{e0}\"")
142            .expect_err("Parse should have failed");
143        QuotedStringParser::parse(Rule::quoted_string, "\"\u{f7}\u{80}\"")
144            .expect_err("Parse should have failed");
145        QuotedStringParser::parse(Rule::quoted_string, "\"\u{f8}\u{80}\u{81}\"")
146            .expect_err("Parse should have failed");
147        QuotedStringParser::parse(Rule::quoted_string, "\"\u{fd}\u{80}\u{81}\u{82}\"")
148            .expect_err("Parse should have failed");
149
150        // qdtext (miss three ut8 cont. character)
151        QuotedStringParser::parse(Rule::quoted_string, "\"\u{f7}\"")
152            .expect_err("Parse should have failed");
153        QuotedStringParser::parse(Rule::quoted_string, "\"\u{f8}\u{80}\"")
154            .expect_err("Parse should have failed");
155        QuotedStringParser::parse(Rule::quoted_string, "\"\u{fd}\u{80}\u{81}\"")
156            .expect_err("Parse should have failed");
157
158        // qdtext (miss four ut8 cont. character)
159        QuotedStringParser::parse(Rule::quoted_string, "\"\u{fb}\"")
160            .expect_err("Parse should have failed");
161        QuotedStringParser::parse(Rule::quoted_string, "\"\u{fd}\u{80}\"")
162            .expect_err("Parse should have failed");
163
164        // qdtext (miss five ut8 cont. character)
165        QuotedStringParser::parse(Rule::quoted_string, "\"\u{fd}\"")
166            .expect_err("Parse should have failed");
167
168        // invalid quoted-string
169        QuotedStringParser::parse(Rule::quoted_string, "\"\\\u{0a}\"")
170            .expect_err("Parse should have failed");
171        QuotedStringParser::parse(Rule::quoted_string, "\"\\\u{0d}\"")
172            .expect_err("Parse should have failed");
173        QuotedStringParser::parse(Rule::quoted_string, "\"\\\u{8a}\"")
174            .expect_err("Parse should have failed");
175
176        // lws failed with missinf LF character
177        QuotedStringParser::parse(Rule::quoted_string, "\" \u{0d} hello\"")
178            .expect_err("Parse should have failed");
179    }
180}