Skip to content

Commit

Permalink
feature: support NullBulkString and NullArray
Browse files Browse the repository at this point in the history
  • Loading branch information
luffy2025 committed Dec 2, 2024
1 parent 38e5e07 commit 6629130
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
34 changes: 32 additions & 2 deletions src/resp/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@ use crate::{
extract_end_and_length, is_combine_complete, RespDecode, RespEncode, RespError, RespFrame,
};
use bytes::Buf;
use lazy_static::lazy_static;
use std::ops::{Deref, DerefMut};

const NULL_ARRAY_ENCODE: &[u8] = b"*-1\r\n";
const ARRAY_CAP: usize = 4096;

lazy_static! {
static ref NULL_ARRAY: RespArray = RespArray::null();
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct RespArray {
pub(crate) data: Vec<RespFrame>,
}

const ARRAY_CAP: usize = 4096;

// - array: "*<number-of-elements>\r\n<element-1>...<element-n>"
// - "*2\r\n$3\r\nget\r\n$5\r\nhello\r\n"
impl RespEncode for RespArray {
fn encode(&self) -> Vec<u8> {
if self.is_empty() {
return NULL_ARRAY_ENCODE.to_vec();
}

let mut buf = Vec::with_capacity(ARRAY_CAP);
buf.extend_from_slice(format!("*{}\r\n", self.len()).as_bytes());
for frame in &self.data {
Expand All @@ -27,6 +37,10 @@ impl RespEncode for RespArray {
impl RespDecode for RespArray {
const PREFIX: &'static u8 = &b'*';
fn decode(buf: &mut bytes::BytesMut) -> Result<Self, RespError> {
if buf == NULL_ARRAY_ENCODE {
return Ok(NULL_ARRAY.clone());
}

let (end, len) = extract_end_and_length(buf, &[*Self::PREFIX])?;
is_combine_complete(buf, len)?;

Expand Down Expand Up @@ -72,6 +86,10 @@ impl RespArray {
RespArray { data: arr }
}

pub fn null() -> RespArray {
RespArray { data: vec![] }
}

pub fn push(&mut self, frame: RespFrame) {
self.data.push(frame);
}
Expand Down Expand Up @@ -135,4 +153,16 @@ mod tests {
);
Ok(())
}

#[test]
fn test_resp_array_null() -> Result<()> {
let arr = NULL_ARRAY.clone();
assert_eq!(arr.encode(), b"*-1\r\n");

let mut buf = bytes::BytesMut::from(&b"*-1\r\n"[..]);
let ret = RespArray::decode(&mut buf)?;
assert_eq!(ret, NULL_ARRAY.clone());

Ok(())
}
}
27 changes: 27 additions & 0 deletions src/resp/bulk_string.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
use crate::{extract_end_and_length, is_single_complete, RespDecode, RespEncode, RespError};
use bytes::{Buf, BytesMut};
use lazy_static::lazy_static;
use std::ops::Deref;

const NULL_BULK_STRING_ENCODE: &[u8] = b"$-1\r\n";

lazy_static! {
static ref NULL_BULK_STRING: BulkString = BulkString::from(NULL_BULK_STRING_ENCODE);
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct BulkString(Vec<u8>);

// - bulk string: "$<length>\r\n<data>\r\n"
impl RespEncode for BulkString {
fn encode(&self) -> Vec<u8> {
if self.to_vec() == NULL_BULK_STRING_ENCODE {
return NULL_BULK_STRING_ENCODE.to_vec();
}

let length = self.len();
let mut buf = Vec::with_capacity(1 + 2 + 1 + 1 + 1 + length + 2);
buf.push(*Self::PREFIX);
Expand All @@ -21,6 +32,10 @@ impl RespEncode for BulkString {
impl RespDecode for BulkString {
const PREFIX: &'static u8 = &b'$';
fn decode(buf: &mut BytesMut) -> Result<Self, RespError> {
if buf.to_vec() == NULL_BULK_STRING_ENCODE {
return Ok(NULL_BULK_STRING.clone());
}

let (end, len) = extract_end_and_length(buf, &[*Self::PREFIX])?;
is_single_complete(buf, len)?;

Expand Down Expand Up @@ -93,4 +108,16 @@ mod tests {
assert_eq!(bs, b"hello".into());
Ok(())
}

#[test]
fn test_bulk_string_null_encode() -> Result<()> {
let bs: BulkString = NULL_BULK_STRING.clone();
assert_eq!(bs.encode(), b"$-1\r\n");

let mut buf = BytesMut::from(NULL_BULK_STRING_ENCODE);
let frame = BulkString::decode(&mut buf)?;
assert_eq!(frame, bs);

Ok(())
}
}

0 comments on commit 6629130

Please sign in to comment.