ember_protocol/types.rs
1//! RESP3 frame types.
2//!
3//! The [`Frame`] enum represents a single parsed RESP3 value.
4//! Blob strings use `Bytes` for efficient, reference-counted storage
5//! that avoids unnecessary copies when moving data through the pipeline.
6
7use bytes::Bytes;
8
9/// A single RESP3 protocol frame.
10///
11/// Covers the core types needed for basic Redis-compatible commands:
12/// strings, errors, integers, bulk data, arrays, null, and maps.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum Frame {
15 /// Simple string response, e.g. `+OK\r\n`.
16 /// Used for short, non-binary status replies.
17 Simple(String),
18
19 /// Error response, e.g. `-ERR unknown command\r\n`.
20 Error(String),
21
22 /// 64-bit signed integer, e.g. `:42\r\n`.
23 Integer(i64),
24
25 /// Bulk (binary-safe) string, e.g. `$5\r\nhello\r\n`.
26 /// Uses `Bytes` for zero-copy-friendly handling.
27 Bulk(Bytes),
28
29 /// Ordered array of frames, e.g. `*2\r\n+hello\r\n+world\r\n`.
30 Array(Vec<Frame>),
31
32 /// Null value, e.g. `_\r\n`.
33 Null,
34
35 /// Ordered map of key-value frame pairs, e.g. `%1\r\n+key\r\n+val\r\n`.
36 Map(Vec<(Frame, Frame)>),
37}
38
39impl Frame {
40 /// Returns `true` if this frame is a null value.
41 pub fn is_null(&self) -> bool {
42 matches!(self, Frame::Null)
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn frame_equality() {
52 assert_eq!(Frame::Simple("OK".into()), Frame::Simple("OK".into()));
53 assert_ne!(Frame::Simple("OK".into()), Frame::Simple("ERR".into()));
54 assert_eq!(Frame::Integer(42), Frame::Integer(42));
55 assert_eq!(Frame::Null, Frame::Null);
56 }
57
58 #[test]
59 fn is_null() {
60 assert!(Frame::Null.is_null());
61 assert!(!Frame::Simple("OK".into()).is_null());
62 assert!(!Frame::Integer(0).is_null());
63 }
64
65 #[test]
66 fn clone_bulk() {
67 let frame = Frame::Bulk(Bytes::from_static(b"hello"));
68 let cloned = frame.clone();
69 assert_eq!(frame, cloned);
70 }
71}