Skip to content

Commit cd776ce

Browse files
committed
Upgrade action impls to use new Array/Str types
1 parent 802ac4f commit cd776ce

File tree

4 files changed

+123
-16
lines changed

4 files changed

+123
-16
lines changed

src/actions.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
//!
3838
//! ```
3939
40+
use crate::types::Array;
4041
use crate::types::SnapshotResult;
42+
use crate::types::Str;
4143
use crate::Element;
4244
use crate::GetIterator;
4345
use crate::IntoSkyhashAction;
@@ -193,9 +195,10 @@ implement_actions!(
193195
///
194196
/// This returns a vector of [`Element`]s which either contain the values
195197
/// as strings or contains `Not Found (Code: 1)` response codes
196-
fn mget(keys: impl IntoSkyhashAction+ 's) -> Vec<Element> {
198+
fn mget(keys: impl IntoSkyhashAction+ 's) -> Array {
197199
{ Query::from("mget").arg(keys)}
198-
Response::Item(Element::Array(array)) => array
200+
Response::Item(Element::BinArray(brr)) => Array::Bin(brr),
201+
Response::Item(Element::StrArray(srr)) => Array::Str(srr)
199202
}
200203
/// Creates a snapshot
201204
///
@@ -247,9 +250,16 @@ implement_actions!(
247250
///
248251
/// This should return either the corresponding values of the provided keys or `Not Found`
249252
/// error codes
250-
fn pop(keys: impl IntoSkyhashAction + 's) -> Vec<Element> {
253+
fn pop(keys: impl IntoSkyhashBytes + 's) -> Str {
251254
{ Query::from("POP").arg(keys) }
252-
Response::Item(Element::Array(arr)) => arr
255+
Response::Item(Element::Str(st)) => Str::Unicode(st),
256+
Response::Item(Element::Binstr(bstr)) => Str::Binary(bstr)
257+
}
258+
/// Consumes the provided keys if they exist
259+
fn mpop(keys: impl IntoSkyhashAction + 's) -> Array {
260+
{ Query::from("mpop").arg(keys)}
261+
Response::Item(Element::BinArray(brr)) => Array::Bin(brr),
262+
Response::Item(Element::StrArray(srr)) => Array::Str(srr)
253263
}
254264
/// Deletes all the provided keys if they exist or doesn't do anything at all. This method
255265
/// will return true if all the provided keys were deleted, else it will return false

src/deserializer.rs

Lines changed: 89 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ pub enum Element {
7676
/// A response code
7777
RespCode(RespCode),
7878
/// An array of unicode strings
79-
StrArray(Vec<String>),
79+
StrArray(Vec<Option<String>>),
8080
/// An array of binary strings
81-
BinArray(Vec<Vec<u8>>),
81+
BinArray(Vec<Option<Vec<u8>>>),
8282
}
8383

8484
#[derive(Debug, PartialEq)]
@@ -298,10 +298,49 @@ impl<'a> Parser<'a> {
298298
Err(ParseError::UnexpectedByte)
299299
}
300300
}
301+
/// Parse the next null checked element
302+
fn parse_next_chunk_nullck(&mut self) -> ParseResult<Option<&[u8]>> {
303+
// we have the chunk
304+
let (start, stop) = self.read_line();
305+
if let Some(sizeline) = self.buffer.get(start..stop) {
306+
let string_size = Self::parse_into_usize_nullck(sizeline)?;
307+
if let Some(size) = string_size {
308+
// so it isn't null
309+
let our_chunk = self.read_until(size)?;
310+
Ok(Some(our_chunk))
311+
} else {
312+
Ok(None)
313+
}
314+
} else {
315+
Err(ParseError::NotEnough)
316+
}
317+
}
301318
/// The cursor should have passed the `+` tsymbol
302319
fn parse_next_string(&mut self) -> ParseResult<String> {
303320
Ok(String::from_utf8_lossy(&self.parse_next_binstr()?).to_string())
304321
}
322+
fn parse_next_binstr_nullck(&mut self) -> ParseResult<Option<Vec<u8>>> {
323+
let our_chunk = self.parse_next_chunk_nullck()?;
324+
if let Some(chunk) = our_chunk {
325+
let our_chunk = chunk.to_owned();
326+
if self.will_cursor_give_linefeed()? {
327+
// there is a lf after the end of the binary string; great!
328+
// let's skip that now
329+
self.incr_cursor();
330+
Ok(Some(our_chunk))
331+
} else {
332+
Err(ParseError::UnexpectedByte)
333+
}
334+
} else {
335+
Ok(None)
336+
}
337+
}
338+
fn parse_next_str_nullck(&mut self) -> ParseResult<Option<String>> {
339+
match self.parse_next_binstr_nullck()? {
340+
Some(chunk) => Ok(Some(String::from_utf8_lossy(&chunk).to_string())),
341+
None => Ok(None),
342+
}
343+
}
305344
/// The cursor should have passed the `:` tsymbol
306345
fn parse_next_u64(&mut self) -> ParseResult<u64> {
307346
let our_u64_chunk = self.__get_next_element()?;
@@ -362,31 +401,39 @@ impl<'a> Parser<'a> {
362401
Err(ParseError::NotEnough)
363402
}
364403
}
404+
/// Parse the next null checked usize
405+
fn parse_into_usize_nullck(inp: &[u8]) -> ParseResult<Option<usize>> {
406+
if inp == [0] {
407+
Ok(None)
408+
} else {
409+
Ok(Some(Self::parse_into_usize(inp)?))
410+
}
411+
}
365412
/// The cursor should have passed the `@+` chars
366-
fn parse_next_typed_array_str(&mut self) -> ParseResult<Vec<String>> {
413+
fn parse_next_typed_array_str(&mut self) -> ParseResult<Vec<Option<String>>> {
367414
let (start, stop) = self.read_line();
368415
if let Some(our_size_chunk) = self.buffer.get(start..stop) {
369416
// so we have a size chunk; let's get the size
370417
let array_size = Self::parse_into_usize(our_size_chunk)?;
371418
let mut array = Vec::with_capacity(array_size);
372419
for _ in 0..array_size {
373420
// no tsymbol, just elements and their sizes
374-
array.push(self.parse_next_string()?);
421+
array.push(self.parse_next_str_nullck()?);
375422
}
376423
Ok(array)
377424
} else {
378425
Err(ParseError::NotEnough)
379426
}
380427
}
381428
/// The cursor should have passed the `@?` chars
382-
fn parse_next_typed_array_bin(&mut self) -> ParseResult<Vec<Vec<u8>>> {
429+
fn parse_next_typed_array_bin(&mut self) -> ParseResult<Vec<Option<Vec<u8>>>> {
383430
let (start, stop) = self.read_line();
384431
if let Some(our_size_chunk) = self.buffer.get(start..stop) {
385432
// got size chunk, let's get the size
386433
let array_size = Self::parse_into_usize(our_size_chunk)?;
387434
let mut array = Vec::with_capacity(array_size);
388435
for _ in 0..array_size {
389-
array.push(self.parse_next_binstr()?);
436+
array.push(self.parse_next_binstr_nullck()?);
390437
}
391438
Ok(array)
392439
} else {
@@ -487,9 +534,9 @@ fn test_typed_str_array() {
487534
assert_eq!(
488535
parsed,
489536
RawResponse::SimpleQuery(Element::StrArray(vec![
490-
"the".to_owned(),
491-
"cat".to_owned(),
492-
"meowed".to_owned()
537+
Some("the".to_owned()),
538+
Some("cat".to_owned()),
539+
Some("meowed".to_owned())
493540
]))
494541
);
495542
}
@@ -502,9 +549,39 @@ fn test_typed_bin_array() {
502549
assert_eq!(
503550
parsed,
504551
RawResponse::SimpleQuery(Element::BinArray(vec![
505-
Vec::from("the"),
506-
Vec::from("cat"),
507-
Vec::from("meowed")
552+
Some(Vec::from("the")),
553+
Some(Vec::from("cat")),
554+
Some(Vec::from("meowed"))
555+
]))
556+
);
557+
}
558+
559+
#[test]
560+
fn test_typed_bin_array_null() {
561+
let typed_array_packet = "*1\n@?3\n3\nthe\n3\ncat\n\0\n".as_bytes();
562+
let (parsed, forward) = Parser::new(typed_array_packet).parse().unwrap();
563+
assert_eq!(forward, typed_array_packet.len());
564+
assert_eq!(
565+
parsed,
566+
RawResponse::SimpleQuery(Element::BinArray(vec![
567+
Some(Vec::from("the")),
568+
Some(Vec::from("cat")),
569+
None
570+
]))
571+
);
572+
}
573+
574+
#[test]
575+
fn test_typed_str_array_null() {
576+
let typed_array_packet = "*1\n@+3\n3\nthe\n3\ncat\n\0\n".as_bytes();
577+
let (parsed, forward) = Parser::new(typed_array_packet).parse().unwrap();
578+
assert_eq!(forward, typed_array_packet.len());
579+
assert_eq!(
580+
parsed,
581+
RawResponse::SimpleQuery(Element::StrArray(vec![
582+
Some("the".to_owned()),
583+
Some("cat".to_owned()),
584+
None
508585
]))
509586
);
510587
}

src/respcode.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ pub enum RespCode {
3939
OtherError,
4040
/// `7`: Wrongtype Error
4141
Wrongtype,
42+
/// `8`: Unknown Data Type Error
43+
UnknownDataType,
44+
/// `9`: Encoding error
45+
EncodingError,
4246
}
4347

4448
impl RespCode {
@@ -54,6 +58,8 @@ impl RespCode {
5458
5 => ServerError,
5559
6 => OtherError,
5660
7 => Wrongtype,
61+
8 => UnknownDataType,
62+
9 => EncodingError,
5763
_ => Self::ErrorString(st.to_owned()),
5864
},
5965
Err(_) => ErrorString(st.to_owned()),
@@ -73,6 +79,8 @@ impl From<RespCode> for u8 {
7379
ServerError => 5,
7480
OtherError | ErrorString(_) => 6,
7581
Wrongtype => 7,
82+
UnknownDataType => 8,
83+
EncodingError => 9,
7684
}
7785
}
7886
}

src/types.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,3 +270,15 @@ impl<T: IntoSkyhashBytes> GetIterator<T> for &Vec<T> {
270270
self.iter()
271271
}
272272
}
273+
274+
/// Array types
275+
pub enum Array {
276+
Bin(Vec<Option<Vec<u8>>>),
277+
Str(Vec<Option<String>>),
278+
}
279+
280+
/// String types
281+
pub enum Str {
282+
Unicode(String),
283+
Binary(Vec<u8>),
284+
}

0 commit comments

Comments
 (0)