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;