1
pub type GenericResponseResult<'a> = Result<GenericResponse<'a>, &'a str>;
2

            
3
pub type GenericResponse<'a> = HashMap<&'a str, GenericResponseValue<'a>>;
4

            
5
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6
pub enum GenericResponseValue<'a> {
7
    Text(&'a str),
8
    Binary(&'a [u8]),
9
    // Many(Vec<GenericResponseValue<'a>>),
10
}
11

            
12
#[derive(Debug, Clone)]
13
pub struct ResponseAttributes<'a> {
14
    bytestring: &'a [u8],
15
    cursor: usize,
16
}
17

            
18
impl<'a> ResponseAttributes<'a> {
19
13
    pub fn new(raw: &'a str) -> Self {
20
13
        Self::new_from_bytes(raw.as_bytes())
21
13
    }
22

            
23
14
    pub fn new_from_bytes(bytes: &'a [u8]) -> Self {
24
14
        Self {
25
14
            bytestring: bytes,
26
14
            cursor: 0,
27
14
        }
28
14
    }
29

            
30
    pub fn is_empty(&self) -> bool {
31
        self.cursor >= self.bytestring.len() || self.bytestring[self.cursor..].starts_with(b"OK")
32
    }
33

            
34
7
    pub fn into_map(
35
7
        self,
36
7
    ) -> Result<HashMap<&'a str, GenericResponseValue<'a>>, ResponseParserError<'a>> {
37
7
        self.into()
38
7
    }
39

            
40
7
    pub fn into_vec(
41
7
        self,
42
7
    ) -> Result<Vec<(&'a str, GenericResponseValue<'a>)>, ResponseParserError<'a>> {
43
7
        self.into()
44
7
    }
45

            
46
    pub fn into_lazy_vec(
47
        self,
48
    ) -> Vec<Result<(&'a str, GenericResponseValue<'a>), ResponseParserError<'a>>> {
49
        self.into()
50
    }
51

            
52
    pub fn verify_all_keys_equal(&self, expected_key: &str) -> Result<(), ResponseParserError<'a>> {
53
        let mut copy = self.clone();
54
        copy.cursor = 0;
55
        for item in copy {
56
            let (key, _) = item?;
57
            if key != expected_key {
58
                return Err(ResponseParserError::UnexpectedProperty(key));
59
            }
60
        }
61
        Ok(())
62
    }
63

            
64
    // pub fn get<'a>(&self, key: &str) -> Option<&GenericResponseValue<'a>> {
65
    //     self.0.iter().find_map(|(k, v)| if k == &key { Some(v) } else { None })
66
    // }
