Skip to content

Commit 7298a52

Browse files
committed
Support non-null non-recursive typed arrays
1 parent 5805896 commit 7298a52

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

src/deserializer.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,26 @@ impl<'a> Parser<'a> {
403403
b'&' => Element::Array(Array::Recursive(self.parse_next_array()?)),
404404
b'!' => Element::RespCode(self.parse_next_respcode()?),
405405
b'%' => Element::Float(self.parse_next_float()?),
406+
b'^' => {
407+
// hmm, a typed non-null array; let's check the tsymbol
408+
if let Some(array_type) = self.buffer.get(self.cursor) {
409+
// got tsymbol, let's skip it
410+
self.incr_cursor();
411+
match array_type {
412+
b'+' => {
413+
Element::Array(Array::NonNullStr(self.parse_next_nonnull_str()?))
414+
}
415+
b'?' => {
416+
Element::Array(Array::NonNullBin(self.parse_next_nonnull_bin()?))
417+
}
418+
_ => return Err(ParseError::UnknownDatatype),
419+
}
420+
} else {
421+
// if we couldn't fetch a tsymbol, there wasn't enough
422+
// data left
423+
return Err(ParseError::NotEnough);
424+
}
425+
}
406426
b'@' => {
407427
// hmmm, a typed array; let's check the tsymbol
408428
if let Some(array_type) = self.buffer.get(self.cursor) {
@@ -436,6 +456,24 @@ impl<'a> Parser<'a> {
436456
Ok(Some(Self::parse_into_usize(inp)?))
437457
}
438458
}
459+
460+
/// The cursor should have passed the `@+` chars
461+
fn parse_next_nonnull_str(&mut self) -> ParseResult<Vec<String>> {
462+
let (start, stop) = self.read_line();
463+
if let Some(our_size_chunk) = self.buffer.get(start..stop) {
464+
// so we have a size chunk; let's get the size
465+
let array_size = Self::parse_into_usize(our_size_chunk)?;
466+
let mut array = Vec::with_capacity(array_size);
467+
for _ in 0..array_size {
468+
// no tsymbol, just elements and their sizes
469+
array.push(self.parse_next_string()?);
470+
}
471+
Ok(array)
472+
} else {
473+
Err(ParseError::NotEnough)
474+
}
475+
}
476+
439477
/// The cursor should have passed the `@+` chars
440478
fn parse_next_typed_array_str(&mut self) -> ParseResult<Vec<Option<String>>> {
441479
let (start, stop) = self.read_line();
@@ -467,6 +505,24 @@ impl<'a> Parser<'a> {
467505
Err(ParseError::NotEnough)
468506
}
469507
}
508+
509+
/// The cursor should have passed the `@+` chars
510+
fn parse_next_nonnull_bin(&mut self) -> ParseResult<Vec<Vec<u8>>> {
511+
let (start, stop) = self.read_line();
512+
if let Some(our_size_chunk) = self.buffer.get(start..stop) {
513+
// so we have a size chunk; let's get the size
514+
let array_size = Self::parse_into_usize(our_size_chunk)?;
515+
let mut array = Vec::with_capacity(array_size);
516+
for _ in 0..array_size {
517+
// no tsymbol, just elements and their sizes
518+
array.push(self.parse_next_binstr()?);
519+
}
520+
Ok(array)
521+
} else {
522+
Err(ParseError::NotEnough)
523+
}
524+
}
525+
470526
/// The cursor should have passed the tsymbol
471527
fn parse_next_flat_array(&mut self) -> ParseResult<Vec<FlatElement>> {
472528
let (start, stop) = self.read_line();
@@ -623,3 +679,31 @@ fn test_parse_float() {
623679
assert_eq!(forward, packet.len());
624680
assert_eq!(parsed, RawResponse::SimpleQuery(Element::Float(1.1)))
625681
}
682+
683+
#[test]
684+
fn test_parse_nonnull_str() {
685+
let packet = b"*1\n^+2\n2\nhi\n5\nthere\n";
686+
let (parsed, forward) = Parser::new(packet).parse().unwrap();
687+
assert_eq!(forward, packet.len());
688+
assert_eq!(
689+
parsed,
690+
RawResponse::SimpleQuery(Element::Array(Array::NonNullStr(vec![
691+
"hi".to_owned(),
692+
"there".to_owned()
693+
])))
694+
)
695+
}
696+
697+
#[test]
698+
fn test_parse_nonnull_bin() {
699+
let packet = b"*1\n^?2\n2\nhi\n5\nthere\n";
700+
let (parsed, forward) = Parser::new(packet).parse().unwrap();
701+
assert_eq!(forward, packet.len());
702+
assert_eq!(
703+
parsed,
704+
RawResponse::SimpleQuery(Element::Array(Array::NonNullBin(vec![
705+
"hi".as_bytes().to_owned(),
706+
"there".as_bytes().to_owned()
707+
])))
708+
)
709+
}

src/types.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,14 @@ impl<T: IntoSkyhashBytes> GetIterator<T> for Vec<T> {
286286
#[derive(Debug, PartialEq)]
287287
#[non_exhaustive]
288288
pub enum Array {
289-
/// A binary array (typed array tsymbol `?`, `@` base tsymbol)
289+
/// A binary array with nullable elements(typed array tsymbol `?`, `@` base tsymbol)
290290
Bin(Vec<Option<Vec<u8>>>),
291-
/// An unicode string array (typed array tsymbol `+`, `@` base tsymbol)
291+
/// A non-null binary array
292+
NonNullBin(Vec<Vec<u8>>),
293+
/// An unicode string array with nullable elements (typed array tsymbol `+`, `@` base tsymbol)
292294
Str(Vec<Option<String>>),
295+
/// A non-null string array
296+
NonNullStr(Vec<String>),
293297
/// A non-recursive 'flat' array (tsymbol `_`)
294298
Flat(Vec<FlatElement>),
295299
/// A recursive array (tsymbol `&`)

0 commit comments

Comments
 (0)