1#![allow(unused_variables)]
7#![allow(dead_code)]
8#![allow(missing_docs)]
9
10use crate::core::{
11 error::{RedisError, RedisResult},
12 value::RespValue,
13};
14use bytes::{Buf, BufMut, Bytes, BytesMut};
15use std::io::Cursor;
16
17const CRLF: &[u8] = b"\r\n";
18
19const OK_RESPONSE: &str = "OK";
21const PONG_RESPONSE: &str = "PONG";
22const QUEUED_RESPONSE: &str = "QUEUED";
23
24pub struct OptimizedRespEncoder {
26 buffer: BytesMut,
28}
29
30impl OptimizedRespEncoder {
31 pub fn new() -> Self {
33 Self {
34 buffer: BytesMut::with_capacity(1024), }
36 }
37
38 pub fn with_capacity(capacity: usize) -> Self {
40 Self {
41 buffer: BytesMut::with_capacity(capacity),
42 }
43 }
44
45 fn estimate_size(value: &RespValue) -> usize {
47 match value {
48 RespValue::SimpleString(s) => 1 + s.len() + 2, RespValue::Error(e) => 1 + e.len() + 2, RespValue::Integer(i) => 1 + i.to_string().len() + 2, RespValue::BulkString(b) => {
52 let len_str = b.len().to_string();
53 1 + len_str.len() + 2 + b.len() + 2 }
55 RespValue::Null => 5, RespValue::Array(arr) => {
57 let len_str = arr.len().to_string();
58 let mut size = 1 + len_str.len() + 2; for item in arr {
60 size += Self::estimate_size(item);
61 }
62 size
63 }
64 }
65 }
66
67 fn estimate_bulk_argument_size(data_len: usize) -> usize {
68 1 + data_len.to_string().len() + 2 + data_len + 2
69 }
70
71 fn estimate_command_arg_size(value: &RespValue) -> usize {
72 match value {
73 RespValue::SimpleString(s) | RespValue::Error(s) => {
74 Self::estimate_bulk_argument_size(s.len())
75 }
76 RespValue::Integer(i) => Self::estimate_bulk_argument_size(i.to_string().len()),
77 RespValue::BulkString(b) => Self::estimate_bulk_argument_size(b.len()),
78 RespValue::Null => 5,
79 RespValue::Array(_) => Self::estimate_size(value),
80 }
81 }
82
83 fn estimate_command_size(command: &str, args: &[RespValue]) -> usize {
85 let total_items = 1 + args.len();
86 let array_header = 1 + total_items.to_string().len() + 2; let cmd_size = 1 + command.len().to_string().len() + 2 + command.len() + 2; let args_size: usize = args.iter().map(Self::estimate_command_arg_size).sum();
93
94 array_header + cmd_size + args_size
95 }
96
97 pub fn encode(&mut self, value: &RespValue) -> RedisResult<Bytes> {
99 let estimated_size = Self::estimate_size(value);
100
101 if self.buffer.capacity() < estimated_size {
103 self.buffer.reserve(estimated_size);
104 }
105
106 self.buffer.clear();
107 self.encode_value(value)?;
108 Ok(self.buffer.split().freeze())
109 }
110
111 pub fn encode_command(&mut self, command: &str, args: &[RespValue]) -> RedisResult<Bytes> {
113 let estimated_size = Self::estimate_command_size(command, args);
114
115 if self.buffer.capacity() < estimated_size {
117 self.buffer.reserve(estimated_size);
118 }
119
120 self.buffer.clear();
121
122 let total_len = 1 + args.len();
124 self.buffer.put_u8(b'*');
125 self.put_integer_bytes(total_len);
126 self.buffer.put_slice(CRLF);
127
128 self.buffer.put_u8(b'$');
130 self.put_integer_bytes(command.len());
131 self.buffer.put_slice(CRLF);
132 self.buffer.put_slice(command.as_bytes());
133 self.buffer.put_slice(CRLF);
134
135 for arg in args {
137 self.encode_command_arg(arg)?;
138 }
139
140 Ok(self.buffer.split().freeze())
141 }
142
143 fn encode_bulk_argument(&mut self, data: &[u8]) {
144 self.buffer.put_u8(b'$');
145 self.put_integer_bytes(data.len());
146 self.buffer.put_slice(CRLF);
147 self.buffer.put_slice(data);
148 self.buffer.put_slice(CRLF);
149 }
150
151 fn encode_command_arg(&mut self, value: &RespValue) -> RedisResult<()> {
152 match value {
153 RespValue::SimpleString(s) | RespValue::Error(s) => {
154 self.encode_bulk_argument(s.as_bytes());
155 }
156 RespValue::Integer(i) => {
157 self.encode_bulk_argument(i.to_string().as_bytes());
158 }
159 RespValue::BulkString(data) => {
160 self.encode_bulk_argument(data);
161 }
162 RespValue::Null => {
163 self.buffer.put_slice(b"$-1\r\n");
164 }
165 RespValue::Array(_) => {
166 self.encode_value(value)?;
167 }
168 }
169 Ok(())
170 }
171
172 fn encode_value(&mut self, value: &RespValue) -> RedisResult<()> {
174 match value {
175 RespValue::SimpleString(s) => {
176 self.buffer.put_u8(b'+');
177 self.buffer.put_slice(s.as_bytes());
179 self.buffer.put_slice(CRLF);
180 }
181 RespValue::Error(e) => {
182 self.buffer.put_u8(b'-');
183 self.buffer.put_slice(e.as_bytes());
184 self.buffer.put_slice(CRLF);
185 }
186 RespValue::Integer(i) => {
187 self.buffer.put_u8(b':');
188 self.put_integer_bytes(*i);
189 self.buffer.put_slice(CRLF);
190 }
191 RespValue::BulkString(data) => {
192 self.buffer.put_u8(b'$');
193 self.put_integer_bytes(data.len());
194 self.buffer.put_slice(CRLF);
195 self.buffer.put_slice(data);
196 self.buffer.put_slice(CRLF);
197 }
198 RespValue::Null => {
199 self.buffer.put_slice(b"$-1\r\n");
200 }
201 RespValue::Array(arr) => {
202 self.buffer.put_u8(b'*');
203 self.put_integer_bytes(arr.len());
204 self.buffer.put_slice(CRLF);
205 for item in arr {
206 self.encode_value(item)?;
207 }
208 }
209 }
210 Ok(())
211 }
212
213 fn put_integer_bytes<T: itoa::Integer>(&mut self, value: T) {
215 let mut buffer = itoa::Buffer::new();
216 let s = buffer.format(value);
217 self.buffer.put_slice(s.as_bytes());
218 }
219
220 pub fn capacity(&self) -> usize {
222 self.buffer.capacity()
223 }
224
225 pub fn clear(&mut self) {
227 self.buffer.clear();
228 }
229
230 pub fn reserve(&mut self, additional: usize) {
232 self.buffer.reserve(additional);
233 }
234}
235
236impl Default for OptimizedRespEncoder {
237 fn default() -> Self {
238 Self::new()
239 }
240}
241
242pub struct OptimizedRespDecoder {
244 buffer: BytesMut,
245 string_cache: std::collections::HashMap<Vec<u8>, String>,
247 max_cache_size: usize,
248}
249
250impl OptimizedRespDecoder {
251 pub fn new() -> Self {
253 Self {
254 buffer: BytesMut::with_capacity(4096),
255 string_cache: std::collections::HashMap::new(),
256 max_cache_size: 1000, }
258 }
259
260 pub fn with_config(buffer_capacity: usize, max_cache_size: usize) -> Self {
262 Self {
263 buffer: BytesMut::with_capacity(buffer_capacity),
264 string_cache: std::collections::HashMap::new(),
265 max_cache_size,
266 }
267 }
268
269 pub fn decode_streaming(&mut self, data: &[u8]) -> RedisResult<Vec<RespValue>> {
271 self.buffer.extend_from_slice(data);
272 let mut results = Vec::new();
273
274 loop {
275 let buffer_len = self.buffer.len();
276 if buffer_len == 0 {
277 break;
278 }
279
280 let buffer_slice = self.buffer.clone().freeze();
281 let mut cursor = Cursor::new(&buffer_slice[..]);
282
283 match self.try_decode_value(&mut cursor)? {
284 Some(value) => {
285 let consumed = cursor.position() as usize;
286 self.buffer.advance(consumed);
287 results.push(value);
288 }
289 None => break, }
291 }
292
293 Ok(results)
294 }
295
296 fn try_decode_value(&mut self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Option<RespValue>> {
298 if !cursor.has_remaining() {
299 return Ok(None);
300 }
301
302 let type_byte = cursor.chunk()[0];
303 cursor.advance(1);
304
305 match type_byte {
306 b'+' => self.try_decode_simple_string(cursor),
307 b'-' => self.try_decode_error(cursor),
308 b':' => self.try_decode_integer(cursor),
309 b'$' => self.try_decode_bulk_string(cursor),
310 b'*' => self.try_decode_array(cursor),
311 _ => Err(RedisError::Protocol(format!(
312 "Invalid RESP type byte: {}",
313 type_byte as char
314 ))),
315 }
316 }
317
318 fn try_decode_simple_string(
320 &mut self,
321 cursor: &mut Cursor<&[u8]>,
322 ) -> RedisResult<Option<RespValue>> {
323 if let Some(line) = self.try_read_line(cursor)? {
324 let string = self.bytes_to_string_cached(&line)?;
325 Ok(Some(RespValue::SimpleString(string)))
326 } else {
327 Ok(None)
328 }
329 }
330
331 fn try_decode_error(&mut self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Option<RespValue>> {
333 if let Some(line) = self.try_read_line(cursor)? {
334 let string = String::from_utf8(line)
335 .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8 in error: {e}")))?;
336 Ok(Some(RespValue::Error(string)))
337 } else {
338 Ok(None)
339 }
340 }
341
342 fn try_decode_integer(&mut self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Option<RespValue>> {
344 if let Some(line) = self.try_read_line(cursor)? {
345 let s = String::from_utf8(line)
346 .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8 in integer: {e}")))?;
347 let num = s
348 .parse::<i64>()
349 .map_err(|e| RedisError::Protocol(format!("Invalid integer format: {e}")))?;
350 Ok(Some(RespValue::Integer(num)))
351 } else {
352 Ok(None)
353 }
354 }
355
356 fn try_decode_bulk_string(
358 &mut self,
359 cursor: &mut Cursor<&[u8]>,
360 ) -> RedisResult<Option<RespValue>> {
361 let len_line = match self.try_read_line(cursor)? {
362 Some(line) => line,
363 None => return Ok(None),
364 };
365
366 let len_str = String::from_utf8(len_line).map_err(|e| {
367 RedisError::Protocol(format!("Invalid UTF-8 in bulk string length: {e}"))
368 })?;
369 let len = len_str
370 .parse::<isize>()
371 .map_err(|e| RedisError::Protocol(format!("Invalid bulk string length: {e}")))?;
372
373 if len == -1 {
374 return Ok(Some(RespValue::Null));
375 }
376
377 if len < 0 {
378 return Err(RedisError::Protocol(
379 "Invalid bulk string length".to_string(),
380 ));
381 }
382
383 let len = len as usize;
384 if cursor.remaining() < len + 2 {
385 return Ok(None); }
387
388 let data = cursor.chunk()[..len].to_vec();
389 cursor.advance(len);
390
391 if cursor.remaining() < 2 || &cursor.chunk()[..2] != CRLF {
393 return Err(RedisError::Protocol(
394 "Missing CRLF after bulk string".to_string(),
395 ));
396 }
397 cursor.advance(2);
398
399 Ok(Some(RespValue::BulkString(Bytes::from(data))))
400 }
401
402 fn try_decode_array(&mut self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Option<RespValue>> {
404 let len_line = match self.try_read_line(cursor)? {
405 Some(line) => line,
406 None => return Ok(None),
407 };
408
409 let len_str = String::from_utf8(len_line)
410 .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8 in array length: {e}")))?;
411 let len = len_str
412 .parse::<isize>()
413 .map_err(|e| RedisError::Protocol(format!("Invalid array length: {e}")))?;
414
415 if len == -1 {
416 return Ok(Some(RespValue::Null));
417 }
418
419 if len < 0 {
420 return Err(RedisError::Protocol("Invalid array length".to_string()));
421 }
422
423 let len = len as usize;
424 let mut elements = Vec::with_capacity(len);
425
426 for _ in 0..len {
427 match self.try_decode_value(cursor)? {
428 Some(element) => elements.push(element),
429 None => return Ok(None), }
431 }
432
433 Ok(Some(RespValue::Array(elements)))
434 }
435
436 fn try_read_line(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Option<Vec<u8>>> {
438 let start_pos = cursor.position() as usize;
439 let remaining = cursor.get_ref();
440
441 for (i, window) in remaining[start_pos..].windows(2).enumerate() {
443 if window == CRLF {
444 let line_end = start_pos + i;
445 let line = remaining[start_pos..line_end].to_vec();
446 cursor.advance(i + 2); return Ok(Some(line));
448 }
449 }
450
451 Ok(None) }
453
454 fn bytes_to_string_cached(&mut self, bytes: &[u8]) -> RedisResult<String> {
456 if let Some(cached) = self.string_cache.get(bytes) {
458 return Ok(cached.clone());
459 }
460
461 let string = String::from_utf8(bytes.to_vec())
462 .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8: {e}")))?;
463
464 if self.string_cache.len() < self.max_cache_size {
466 self.string_cache.insert(bytes.to_vec(), string.clone());
467 }
468
469 Ok(string)
470 }
471
472 pub fn clear_cache(&mut self) {
474 self.string_cache.clear();
475 }
476
477 pub fn cache_stats(&self) -> (usize, usize) {
479 (self.string_cache.len(), self.max_cache_size)
480 }
481}
482
483impl Default for OptimizedRespDecoder {
484 fn default() -> Self {
485 Self::new()
486 }
487}
488
489#[cfg(test)]
490mod tests {
491 use super::*;
492
493 #[test]
494 fn test_optimized_encoder_simple_string() {
495 let mut encoder = OptimizedRespEncoder::new();
496 let value = RespValue::SimpleString("OK".to_string());
497 let encoded_result = encoder.encode(&value).unwrap();
498 assert_eq!(encoded_result, Bytes::from("+OK\r\n"));
499 }
500
501 #[test]
502 fn test_optimized_encoder_command() {
503 let mut encoder = OptimizedRespEncoder::new();
504 let args = vec![RespValue::from("mykey")];
505 let encoded_result = encoder.encode_command("GET", &args).unwrap();
506
507 let expected = "*2\r\n$3\r\nGET\r\n$5\r\nmykey\r\n";
508 assert_eq!(encoded_result, Bytes::from(expected));
509 }
510
511 #[test]
512 fn test_optimized_encoder_command_arguments_are_bulk_strings() {
513 let mut encoder = OptimizedRespEncoder::new();
514 let args = vec![
515 RespValue::from("items"),
516 RespValue::from(0),
517 RespValue::from(-1),
518 ];
519 let encoded_result = encoder.encode_command("LRANGE", &args).unwrap();
520
521 let expected = "*4\r\n$6\r\nLRANGE\r\n$5\r\nitems\r\n$1\r\n0\r\n$2\r\n-1\r\n";
522 assert_eq!(encoded_result, Bytes::from(expected));
523 }
524
525 #[test]
526 fn test_optimized_decoder_streaming() {
527 let mut decoder = OptimizedRespDecoder::new();
528
529 let partial1 = b"+OK\r\n:42\r\n$5\r\nhel";
531 let results1 = decoder.decode_streaming(partial1).unwrap();
532 assert_eq!(results1.len(), 2); let partial2 = b"lo\r\n";
536 let results2 = decoder.decode_streaming(partial2).unwrap();
537 assert_eq!(results2.len(), 1); match &results2[0] {
540 RespValue::BulkString(b) => assert_eq!(b, &Bytes::from("hello")),
541 _ => panic!("Expected bulk string"),
542 }
543 }
544
545 #[test]
546 fn test_size_estimation() {
547 let value = RespValue::SimpleString("OK".to_string());
548 let estimated = OptimizedRespEncoder::estimate_size(&value);
549 assert_eq!(estimated, 5); let value = RespValue::BulkString(Bytes::from("hello"));
552 let estimated = OptimizedRespEncoder::estimate_size(&value);
553 assert_eq!(estimated, 11); }
555
556 #[test]
557 fn test_string_caching() {
558 let mut decoder = OptimizedRespDecoder::new();
559
560 let data = b"+OK\r\n+OK\r\n";
562 let results = decoder.decode_streaming(data).unwrap();
563
564 assert_eq!(results.len(), 2);
565 let (cache_size, _) = decoder.cache_stats();
566 assert_eq!(cache_size, 1); }
568}