Skip to main content

kevy_resp/
lib.rs

1//! kevy-resp — a zero-dependency [RESP] (REdis Serialization Protocol) codec.
2//!
3//! It covers what a client sends to drive commands — the RESP2 multi-bulk
4//! request (`*N\r\n$len\r\n…`) and the inline form (a bare `PING\r\n` typed over
5//! a raw connection) — plus the reply primitives a server writes back. Parsing
6//! is incremental and allocation-light: [`parse_command`] returns `Ok(None)`
7//! when more bytes are needed, so it composes with a streaming read loop.
8//!
9//! Pure Rust, no dependencies. Part of the [kevy] key–value server.
10//!
11//! [RESP]: https://redis.io/docs/latest/develop/reference/protocol-spec/
12//! [kevy]: https://crates.io/crates/kevy
13//!
14//! # Example
15//!
16//! ```
17//! use kevy_resp::{encode_bulk, encode_simple_string, parse_command};
18//!
19//! // Parse one command from a request buffer.
20//! let (cmd, consumed) = parse_command(b"*2\r\n$4\r\nECHO\r\n$2\r\nhi\r\n")
21//!     .unwrap() // not a protocol error
22//!     .unwrap(); // a complete frame was present
23//! assert_eq!(cmd, vec![b"ECHO".to_vec(), b"hi".to_vec()]);
24//! assert_eq!(consumed, 22);
25//!
26//! // A partial frame asks for more bytes rather than erroring.
27//! assert_eq!(parse_command(b"*1\r\n$4\r\nPI").unwrap(), None);
28//!
29//! // Encode replies into a caller-owned buffer.
30//! let mut out = Vec::new();
31//! encode_simple_string(&mut out, "PONG");
32//! encode_bulk(&mut out, b"hi");
33//! assert_eq!(out, b"+PONG\r\n$2\r\nhi\r\n");
34//! ```
35#![forbid(unsafe_code)]
36#![warn(missing_docs)]
37
38mod argv;
39mod argv_borrowed;
40mod argv_pool;
41mod argv_view;
42mod error;
43pub mod fuzz;
44mod inline_ranges;
45pub mod ops_table;
46mod reply_encode;
47mod reply_encode_resp3;
48mod reply_parse;
49mod request;
50mod request_borrowed;
51pub mod verb_arity;
52
53pub use argv::{Argv, Command};
54pub use argv_borrowed::ArgvBorrowed;
55pub use argv_pool::ArgvPool;
56pub use argv_view::{ArgvIter, ArgvView};
57pub use error::{CmdError, ProtocolError};
58pub use reply_encode::{
59    encode_array_len, encode_bulk, encode_command, encode_command_borrowed, encode_error,
60    encode_integer, encode_null_bulk, encode_simple_string,
61};
62pub use reply_encode_resp3::{
63    encode_big_number, encode_blob_error, encode_boolean, encode_double, encode_map_header,
64    encode_null, encode_push_header, encode_set_header, encode_verbatim,
65};
66pub use reply_parse::{Reply, parse_reply};
67pub use request::{MAX_BULK_LEN, MAX_MULTIBULK_LEN, parse_command, parse_command_into};
68pub use request_borrowed::parse_command_borrowed;
69
70/// Which version of RESP a connection is speaking. Negotiated via the
71/// `HELLO` command — RESP2 is the default for backwards compatibility
72/// with every Redis 6.x and earlier client; RESP3 is opt-in via
73/// `HELLO 3` and unlocks the additive reply types
74/// ([`Reply::Map`] / [`Reply::Set`] / [`Reply::Double`] / [`Reply::Boolean`]
75/// / [`Reply::Verbatim`] / [`Reply::BigNumber`] / [`Reply::Null`] /
76/// [`Reply::Push`] / [`Reply::BlobError`]) plus out-of-band push frames
77/// for `PUBLISH` delivery.
78///
79/// Stored per-connection in `kevy-rt` and forwarded to dispatch so each
80/// reply encoder can pick the right wire shape — see the kevy v2 RESP3
81/// design notes for the full phase plan.
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
83pub enum RespVersion {
84    /// RESP2 — every reply is one of the seven legacy prefixes
85    /// (`+ - : $ * $-1 *-1`). Default for backward compatibility.
86    #[default]
87    V2,
88    /// RESP3 — adds 9 reply prefixes (`% ~ , # = ( _ > !`) plus
89    /// attributes (`|`). Opt-in via `HELLO 3`.
90    V3,
91}