Last active 2 months ago

parser.rs Raw
1use core::slice::Iter;
2use std::iter::Peekable;
3
4use anyhow::anyhow;
5
6use crate::tokenizer::Token;
7
8#[derive(Debug, Clone)]
9pub enum ParserValue {
10 SimpleString(String),
11 BulkString(String),
12 Array(Vec<ParserValue>),
13 NullBulkString,
14}
15
16impl ParserValue {
17 pub fn is_string(self: &ParserValue) -> bool {
18 matches!(self, ParserValue::SimpleString(_)) || matches!(self, ParserValue::BulkString(_))
19 }
20
21 pub fn is_array(self: &ParserValue) -> bool {
22 matches!(self, ParserValue::Array(_))
23 }
24
25 pub fn to_string(self: &ParserValue) -> Option<String> {
26 match self {
27 ParserValue::SimpleString(s) => Some(s.clone()),
28 ParserValue::BulkString(s) => Some(s.clone()),
29 _ => None,
30 }
31 }
32
33 pub fn to_vec(self: &ParserValue) -> Option<&Vec<ParserValue>> {
34 match self {
35 ParserValue::Array(arr) => Some(arr),
36 _ => None,
37 }
38 }
39
40 pub fn to_tokens(self: &ParserValue) -> Vec<Token> {
41 match self {
42 ParserValue::SimpleString(s) => {
43 vec![Token::Plus, Token::String(s.clone()), Token::Separator]
44 }
45 ParserValue::BulkString(s) => {
46 vec![
47 Token::Dollar,
48 Token::Number(s.len() as i64),
49 Token::Separator,
50 Token::String(s.clone()),
51 Token::Separator,
52 ]
53 }
54 ParserValue::Array(arr) => {
55 let mut tokens = vec![
56 Token::Asterisk,
57 Token::Number(arr.len() as i64),
58 Token::Separator,
59 ];
60 for parser_value in arr {
61 tokens.append(&mut parser_value.to_tokens());
62 }
63 tokens
64 }
65 ParserValue::NullBulkString => {
66 vec![Token::Dollar, Token::Number(-1), Token::Separator]
67 }
68 }
69 }
70}
71
72pub fn parse_tokens(tokens: &[Token]) -> Option<ParserValue> {
73 if tokens.is_empty() {
74 return None;
75 }
76
77 let mut tokens_iter = tokens.iter().peekable();
78 let first = tokens_iter.peek().expect("must have at least one token");
79
80 eprintln!("First Token {:?}", first);
81
82 match first {
83 // Simple String
84 Token::Plus => {
85 if let Ok(simple_string) = tokens_to_simple_string(&mut tokens_iter) {
86 return Some(simple_string);
87 }
88
89 None
90 }
91 // Bulk String
92 Token::Dollar => {
93 if let Ok(bulk_string) = tokens_to_bulk_string(&mut tokens_iter) {
94 return Some(bulk_string);
95 }
96
97 None
98 }
99 // Array
100 Token::Asterisk => match tokens_to_array(&mut tokens_iter) {
101 Ok(arr) => Some(arr),
102 Err(err) => {
103 eprintln!("{:?}", err);
104 None
105 }
106 },
107 _ => None,
108 }
109}
110
111fn tokens_to_simple_string(token_iter: &mut Peekable<Iter<Token>>) -> anyhow::Result<ParserValue> {
112 if !token_iter.next().is_some_and(|t| t.is_plus()) {
113 return Err(anyhow!("first token in simple string must be a plus"));
114 }
115 let str_token = token_iter
116 .next()
117 .expect("should have a second token for simple string");
118
119 let separator_token = token_iter
120 .next()
121 .expect("should have a third token for simple string");
122
123 if !separator_token.is_separator() {
124 return Err(anyhow!("third token in simple string must be a separator"));
125 }
126
127 Ok(ParserValue::SimpleString(str_token.to_string().expect(
128 "should be able to get strings from string tokens",
129 )))
130}
131
132fn tokens_to_bulk_string(token_iter: &mut Peekable<Iter<Token>>) -> anyhow::Result<ParserValue> {
133 if !token_iter.next().is_some_and(|t| t.is_dollar()) {
134 return Err(anyhow!("first token in bulk string must be a dollar sign"));
135 }
136 let size_token = token_iter
137 .next()
138 .expect("should have second token for bulk string");
139 if !size_token.is_number() {
140 return Err(anyhow!("second token in bulk string must be a number"));
141 }
142 let separator_token = token_iter
143 .next()
144 .expect("should have a third token for simple string");
145 if !separator_token.is_separator() {
146 return Err(anyhow!("third token in bulk string must be a separator"));
147 }
148 let mut str_tokens = Vec::new();
149 while token_iter.peek().is_some_and(|t| !t.is_separator()) {
150 let str_token = token_iter.next().expect("should str_token");
151 str_tokens.push(str_token);
152 }
153
154 let separator_token = token_iter
155 .next()
156 .expect("should have a fifth token for simple string");
157 if !separator_token.is_separator() {
158 return Err(anyhow!("fifth token in bulk string must be a separator"));
159 }
160 let mut s = String::with_capacity(size_token.to_usize().expect("size_token must be a usize"));
161 for t in str_tokens.iter() {
162 match t {
163 Token::Plus => {
164 s.push('+');
165 }
166 Token::Hyphen => {
167 s.push('-');
168 }
169 Token::Colon => {
170 s.push(':');
171 }
172 Token::Dollar => {
173 s.push('$');
174 }
175 Token::Asterisk => {
176 s.push('*');
177 }
178 Token::Underscore => {
179 s.push('_');
180 }
181 Token::PoundSign => {
182 s.push('#');
183 }
184 Token::Comma => {
185 s.push(',');
186 }
187 Token::LeftParenthesis => {
188 s.push('(');
189 }
190 Token::Exclamation => {
191 s.push('!');
192 }
193 Token::Equals => {
194 s.push('=');
195 }
196 Token::Percentage => {
197 s.push('%');
198 }
199 Token::Tilda => {
200 s.push('~');
201 }
202 Token::GreaterThan => {
203 s.push('>');
204 }
205 Token::String(ts) => s.push_str(ts),
206 Token::Number(n) => s.push_str(n.to_string().as_str()),
207 Token::Separator => {}
208 }
209 }
210 if s.len() != size_token.to_usize().expect("size_token must be a usize") {
211 return Err(anyhow!("incorrect string size in bulk token"));
212 }
213
214 Ok(ParserValue::BulkString(s))
215}
216
217fn tokens_to_array(token_iter: &mut Peekable<Iter<Token>>) -> anyhow::Result<ParserValue> {
218 if !token_iter.next().is_some_and(|t| t.is_asterisk()) {
219 return Err(anyhow!("first token in bulk string must be an asterisk"));
220 }
221 let length = token_iter.next().expect("should have a length token");
222 eprintln!("Length Token: {:?}", length);
223 if !length.is_number() {
224 return Err(anyhow!("second token in array should be length"));
225 }
226 let length = length.to_i64().expect("number token should have i64");
227 eprintln!("Length: {:?}", length);
228 if length < 0 {
229 return Err(anyhow!("array length cannot be negative"));
230 }
231
232 if length == 0 {
233 return Ok(ParserValue::Array(Vec::new()));
234 }
235
236 if !token_iter.next().is_some_and(|t| t.is_separator()) {
237 return Err(anyhow!("third token in an array must be a separator"));
238 }
239
240 let mut values: Vec<ParserValue> = Vec::with_capacity(length as usize);
241 for _ in 0..length {
242 let first = token_iter.peek().expect("should have next token in array");
243 eprintln!("First Array Token: {:?}", first);
244 match first {
245 Token::Plus => {
246 let simple_string = tokens_to_simple_string(token_iter);
247 if let Ok(simple_string) = simple_string {
248 values.push(simple_string);
249 } else {
250 return Err(simple_string.err().unwrap());
251 }
252 }
253 Token::Dollar => {
254 let bulk_string = tokens_to_bulk_string(token_iter);
255 if let Ok(bulk_string) = bulk_string {
256 values.push(bulk_string);
257 } else {
258 let err = bulk_string.err().unwrap();
259 eprintln!("{:?}", err);
260 return Err(err);
261 }
262 }
263 Token::Asterisk => {
264 let arr = tokens_to_array(token_iter);
265 if let Ok(arr) = arr {
266 values.push(arr);
267 } else {
268 return Err(arr.err().unwrap());
269 }
270 }
271 _ => return Err(anyhow!("unexpected starting token in array")),
272 }
273 }
274
275 Ok(ParserValue::Array(values))
276}
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281
282 #[test]
283 fn test_parses_bulk_string_with_negative_number() {
284 let tokens = [
285 Token::Dollar,
286 Token::Number(2),
287 Token::Separator,
288 Token::Hyphen,
289 Token::Number(1),
290 Token::Separator,
291 ];
292 let result = tokens_to_bulk_string(&mut tokens.iter().peekable());
293 assert!(result.is_ok());
294 assert_eq!(
295 ParserValue::BulkString("-1".to_string())
296 .to_string()
297 .unwrap(),
298 result.unwrap().to_string().unwrap()
299 );
300 }
301
302 #[test]
303 fn test_parses_bulk_string() {
304 let tokens = [
305 Token::Dollar,
306 Token::Number(5),
307 Token::Separator,
308 Token::String("PSYNC".to_string()),
309 Token::Separator,
310 ];
311
312 let result = tokens_to_bulk_string(&mut tokens.iter().peekable());
313 assert!(result.is_ok());
314 assert_eq!(
315 ParserValue::BulkString("PSYNC".to_string())
316 .to_string()
317 .unwrap(),
318 result.unwrap().to_string().unwrap()
319 );
320 }
321}
322