67
}
68

            
69
impl<'a> Iterator for ResponseAttributes<'a> {
70
    type Item = Result<(&'a str, GenericResponseValue<'a>), ResponseParserError<'a>>;
71

            
72
81
    fn next(&mut self) -> Option<Self::Item> {
73
81
        if self.cursor >= self.bytestring.len() {
74
1
            return Some(Err(ResponseParserError::UnexpectedEOF));
75
80
        }
76
80
        if self.bytestring[self.cursor..].starts_with(b"OK") {
77
13
            return None;
78
67
        }
79

            
80
67
        let remaining = &self.bytestring[self.cursor..];
81
67
        let newline_pos = remaining
82
67
            .iter()
83
1099
            .position(|&b| b == b'\n')
84
67
            .unwrap_or(remaining.len());
85
67
        let line = &remaining[..newline_pos];
86

            
87
        // Skip empty lines
88
67
        if line.is_empty() {
89
1
            self.cursor += newline_pos + 1;
90
1
            return self.next();
91
66
        }
92

            
93
        // NOTE: it is important that this happens before any None returns,
94
        //       so that the iterator advances despite errors.
95
66
        self.cursor += newline_pos + 1;
96

            
97
526
        let mut keyval = line.splitn(2, |&b| b == b':');
98
66
        let key_bytes = keyval.next()?;
99

            
100
        // TODO: should this be a proper runtime error?
101
66
        debug_assert!(!key_bytes.is_empty());
102
66
        debug_assert!(std::str::from_utf8(key_bytes).is_ok());
103
66
        let key = std::str::from_utf8(key_bytes).ok()?;
104

            
105
        // In the case of binary data, the following value will be the byte count
106
        // in decimal, and the actual binary data will follow in the next N bytes,
107
        // followed by a newline.
108
        //
109
        // We parse the number and assign the binary data to the "binary" key.
110
66
        if key == "binary" {
111
1
            let byte_count = match keyval.next() {
112
1
                Some(count) => count.trim_ascii_start(),
113
                None => {
114
                    // TODO: throw more specific error
115
                    return Some(Err(ResponseParserError::UnexpectedEOF));
116
                }
117
            };
118
1
            let byte_count_str = match std::str::from_utf8(byte_count) {
119
1
                Ok(s) => s,
120
                Err(_) => {
121
                    // TODO: throw more specific error
122
                    return Some(Err(ResponseParserError::SyntaxError(
123
                        0,
124
                        "Invalid byte count",
125
                    )));
126
                }
127
            };
128
1
            let byte_count: usize = match byte_count_str.parse() {
129
1
                Ok(n) => n,
130
                Err(_) => {
131
                    // TODO: throw more specific error
132
                    return Some(Err(ResponseParserError::SyntaxError(
133
                        0,
134
                        "Invalid byte count",
135
                    )));
136
                }
137
            };
138

            
139
1
            let value_start = self.cursor;
140
1
            let value_end = self.cursor + byte_count;
141
1
            if value_end > self.bytestring.len() {
142
                return Some(Err(ResponseParserError::UnexpectedEOF));
143
1
            }
144
1
            let value_bytes = &self.bytestring[value_start..value_end];
145

            
146
1
            debug_assert!(
147
                self.bytestring[value_end..]
148
                    .iter()
149
                    .next()
150
                    .is_none_or(|&b| b == b'\n')
151
            );
152

            
153
            // Skip the binary data and the following newline
154
1
            self.cursor = value_end + 1;
155

            
156
1
            Some(Ok((key, GenericResponseValue::Binary(value_bytes))))
157
        } else {
158
65
            let value_bytes = match keyval.next() {
159
65
                Some(v) => v.trim_ascii_start(),
160
                None => b"",
161
            };
162
            // TODO: this should be a proper runtime error, the specification
163
            //       declares that all string values are UTF-8.
164
65
            debug_assert!(std::str::from_utf8(value_bytes).is_ok());
165
65
            let value_str = std::str::from_utf8(value_bytes).ok()?;
166

            
167
65
            Some(Ok((key, GenericResponseValue::Text(value_str))))
168
        }
169
81
    }
170
}
171

            
172
impl<'a> From<ResponseAttributes<'a>>
173
    for Result<HashMap<&'a str, GenericResponseValue<'a>>, ResponseParserError<'a>>
174
{
175
7
    fn from(val: ResponseAttributes<'a>) -> Self {
176
7
        let mut map = HashMap::new();
177
28
        for item in val {
178
28
            let (k, v) = item?;
179
28
            if map.contains_key(k) {
180
                return Err(ResponseParserError::DuplicateProperty(k));
181
28
            }
182
28
            map.insert(k, v);
183
        }
184
7
        Ok(map)
185
7
    }
186
}
187

            
188
impl<'a> From<ResponseAttributes<'a>>
189
    for Vec<Result<(&'a str, GenericResponseValue<'a>), ResponseParserError<'a>>>
190
{
191
    fn from(val: ResponseAttributes<'a>) -> Self {
192
        val.collect()
193
    }
194
}
195

            
196
impl<'a> From<ResponseAttributes<'a>>
197
    for Result<Vec<(&'a str, GenericResponseValue<'a>)>, ResponseParserError<'a>>
