resp_protocol/bulk_string/
mod.rs

1use crate::RespError;
2use bytes::{BufMut, Bytes, BytesMut};
3
4pub const EMPTY_BULK_STRING: BulkString = BulkString(Bytes::from_static(b"$0\r\n\r\n"));
5pub const NULL_BULK_STRING: BulkString = BulkString(Bytes::from_static(b"$-1\r\n"));
6
7#[derive(Debug, Clone, PartialEq)]
8pub struct BulkString(Bytes);
9
10impl BulkString {
11    /// Build a new Bulk String
12    ///
13    /// ``` rust
14    /// use resp_protocol::BulkString;
15    ///
16    /// let bulk_string: BulkString = BulkString::new(b"foobar");
17    /// println!("{:?}", bulk_string); // BulkString(b"$6\r\nfoobar\r\n")
18    /// ```
19    pub fn new(input: &[u8]) -> Self {
20        let length = input.len();
21        if length == 0 {
22            return EMPTY_BULK_STRING;
23        }
24        let length_string = length.to_string();
25        let mut bytes = BytesMut::with_capacity(input.len() + length_string.len() + 5);
26        bytes.put_u8(0x24); // "$"
27        bytes.put_slice(length_string.as_bytes());
28        bytes.put_u8(0x0d); // CR
29        bytes.put_u8(0x0a); // LF
30        bytes.put_slice(input);
31        bytes.put_u8(0x0d); // CR
32        bytes.put_u8(0x0a); // LF
33        Self::from_bytes(bytes.freeze())
34    }
35
36    ///
37    ///
38    /// ``` rust
39    /// use resp_protocol::{BulkString, EMPTY_BULK_STRING};
40    ///
41    /// let bulk_string: BulkString = EMPTY_BULK_STRING;
42    /// println!("{:?}", bulk_string.is_empty()); // true
43    ///
44    /// ```
45    #[inline]
46    pub fn is_empty(&self) -> bool {
47        self == EMPTY_BULK_STRING
48    }
49
50    ///
51    ///
52    /// ``` rust
53    /// use resp_protocol::{BulkString, NULL_BULK_STRING};
54    ///
55    /// let bulk_string: BulkString = NULL_BULK_STRING;
56    /// println!("{:?}", bulk_string.is_null()); // true
57    ///
58    /// ```
59    #[inline]
60    pub fn is_null(&self) -> bool {
61        self == NULL_BULK_STRING
62    }
63
64    #[inline]
65    pub fn bytes(&self) -> Bytes {
66        self.0.clone()
67    }
68
69    #[inline]
70    pub fn len(&self) -> usize {
71        self.0.len()
72    }
73
74    #[inline]
75    pub fn from_bytes(input: Bytes) -> Self {
76        Self(input)
77    }
78
79    #[inline]
80    pub fn from_slice(input: &[u8]) -> Self {
81        let bytes = Bytes::copy_from_slice(input);
82        Self::from_bytes(bytes)
83    }
84
85    #[inline]
86    pub unsafe fn from_raw(ptr: *mut u8, length: usize) -> Self {
87        let vector = Vec::from_raw_parts(ptr, length, length);
88        let bytes = Bytes::from(vector);
89        Self::from_bytes(bytes)
90    }
91
92    pub fn while_valid(input: &[u8], start: &mut usize, end: &usize) -> Result<(), RespError> {
93        let mut index = *start;
94        if index + 4 >= *end {
95            return Err(RespError::InvalidValue);
96        }
97        if input[index] != 0x24 {
98            return Err(RespError::InvalidFirstChar);
99        }
100        index += 1;
101        if input[index] == 0x2d {
102            if input[index + 1] != 0x31 || input[index + 2] != 0x0d || input[index + 3] != 0x0a {
103                return Err(RespError::InvalidNullValue);
104            }
105            *start = index + 4;
106            return Ok(());
107        }
108        if input[index] == 0x30 && input[index + 1] >= 0x30 && input[index + 1] <= 0x39 {
109            return Err(RespError::InvalidLength);
110        }
111        while index < *end && input[index] >= 0x30 && input[index] <= 0x39 {
112            index += 1;
113        }
114        if index + 1 >= *end || input[index] != 0x0d || input[index + 1] != 0x0a {
115            return Err(RespError::InvalidLengthSeparator);
116        }
117        let length = unsafe {
118            String::from_utf8_unchecked(input[*start + 1..index].to_vec())
119                .parse::<usize>()
120                .unwrap()
121        };
122        index += 2;
123        let value_start_index = index;
124        while index < *end
125            && index - value_start_index <= length
126            && input[index] != 0x0d
127            && input[index] != 0x0a
128        {
129            index += 1;
130        }
131        if length != index - value_start_index {
132            return Err(RespError::LengthsNotMatch);
133        }
134        if index + 1 >= *end || input[index] != 0x0d || input[index + 1] != 0x0a {
135            return Err(RespError::InvalidTerminate);
136        }
137        *start = index + 2;
138        Ok(())
139    }
140
141    pub fn parse(input: &[u8], start: &mut usize, end: &usize) -> Result<Self, RespError> {
142        let mut index = *start;
143        Self::while_valid(input, &mut index, end)?;
144        let value = Self::from_slice(&input[*start..index]);
145        *start = index;
146        Ok(value)
147    }
148}
149
150impl<'a> PartialEq<BulkString> for &'a BulkString {
151    fn eq(&self, other: &BulkString) -> bool {
152        self.0 == other.bytes()
153    }
154    fn ne(&self, other: &BulkString) -> bool {
155        self.0 != other.bytes()
156    }
157}
158
159#[cfg(test)]
160mod tests_bulk_string {
161    use crate::{BulkString, EMPTY_BULK_STRING, NULL_BULK_STRING};
162    use bytes::Bytes;
163
164    #[test]
165    fn test_new() {
166        let bulk_string: BulkString = BulkString::new(b"foobar");
167        assert_eq!(bulk_string.bytes(), Bytes::from_static(b"$6\r\nfoobar\r\n"));
168    }
169
170    #[test]
171    fn test_new_empty() {
172        let bulk_string: BulkString = BulkString::new(b"");
173        assert_eq!(bulk_string.bytes(), Bytes::from_static(b"$0\r\n\r\n"));
174    }
175
176    #[test]
177    fn test_from_bytes() {
178        let bulk_string: BulkString =
179            BulkString::from_bytes(Bytes::from_static(b"$6\r\nfoobar\r\n"));
180        assert_eq!(bulk_string.bytes(), Bytes::from_static(b"$6\r\nfoobar\r\n"));
181    }
182
183    #[test]
184    fn test_from_slice() {
185        let bulk_string: BulkString =
186            BulkString::from_slice(Vec::from("$6\r\nfoobar\r\n").as_slice());
187        assert_eq!(bulk_string.bytes(), Bytes::from_static(b"$6\r\nfoobar\r\n"));
188    }
189
190    #[test]
191    fn test_is_empty() {
192        assert_eq!(EMPTY_BULK_STRING.is_empty(), true)
193    }
194
195    #[test]
196    fn test_is_null() {
197        assert_eq!(NULL_BULK_STRING.is_null(), true)
198    }
199
200    #[test]
201    fn test_parse() {
202        let string = "$6\r\nfoobar\r\n";
203        let mut cursor = 0;
204        assert_eq!(
205            BulkString::parse(string.as_bytes(), &mut cursor, &string.len()).unwrap(),
206            BulkString::new(b"foobar")
207        );
208        assert_eq!(cursor, 12);
209    }
210
211    #[test]
212    fn test_parse_empty() {
213        let string = "$0\r\n\r\n";
214        let mut cursor = 0;
215        assert_eq!(
216            BulkString::parse(string.as_bytes(), &mut cursor, &string.len()).unwrap(),
217            EMPTY_BULK_STRING
218        );
219        assert_eq!(cursor, 6);
220    }
221
222    #[test]
223    fn test_parse_null() {
224        let string = "$-1\r\n";
225        let mut cursor = 0;
226        assert_eq!(
227            BulkString::parse(string.as_bytes(), &mut cursor, &string.len()).unwrap(),
228            NULL_BULK_STRING
229        );
230        assert_eq!(cursor, 5);
231    }
232}