1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
//! Abstractions for reading the RESP protocol.
//!
//! You can read a RESP stream in several ways. Which one is appropriate depends on your goals.
//!
//! # Frames
//!
//! With [`RespReader::frame`], you can read each individual frame from a RESP stream and decide
//! what to do with it. This allows you to process streams without buffering.
//!
//! # Requests
//!
//! [`RespReader::requests`] will pass each component of a Redis-style request to a closure you
//! provide. This allows for easily sending each argument over a channel to another task.
//!
//! # Values
//!
//! You can also use [`RespReader::value`], which will buffer values and return a whole tree of
//! frames for arrays, maps, sets, etc. This is primarily meant for testing purposes, but could
//! also be useful in cases where performance isn't super important.
/// Conveniently create a [`RespPrimitive`]
#[macro_export]
macro_rules! resp_primitive {
(nil) => {{
use $crate::RespPrimitive;
RespPrimitive::Nil
}};
($x:tt) => {{
$x.into()
}};
}
/// Conveniently create a [`RespValue`]
#[macro_export]
macro_rules! resp {
( ( ! $error:expr ) ) => {{
use $crate::RespValue;
RespValue::Error($error.into())
}};
( ( = $format:expr, $text:expr ) ) => {{
use $crate::RespValue;
RespValue::Verbatim($format.into(), $text.into())
}};
( [ > $($x:tt),* ] ) => {{
use $crate::RespValue;
RespValue::Push(vec![$( resp!{ $x } ),*])
}};
( [ $($x:tt),* ] ) => {{
use $crate::RespValue;
RespValue::Array(vec![$( resp!{ $x } ),*])
}};
( ( big $x:tt ) ) => {{
use $crate::RespValue;
RespValue::Bignum($x.into())
}};
( { } ) => {{
use $crate::RespValue;
use std::collections::BTreeMap;
RespValue::Map(BTreeMap::new())
}};
( { ~ } ) => {{
use $crate::RespValue;
use std::collections::BTreeSet;
RespValue::Set(BTreeSet::new())
}};
( { $($key:tt => $value:tt),* } ) => {{
use $crate::RespValue;
use std::collections::BTreeMap;
// Bytes is a false positive here.
// <https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type>
#[allow(clippy::mutable_key_type)]
let mut map = BTreeMap::new();
$(map.insert(resp_primitive!{ $key }, resp!{ $value });)*
RespValue::Map(map)
}};
( { $($x:tt),* } ) => {{
use $crate::RespValue;
use std::collections::BTreeSet;
// Bytes is a false positive here.
// <https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type>
#[allow(clippy::mutable_key_type)]
let mut set = BTreeSet::new();
$(set.insert(resp_primitive!{ $x });)*
RespValue::Set(set)
}};
( {a $($key:tt => $value:tt),* } ) => {{
use $crate::RespValue;
use std::collections::BTreeMap;
// Bytes is a false positive here.
// <https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type>
#[allow(clippy::mutable_key_type)]
let mut map = BTreeMap::new();
$(map.insert(resp_primitive!{ $key }, resp!{ $value });)*
RespValue::Attribute(map)
}};
(nil) => {{
use $crate::RespValue;
RespValue::Nil
}};
($x:tt) => {{
$x.into()
}};
}
mod config;
mod error;
mod frame;
mod primitive;
mod reader;
mod request;
mod splitter;
mod value;
mod version;
mod writer;
pub use config::RespConfig;
pub use error::RespError;
pub use frame::RespFrame;
pub use primitive::RespPrimitive;
pub use reader::RespReader;
pub use request::RespRequest;
use splitter::Splitter;
pub use value::RespValue;
pub use version::RespVersion;
pub use writer::RespWriter;