198
{
199
7
    fn from(val: ResponseAttributes<'a>) -> Self {
200
7
        val.collect()
201
7
    }
202
}
203

            
204
// TODO: There should probably be a helper that lets you extract and verify one, two or maybe
205
//       three properties without having to allocate a hashmap to get a nice API. We can retrieve
206
//       the properties by name with a loop on the inner vec.
207

            
208
/*******************/
209
/* Parsing Helpers */
210
/*******************/
211

            
212
macro_rules! _expect_property_type {
213
    ($property:expr, $name:expr, $variant:ident) => {
214
        match $property {
215
            Some(crate::response_tokenizer::GenericResponseValue::$variant(value)) => Some(value),
216
            Some(value) => {
217
                let actual_type = match value {
218
                    crate::response_tokenizer::GenericResponseValue::Text(_) => "Text",
219
                    crate::response_tokenizer::GenericResponseValue::Binary(_) => "Binary",
220
                };
221
                return Err(
222
                    crate::commands::ResponseParserError::UnexpectedPropertyType(
223
                        $name,
224
                        actual_type,
225
                    ),
226
                );
227
            }
228
            None => None,
229
        }
230
    };
231
}
232

            
233
macro_rules! _parse_optional_property_type {
234
    ($name:expr, $property:expr) => {
235
        $property
236
14
            .map(|value| {
237
14
                value.parse().map_err(|_| {
238
                    crate::commands::ResponseParserError::InvalidProperty($name, value)
239
                })
240
14
            })
241
            .transpose()?
242
    };
243
}
244

            
245
macro_rules! _unwrap_optional_property_type {
246
    ($name:expr, $property:expr) => {
247
        match $property {
248
            Some(value) => value,
249
            None => return Err(crate::commands::ResponseParserError::MissingProperty($name)),
250
        }
251
    };
252
}
253

            
254
macro_rules! expect_optional_property_type {
255
    ($property:expr, $name:expr, $variant:ident) => {
256
        crate::response_tokenizer::_expect_property_type!($property, $name, $variant)
257
    };
258
}
259

            
260
macro_rules! expect_property_type {
261
    ($property:expr, $name:expr, $variant:ident) => {{
262
        let prop = crate::response_tokenizer::_expect_property_type!($property, $name, $variant);
263
        crate::response_tokenizer::_unwrap_optional_property_type!($name, prop)
264
    }};
265
}
266

            
267
macro_rules! get_optional_property {
268
    ($parts:expr, $name:literal, $variant:ident) => {
269
        crate::response_tokenizer::_expect_property_type!(
270
            { $parts.get($name).map(|v| *v) },
271
            $name,
272
            $variant
273
        )
274
    };
275
}
276

            
277
macro_rules! get_property {
278
    ($parts:expr, $name:literal, $variant:ident) => {{
279
        let prop = crate::response_tokenizer::_expect_property_type!(
280
            { $parts.get($name).map(|v| *v) },
281
            $name,
282
            $variant
283
        );
284
        crate::response_tokenizer::_unwrap_optional_property_type!($name, prop)
285
    }};
286
}
287

            
288
macro_rules! get_and_parse_optional_property {
289
    ($parts:ident, $name:literal, $variant:ident) => {{
290
        let prop = crate::response_tokenizer::_expect_property_type!(
291
            { $parts.get($name).map(|v| *v) },
292
            $name,
293
            $variant
294
        );
295
        crate::response_tokenizer::_parse_optional_property_type!($name, prop)
296
    }};
297
}
298

            
299
macro_rules! get_and_parse_property {
300
    ($parts:ident, $name:literal, $variant:ident) => {{
301
        let prop = crate::response_tokenizer::_expect_property_type!(
302
            { $parts.get($name).map(|v| *v) },
303
            $name,
304
            $variant
305
        );
306
        let prop = crate::response_tokenizer::_parse_optional_property_type!($name, prop);
307
        crate::response_tokenizer::_unwrap_optional_property_type!($name, prop)
308
    }};
309
}
310

            
311
macro_rules! get_next_optional_property {
312
    ($parts:ident, $variant:ident) => {
313
        match $parts.next() {
314
            Some((name, value)) => {
315
                crate::response_tokenizer::_expect_property_type!({ Some(value) }, name, $variant)
316
                    .map(|value| (name, value))
317
            }
318
            None => None,
319
        }
320
    };
321
}
322

            
323
macro_rules! get_next_property {
324
    ($parts:ident, $variant:ident) => {
325
        match $parts.next() {
326
            Some(Ok((name, value))) => (
327
                name,
328
                crate::response_tokenizer::_expect_property_type!({ Some(value) }, name, $variant)
329
                    .unwrap(),
330
            ),
331
            Some(Err(e)) => return Err(e),
332
            None => return Err(crate::commands::ResponseParserError::UnexpectedEOF),
333
        }
334
    };
335
}
336

            
337
macro_rules! get_next_and_parse_optional_property {
338
    ($parts:ident, $variant:ident) => {
339
        match $parts.next() {
340
            Some((name, value)) => {
341
                let prop = crate::response_tokenizer::_expect_property_type!(
342
                    { Some(value) },
343
                    name,
344
                    $variant
345
                );
346
                prop.map(|value| {
347
                    (
348
                        name,
349
                        crate::response_tokenizer::_parse_optional_property_type!(name, value),
350
                    )
351
                })
352
            }
353
            None => None,
354
        }
355
    };
356
}
357

            
358
macro_rules! get_next_and_parse_property {
359
    ($parts:ident, $variant:ident) => {
360
        match $parts.next() {
361
            Some(Ok((name, value))) => {
362
                let prop = crate::response_tokenizer::_expect_property_type!(
363
                    { Some(value) },
364
                    name,
365
                    $variant
366
                );
367
                let prop = crate::response_tokenizer::_parse_optional_property_type!(name, prop);
368
                (
369
                    name,
370
                    crate::response_tokenizer::_unwrap_optional_property_type!(name, prop),
371
                )
372
            }
373
            Some(Err(e)) => return Err(e),
374
            None => return Err(crate::commands::ResponseParserError::UnexpectedEOF),
375
        }
376
    };
377
}
378

            
379
use std::collections::HashMap;
380

            
381
pub(crate) use _expect_property_type;
382
pub(crate) use _parse_optional_property_type;
383
pub(crate) use _unwrap_optional_property_type;
384
pub(crate) use expect_property_type;
385
// pub(crate) use expect_optional_property_type;
386
pub(crate) use get_and_parse_optional_property;
387
pub(crate) use get_and_parse_property;
388
// pub(crate) use get_next_and_parse_optional_property;
389
pub(crate) use get_next_and_parse_property;
390
// pub(crate) use get_next_optional_property;
391
pub(crate) use get_next_property;
392
pub(crate) use get_optional_property;
393
pub(crate) use get_property;
394

            
395
use crate::commands::ResponseParserError;
396

            
397
#[cfg(test)]
398
mod tests {
399
    use indoc::indoc;
400

            
401
    use super::*;
402

            
403
    #[test]
404
    #[cfg(debug_assertions)]
405
    fn test_valid_hashmap_uniqueness_assert() -> Result<(), ResponseParserError<'static>> {
406
        let raw_response = indoc! {
407
            "a: 1
408
            A: 2
409
            A : 3
410
            b: 4
411
            OK"
412
        };
413
        let attrs = ResponseAttributes::new(raw_response);
414
        let map: HashMap<_, _> = attrs.into_map()?;
415
        assert_eq!(map.len(), 4);
416
        Ok(())
417
    }
