1use std::io::Write;
7
8#[derive(Debug, Clone)]
26pub struct Request<'a> {
27 args: Vec<&'a [u8]>,
28}
29
30impl<'a> Request<'a> {
31 #[inline]
33 pub fn new(args: Vec<&'a [u8]>) -> Self {
34 Self { args }
35 }
36
37 #[inline]
39 pub fn ping() -> Self {
40 Self {
41 args: vec![b"PING"],
42 }
43 }
44
45 #[inline]
47 pub fn get(key: &'a [u8]) -> Self {
48 Self {
49 args: vec![b"GET", key],
50 }
51 }
52
53 #[inline]
55 pub fn set(key: &'a [u8], value: &'a [u8]) -> SetRequest<'a> {
56 SetRequest {
57 key,
58 value,
59 ex: None,
60 px: None,
61 nx: false,
62 xx: false,
63 }
64 }
65
66 #[inline]
68 pub fn del(key: &'a [u8]) -> Self {
69 Self {
70 args: vec![b"DEL", key],
71 }
72 }
73
74 #[inline]
76 pub fn mget(keys: &[&'a [u8]]) -> Self {
77 let mut args = Vec::with_capacity(1 + keys.len());
78 args.push(b"MGET" as &[u8]);
79 args.extend_from_slice(keys);
80 Self { args }
81 }
82
83 #[inline]
85 pub fn config_get(key: &'a [u8]) -> Self {
86 Self {
87 args: vec![b"CONFIG", b"GET", key],
88 }
89 }
90
91 #[inline]
93 pub fn config_set(key: &'a [u8], value: &'a [u8]) -> Self {
94 Self {
95 args: vec![b"CONFIG", b"SET", key, value],
96 }
97 }
98
99 #[inline]
101 pub fn flushdb() -> Self {
102 Self {
103 args: vec![b"FLUSHDB"],
104 }
105 }
106
107 #[inline]
109 pub fn flushall() -> Self {
110 Self {
111 args: vec![b"FLUSHALL"],
112 }
113 }
114
115 #[inline]
117 pub fn cluster_slots() -> Self {
118 Self {
119 args: vec![b"CLUSTER", b"SLOTS"],
120 }
121 }
122
123 #[inline]
125 pub fn cluster_nodes() -> Self {
126 Self {
127 args: vec![b"CLUSTER", b"NODES"],
128 }
129 }
130
131 #[inline]
133 pub fn cluster_info() -> Self {
134 Self {
135 args: vec![b"CLUSTER", b"INFO"],
136 }
137 }
138
139 #[inline]
141 pub fn cluster_myid() -> Self {
142 Self {
143 args: vec![b"CLUSTER", b"MYID"],
144 }
145 }
146
147 #[inline]
149 pub fn asking() -> Self {
150 Self {
151 args: vec![b"ASKING"],
152 }
153 }
154
155 #[inline]
157 pub fn readonly() -> Self {
158 Self {
159 args: vec![b"READONLY"],
160 }
161 }
162
163 #[inline]
165 pub fn readwrite() -> Self {
166 Self {
167 args: vec![b"READWRITE"],
168 }
169 }
170
171 #[inline]
173 pub fn cmd(name: &'a [u8]) -> Self {
174 Self { args: vec![name] }
175 }
176
177 #[inline]
179 pub fn arg(mut self, arg: &'a [u8]) -> Self {
180 self.args.push(arg);
181 self
182 }
183
184 #[inline]
192 pub fn encode(&self, buf: &mut [u8]) -> usize {
193 encode_command(buf, &self.args)
194 }
195
196 pub fn encoded_len(&self) -> usize {
198 let mut len = 0;
199
200 let mut count_buf = itoa::Buffer::new();
202 len += 1 + count_buf.format(self.args.len()).len() + 2;
203
204 for arg in &self.args {
206 let mut arg_len_buf = itoa::Buffer::new();
207 len += 1 + arg_len_buf.format(arg.len()).len() + 2 + arg.len() + 2;
208 }
209
210 len
211 }
212}
213
214#[derive(Debug, Clone)]
216pub struct SetRequest<'a> {
217 key: &'a [u8],
218 value: &'a [u8],
219 ex: Option<u64>,
220 px: Option<u64>,
221 nx: bool,
222 xx: bool,
223}
224
225impl<'a> SetRequest<'a> {
226 #[inline]
228 pub fn ex(mut self, seconds: u64) -> Self {
229 self.ex = Some(seconds);
230 self.px = None; self
232 }
233
234 #[inline]
236 pub fn px(mut self, milliseconds: u64) -> Self {
237 self.px = Some(milliseconds);
238 self.ex = None; self
240 }
241
242 #[inline]
244 pub fn nx(mut self) -> Self {
245 self.nx = true;
246 self.xx = false; self
248 }
249
250 #[inline]
252 pub fn xx(mut self) -> Self {
253 self.xx = true;
254 self.nx = false; self
256 }
257
258 pub fn encode_parts(&self) -> (Vec<u8>, Vec<u8>) {
266 let mut ex_str = itoa::Buffer::new();
267 let mut px_str = itoa::Buffer::new();
268
269 let mut arg_count: usize = 3;
271 if self.ex.is_some() || self.px.is_some() {
272 arg_count += 2;
273 }
274 if self.nx || self.xx {
275 arg_count += 1;
276 }
277
278 let mut prefix = Vec::new();
280 let mut count_buf = itoa::Buffer::new();
281 write!(prefix, "*{}\r\n", count_buf.format(arg_count)).unwrap();
282 write!(prefix, "$3\r\nSET\r\n").unwrap();
284 let mut klen_buf = itoa::Buffer::new();
286 write!(prefix, "${}\r\n", klen_buf.format(self.key.len())).unwrap();
287 prefix.extend_from_slice(self.key);
288 write!(prefix, "\r\n").unwrap();
289 let mut vlen_buf = itoa::Buffer::new();
291 write!(prefix, "${}\r\n", vlen_buf.format(self.value.len())).unwrap();
292
293 let mut suffix = Vec::new();
295 write!(suffix, "\r\n").unwrap();
296 if let Some(seconds) = self.ex {
297 let s = ex_str.format(seconds);
298 let mut slen_buf = itoa::Buffer::new();
299 write!(suffix, "$2\r\nEX\r\n${}\r\n", slen_buf.format(s.len())).unwrap();
300 suffix.extend_from_slice(s.as_bytes());
301 write!(suffix, "\r\n").unwrap();
302 } else if let Some(millis) = self.px {
303 let s = px_str.format(millis);
304 let mut slen_buf = itoa::Buffer::new();
305 write!(suffix, "$2\r\nPX\r\n${}\r\n", slen_buf.format(s.len())).unwrap();
306 suffix.extend_from_slice(s.as_bytes());
307 write!(suffix, "\r\n").unwrap();
308 }
309 if self.nx {
310 write!(suffix, "$2\r\nNX\r\n").unwrap();
311 } else if self.xx {
312 write!(suffix, "$2\r\nXX\r\n").unwrap();
313 }
314
315 (prefix, suffix)
316 }
317
318 #[inline]
322 pub fn encode(&self, buf: &mut [u8]) -> usize {
323 let mut ex_str = itoa::Buffer::new();
325 let mut px_str = itoa::Buffer::new();
326
327 let mut args: Vec<&[u8]> = vec![b"SET", self.key, self.value];
328
329 if let Some(seconds) = self.ex {
330 args.push(b"EX");
331 args.push(ex_str.format(seconds).as_bytes());
332 } else if let Some(millis) = self.px {
333 args.push(b"PX");
334 args.push(px_str.format(millis).as_bytes());
335 }
336
337 if self.nx {
338 args.push(b"NX");
339 } else if self.xx {
340 args.push(b"XX");
341 }
342
343 encode_command(buf, &args)
344 }
345
346 pub fn encoded_len(&self) -> usize {
348 let mut ex_str = itoa::Buffer::new();
350 let mut px_str = itoa::Buffer::new();
351
352 let mut args: Vec<&[u8]> = vec![b"SET", self.key, self.value];
353
354 if let Some(seconds) = self.ex {
355 args.push(b"EX");
356 args.push(ex_str.format(seconds).as_bytes());
357 } else if let Some(millis) = self.px {
358 args.push(b"PX");
359 args.push(px_str.format(millis).as_bytes());
360 }
361
362 if self.nx {
363 args.push(b"NX");
364 } else if self.xx {
365 args.push(b"XX");
366 }
367
368 let mut len = 0;
370
371 let mut count_buf = itoa::Buffer::new();
373 len += 1 + count_buf.format(args.len()).len() + 2;
374
375 for arg in &args {
377 let mut arg_len_buf = itoa::Buffer::new();
378 len += 1 + arg_len_buf.format(arg.len()).len() + 2 + arg.len() + 2;
379 }
380
381 len
382 }
383}
384
385#[inline]
389pub fn encode_command(buf: &mut [u8], args: &[&[u8]]) -> usize {
390 let mut pos = 0;
391
392 buf[pos] = b'*';
394 pos += 1;
395 let mut cursor = std::io::Cursor::new(&mut buf[pos..]);
396 write!(cursor, "{}\r\n", args.len()).unwrap();
397 pos += cursor.position() as usize;
398
399 for arg in args {
401 buf[pos] = b'$';
403 pos += 1;
404 let mut cursor = std::io::Cursor::new(&mut buf[pos..]);
405 write!(cursor, "{}\r\n", arg.len()).unwrap();
406 pos += cursor.position() as usize;
407
408 buf[pos..pos + arg.len()].copy_from_slice(arg);
410 pos += arg.len();
411 buf[pos] = b'\r';
412 buf[pos + 1] = b'\n';
413 pos += 2;
414 }
415
416 pos
417}
418
419#[cfg(test)]
420mod tests {
421 use super::*;
422
423 #[test]
424 fn test_encode_ping() {
425 let mut buf = [0u8; 64];
426 let len = Request::ping().encode(&mut buf);
427 assert_eq!(&buf[..len], b"*1\r\n$4\r\nPING\r\n");
428 }
429
430 #[test]
431 fn test_encode_get() {
432 let mut buf = [0u8; 64];
433 let len = Request::get(b"mykey").encode(&mut buf);
434 assert_eq!(&buf[..len], b"*2\r\n$3\r\nGET\r\n$5\r\nmykey\r\n");
435 }
436
437 #[test]
438 fn test_encode_set() {
439 let mut buf = [0u8; 64];
440 let len = Request::set(b"mykey", b"myvalue").encode(&mut buf);
441 assert_eq!(
442 &buf[..len],
443 b"*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n"
444 );
445 }
446
447 #[test]
448 fn test_encode_set_ex() {
449 let mut buf = [0u8; 128];
450 let len = Request::set(b"mykey", b"myvalue").ex(3600).encode(&mut buf);
451 assert_eq!(
452 &buf[..len],
453 b"*5\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n$2\r\nEX\r\n$4\r\n3600\r\n"
454 );
455 }
456
457 #[test]
458 fn test_encode_set_px() {
459 let mut buf = [0u8; 128];
460 let len = Request::set(b"key", b"val").px(1000).encode(&mut buf);
461 assert!(std::str::from_utf8(&buf[..len]).unwrap().contains("PX"));
462 }
463
464 #[test]
465 fn test_encode_set_nx() {
466 let mut buf = [0u8; 128];
467 let len = Request::set(b"key", b"val").nx().encode(&mut buf);
468 assert!(std::str::from_utf8(&buf[..len]).unwrap().contains("NX"));
469 }
470
471 #[test]
472 fn test_encode_del() {
473 let mut buf = [0u8; 64];
474 let len = Request::del(b"mykey").encode(&mut buf);
475 assert_eq!(&buf[..len], b"*2\r\n$3\r\nDEL\r\n$5\r\nmykey\r\n");
476 }
477
478 #[test]
479 fn test_encode_mget() {
480 let mut buf = [0u8; 128];
481 let keys: &[&[u8]] = &[b"key1", b"key2", b"key3"];
482 let len = Request::mget(keys).encode(&mut buf);
483 assert_eq!(
484 &buf[..len],
485 b"*4\r\n$4\r\nMGET\r\n$4\r\nkey1\r\n$4\r\nkey2\r\n$4\r\nkey3\r\n"
486 );
487 }
488
489 #[test]
490 fn test_encode_flushdb() {
491 let mut buf = [0u8; 64];
492 let len = Request::flushdb().encode(&mut buf);
493 assert_eq!(&buf[..len], b"*1\r\n$7\r\nFLUSHDB\r\n");
494 }
495
496 #[test]
497 fn test_encode_custom() {
498 let mut buf = [0u8; 64];
499 let len = Request::cmd(b"INCR").arg(b"counter").encode(&mut buf);
500 assert_eq!(&buf[..len], b"*2\r\n$4\r\nINCR\r\n$7\r\ncounter\r\n");
501 }
502
503 #[test]
504 fn test_encoded_len() {
505 let requests: Vec<Request> = vec![
506 Request::ping(),
507 Request::get(b"mykey"),
508 Request::del(b"test"),
509 ];
510
511 for req in requests {
512 let mut buf = [0u8; 256];
513 let actual_len = req.encode(&mut buf);
514 assert_eq!(req.encoded_len(), actual_len);
515 }
516 }
517
518 #[test]
519 fn test_request_new() {
520 let args: Vec<&[u8]> = vec![b"CUSTOM", b"arg1", b"arg2"];
521 let req = Request::new(args);
522 let mut buf = [0u8; 128];
523 let len = req.encode(&mut buf);
524 assert!(len > 0);
525 assert!(std::str::from_utf8(&buf[..len]).unwrap().contains("CUSTOM"));
526 }
527
528 #[test]
529 fn test_encode_config_get() {
530 let mut buf = [0u8; 128];
531 let len = Request::config_get(b"maxclients").encode(&mut buf);
532 let encoded = std::str::from_utf8(&buf[..len]).unwrap();
533 assert!(encoded.contains("CONFIG"));
534 assert!(encoded.contains("GET"));
535 assert!(encoded.contains("maxclients"));
536 }
537
538 #[test]
539 fn test_encode_config_set() {
540 let mut buf = [0u8; 128];
541 let len = Request::config_set(b"maxclients", b"100").encode(&mut buf);
542 let encoded = std::str::from_utf8(&buf[..len]).unwrap();
543 assert!(encoded.contains("CONFIG"));
544 assert!(encoded.contains("SET"));
545 assert!(encoded.contains("maxclients"));
546 assert!(encoded.contains("100"));
547 }
548
549 #[test]
550 fn test_encode_flushall() {
551 let mut buf = [0u8; 64];
552 let len = Request::flushall().encode(&mut buf);
553 assert_eq!(&buf[..len], b"*1\r\n$8\r\nFLUSHALL\r\n");
554 }
555
556 #[test]
557 fn test_encode_set_xx() {
558 let mut buf = [0u8; 128];
559 let len = Request::set(b"key", b"val").xx().encode(&mut buf);
560 assert!(std::str::from_utf8(&buf[..len]).unwrap().contains("XX"));
561 }
562
563 #[test]
564 fn test_set_px_overrides_ex() {
565 let mut buf = [0u8; 128];
567 let len = Request::set(b"key", b"val")
568 .ex(100)
569 .px(5000)
570 .encode(&mut buf);
571 let encoded = std::str::from_utf8(&buf[..len]).unwrap();
572 assert!(encoded.contains("PX"));
573 assert!(!encoded.contains("EX\r\n")); }
575
576 #[test]
577 fn test_set_ex_overrides_px() {
578 let mut buf = [0u8; 128];
580 let len = Request::set(b"key", b"val")
581 .px(5000)
582 .ex(100)
583 .encode(&mut buf);
584 let encoded = std::str::from_utf8(&buf[..len]).unwrap();
585 assert!(encoded.contains("EX"));
586 assert!(!encoded.contains("PX"));
587 }
588
589 #[test]
590 fn test_set_xx_overrides_nx() {
591 let set_req = Request::set(b"key", b"val").nx().xx();
593 assert!(set_req.xx);
594 assert!(!set_req.nx);
595 }
596
597 #[test]
598 fn test_set_nx_overrides_xx() {
599 let set_req = Request::set(b"key", b"val").xx().nx();
601 assert!(set_req.nx);
602 assert!(!set_req.xx);
603 }
604
605 #[test]
606 fn test_set_request_encoded_len() {
607 let configs = vec![
609 Request::set(b"key", b"value"),
610 Request::set(b"key", b"value").ex(3600),
611 Request::set(b"key", b"value").px(5000),
612 Request::set(b"key", b"value").nx(),
613 Request::set(b"key", b"value").xx(),
614 Request::set(b"key", b"value").ex(3600).nx(),
615 ];
616
617 for config in configs {
618 let mut buf = [0u8; 256];
619 let actual_len = config.encode(&mut buf);
620 let estimated_len = config.encoded_len();
621 assert_eq!(
622 estimated_len, actual_len,
623 "encoded_len() should match actual encoded length"
624 );
625 }
626 }
627
628 #[test]
629 fn test_set_request_encoded_len_large_values() {
630 let large_key = vec![b'k'; 1000];
633 let large_value = vec![b'v'; 10000];
634
635 let config = Request::set(&large_key, &large_value).ex(86400);
636 let mut buf = vec![0u8; 20000];
637 let actual_len = config.encode(&mut buf);
638 let estimated_len = config.encoded_len();
639 assert_eq!(
640 estimated_len, actual_len,
641 "encoded_len() should match for large values"
642 );
643 }
644
645 #[test]
646 fn test_encode_parts_matches_encode() {
647 let configs: Vec<SetRequest<'_>> = vec![
648 Request::set(b"mykey", b"myvalue"),
649 Request::set(b"k", b"v").ex(3600),
650 Request::set(b"key", b"val").px(1000),
651 Request::set(b"key", b"val").nx(),
652 Request::set(b"key", b"val").xx(),
653 Request::set(b"key", b"val").ex(86400).nx(),
654 Request::set(b"key", b"val").px(500).xx(),
655 ];
656
657 for config in &configs {
658 let mut buf = vec![0u8; 512];
660 let len = config.encode(&mut buf);
661 let full = &buf[..len];
662
663 let (prefix, suffix) = config.encode_parts();
665 let mut assembled = Vec::new();
666 assembled.extend_from_slice(&prefix);
667 assembled.extend_from_slice(config.value);
668 assembled.extend_from_slice(&suffix);
669
670 assert_eq!(
671 assembled, full,
672 "encode_parts concat must match encode() for {:?}",
673 config
674 );
675 }
676 }
677
678 #[test]
679 fn test_request_debug() {
680 let req = Request::ping();
681 let debug_str = format!("{:?}", req);
682 assert!(debug_str.contains("Request"));
683 }
684
685 #[test]
686 fn test_request_clone() {
687 let req1 = Request::get(b"mykey");
688 let req2 = req1.clone();
689 let mut buf1 = [0u8; 64];
690 let mut buf2 = [0u8; 64];
691 let len1 = req1.encode(&mut buf1);
692 let len2 = req2.encode(&mut buf2);
693 assert_eq!(&buf1[..len1], &buf2[..len2]);
694 }
695
696 #[test]
697 fn test_set_request_debug() {
698 let set_req = Request::set(b"key", b"value");
699 let debug_str = format!("{:?}", set_req);
700 assert!(debug_str.contains("SetRequest"));
701 }
702
703 #[test]
704 fn test_set_request_clone() {
705 let set1 = Request::set(b"key", b"value").ex(100);
706 let set2 = set1.clone();
707 let mut buf1 = [0u8; 128];
708 let mut buf2 = [0u8; 128];
709 let len1 = set1.encode(&mut buf1);
710 let len2 = set2.encode(&mut buf2);
711 assert_eq!(&buf1[..len1], &buf2[..len2]);
712 }
713
714 #[test]
715 fn test_encode_cluster_slots() {
716 let mut buf = [0u8; 128];
717 let len = Request::cluster_slots().encode(&mut buf);
718 assert_eq!(&buf[..len], b"*2\r\n$7\r\nCLUSTER\r\n$5\r\nSLOTS\r\n");
719 }
720
721 #[test]
722 fn test_encode_cluster_nodes() {
723 let mut buf = [0u8; 128];
724 let len = Request::cluster_nodes().encode(&mut buf);
725 assert_eq!(&buf[..len], b"*2\r\n$7\r\nCLUSTER\r\n$5\r\nNODES\r\n");
726 }
727
728 #[test]
729 fn test_encode_cluster_info() {
730 let mut buf = [0u8; 128];
731 let len = Request::cluster_info().encode(&mut buf);
732 assert_eq!(&buf[..len], b"*2\r\n$7\r\nCLUSTER\r\n$4\r\nINFO\r\n");
733 }
734
735 #[test]
736 fn test_encode_cluster_myid() {
737 let mut buf = [0u8; 128];
738 let len = Request::cluster_myid().encode(&mut buf);
739 assert_eq!(&buf[..len], b"*2\r\n$7\r\nCLUSTER\r\n$4\r\nMYID\r\n");
740 }
741
742 #[test]
743 fn test_encode_asking() {
744 let mut buf = [0u8; 64];
745 let len = Request::asking().encode(&mut buf);
746 assert_eq!(&buf[..len], b"*1\r\n$6\r\nASKING\r\n");
747 }
748
749 #[test]
750 fn test_encode_readonly() {
751 let mut buf = [0u8; 64];
752 let len = Request::readonly().encode(&mut buf);
753 assert_eq!(&buf[..len], b"*1\r\n$8\r\nREADONLY\r\n");
754 }
755
756 #[test]
757 fn test_encode_readwrite() {
758 let mut buf = [0u8; 64];
759 let len = Request::readwrite().encode(&mut buf);
760 assert_eq!(&buf[..len], b"*1\r\n$9\r\nREADWRITE\r\n");
761 }
762
763 #[test]
764 fn test_mget_empty() {
765 let keys: &[&[u8]] = &[];
766 let req = Request::mget(keys);
767 let mut buf = [0u8; 64];
768 let len = req.encode(&mut buf);
769 assert_eq!(&buf[..len], b"*1\r\n$4\r\nMGET\r\n");
771 }
772}