418

            
419
    #[test]
420
    #[cfg(debug_assertions)]
421
    #[should_panic]
422
    fn test_invalid_hashmap_uniqueness_assert() {
423
        let raw_response = indoc! {
424
            "a: 1
425
            b: 2
426
            c: 3
427
            a: 4
428
            OK"
429
        };
430
        ResponseAttributes::new(raw_response).into_map().unwrap();
431
    }
432

            
433
    #[test]
434
1
    fn test_response_attributes_single_attribute() -> Result<(), ResponseParserError<'static>> {
435
1
        let raw_response = indoc! {
436
1
            "name: Sticker1
437
1
            OK"
438
        };
439
1
        let attrs = ResponseAttributes::new(raw_response);
440
1
        let map: HashMap<_, _> = attrs.into_map()?;
441
1
        assert_eq!(map.len(), 1);
442
1
        assert_eq!(
443
1
            map.get("name"),
444
            Some(&GenericResponseValue::Text("Sticker1"))
445
        );
446
1
        Ok(())
447
1
    }
448

            
449
    #[test]
450
1
    fn test_response_attributes_multiple_attributes() -> Result<(), ResponseParserError<'static>> {
451
1
        let raw_response = indoc! {
452
1
            "name: Sticker1
453
1
            type: emoji
454
1
            size: 128
455
1
            OK"
456
        };
457
1
        let attrs = ResponseAttributes::new(raw_response);
458
1
        let map: HashMap<_, _> = attrs.into_map()?;
459
1
        assert_eq!(map.len(), 3);
460
1
        assert_eq!(
461
1
            map.get("name"),
462
            Some(&GenericResponseValue::Text("Sticker1"))
463
        );
464
1
        assert_eq!(map.get("type"), Some(&GenericResponseValue::Text("emoji")));
465
1
        assert_eq!(map.get("size"), Some(&GenericResponseValue::Text("128")));
466
1
        Ok(())
467
1
    }
468

            
469
    #[test]
470
1
    fn test_response_attributes_empty_response() -> Result<(), ResponseParserError<'static>> {
471
1
        let raw_response = indoc! {
472
1
            "OK"
473
        };
474
1
        let attrs = ResponseAttributes::new(raw_response);
475
1
        let map: HashMap<_, _> = attrs.into_map()?;
476
1
        assert_eq!(map.len(), 0);
477
1
        Ok(())
478
1
    }
479

            
480
    #[test]
481
1
    fn test_response_attributes_unexpected_eof() -> Result<(), ResponseParserError<'static>> {
482
1
        let raw_response = indoc! {
483
1
            "name: Sticker1
484
1
            type: emoji"
485
        };
486
1
        let attrs = ResponseAttributes::new(raw_response);
487
1
        let vec: Result<Vec<_>, ResponseParserError> = attrs.into_vec();
488
1
        assert!(matches!(vec, Err(ResponseParserError::UnexpectedEOF)));
489
1
        Ok(())
490
1
    }
491

            
492
    #[test]
493
1
    fn test_response_attributes_repeated_attribute() -> Result<(), ResponseParserError<'static>> {
494
1
        let raw_response = indoc! {
495
1
            "name: Sticker1
496
1
            name: Sticker2
497
1
            OK"
498
        };
499
1
        let attrs = ResponseAttributes::new(raw_response);
500
1
        let vec = attrs.into_vec()?;
501
1
        assert_eq!(vec.len(), 2);
502
1
        assert_eq!(vec[0], ("name", GenericResponseValue::Text("Sticker1")));
503
1
        assert_eq!(vec[1], ("name", GenericResponseValue::Text("Sticker2")));
504
1
        Ok(())
505
1
    }
506

            
507
    #[test]
508
1
    fn test_response_attributes_empty_line() -> Result<(), ResponseParserError<'static>> {
509
1
        let raw_response = indoc! {
510
1
            "name: Sticker1
511
1

            
512
1
            type: emoji
513
1
            OK"
514
        };
515
1
        let attrs = ResponseAttributes::new(raw_response);
516
1
        let map: HashMap<_, _> = attrs.into_map()?;
517
1
        assert_eq!(map.len(), 2);
518
1
        assert_eq!(
519
1
            map.get("name"),
520
            Some(&GenericResponseValue::Text("Sticker1"))
521
        );
522
1
        assert_eq!(map.get("type"), Some(&GenericResponseValue::Text("emoji")));
523
1
        Ok(())
524
1
    }
525

            
526
    #[test]
527
1
    fn test_response_attributes_no_value() -> Result<(), ResponseParserError<'static>> {
528
1
        let raw_response = indoc! {
529
1
            "name:
530
1
            type: emoji
531
1
            OK"
532
        };
533
1
        let attrs = ResponseAttributes::new(raw_response);
534
1
        let map: HashMap<_, _> = attrs.into_map()?;
535
1
        assert_eq!(map.len(), 2);
536
1
        assert_eq!(map.get("name"), Some(&GenericResponseValue::Text("")));
537
1
        assert_eq!(map.get("type"), Some(&GenericResponseValue::Text("emoji")));
538
1
        Ok(())
539
1
    }
540

            
541
    #[test]
542
1
    fn test_response_attributes_binary_data() -> Result<(), ResponseParserError<'static>> {
543
1
        let bytestring: &[u8] = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09";
544
1
        let raw_response = {
545
1
            let mut response = format!("binary: {}\n", bytestring.len()).into_bytes();
546
1
            response.extend_from_slice(bytestring);
547
1
            response.extend_from_slice(b"\nOK");
548
1
            response
549
        };
550

            
551
1
        let attrs = ResponseAttributes::new_from_bytes(&raw_response);
552
1
        let map: HashMap<_, _> = attrs.into_map().unwrap();
553
1
        assert_eq!(map.len(), 1);
554
1
        assert_eq!(
555
1
            map.get("binary"),
556
1
            Some(&GenericResponseValue::Binary(bytestring))
557
        );
558
1
        Ok(())
559
1
    }
560
}