Skip to main content

redust_resp/resp2/
data.rs

1use hipstr::HipStr;
2
3pub use bulk::Bulk;
4
5mod bulk;
6
7pub mod de;
8pub mod ser;
9
10/// RESP data. Read the [Redis documenation](https://redis.io/commands) for details on which type
11/// to expect as a response.
12///
13/// Both [Data::BulkString] and [Data::Array] can represent nulls in RESP, but in this
14/// representation they are not optional. They will be represented with [Data::Null] if the bulk
15/// string or array is null.
16///
17/// Errors are not represented here for two reasons: 1) it's never correct to send an error to the
18/// Redis server, and 2) it's more ergonomic to have errors returned in a [Result](crate::Result).
19///
20/// Since errors are not represented, it's possible to convert a Rust string into `Data` without
21/// ambiguity.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum Data<'a> {
24	SimpleString(HipStr<'a>),
25	Integer(i64),
26	BulkString(Bulk<'a>),
27	Array(Vec<Data<'a>>),
28	Null,
29}
30
31impl<'a> Data<'a> {
32	/// Convenience method to create a [Data::SimpleString].
33	pub fn simple_string<T>(str: &'a T) -> Self
34	where
35		T: AsRef<str> + ?Sized,
36	{
37		Self::SimpleString(HipStr::borrowed(str.as_ref()))
38	}
39
40	/// Convenience method to create a [Data::BulkString].
41	pub fn bulk_string<T>(bytes: &'a T) -> Self
42	where
43		T: AsRef<[u8]> + ?Sized,
44	{
45		Self::BulkString(bytes.as_ref().into())
46	}
47
48	/// Convert this data into owned data.
49	pub fn into_owned(self) -> Data<'static> {
50		match self {
51			Self::SimpleString(str) => Data::SimpleString(str.into_owned()),
52			Self::Integer(int) => Data::Integer(int),
53			Self::BulkString(bytes) => Data::BulkString(bytes.into_owned().into()),
54			Self::Array(arr) => Data::Array(arr.into_iter().map(Data::into_owned).collect()),
55			Self::Null => Data::Null,
56		}
57	}
58
59	pub fn from_bytes_iter<I, B>(iter: I) -> Data<'a>
60	where
61		I: IntoIterator<Item = &'a B>,
62		B: 'a + AsRef<[u8]> + ?Sized,
63	{
64		Data::Array(iter.into_iter().map(Data::from_bytes).collect())
65	}
66
67	pub fn from_bytes<B>(bytes: &'a B) -> Data<'a>
68	where
69		B: 'a + AsRef<[u8]> + ?Sized,
70	{
71		Data::BulkString(bytes.as_ref().into())
72	}
73}
74
75impl<'a> From<&'a str> for Data<'a> {
76	fn from(str: &'a str) -> Self {
77		Data::SimpleString(HipStr::borrowed(str))
78	}
79}
80
81impl From<String> for Data<'_> {
82	fn from(str: String) -> Self {
83		Data::SimpleString(str.into())
84	}
85}
86
87impl From<i64> for Data<'_> {
88	fn from(i: i64) -> Self {
89		Data::Integer(i)
90	}
91}
92
93impl<'a, const N: usize> From<&'a [u8; N]> for Data<'a> {
94	fn from(bytes: &'a [u8; N]) -> Self {
95		Self::bulk_string(bytes)
96	}
97}
98
99impl<'a> From<&'a [u8]> for Data<'a> {
100	fn from(bytes: &'a [u8]) -> Self {
101		Self::BulkString(bytes.into())
102	}
103}
104
105impl From<Vec<u8>> for Data<'_> {
106	fn from(bytes: Vec<u8>) -> Self {
107		Self::BulkString(bytes.into())
108	}
109}
110
111impl<I> FromIterator<I> for Data<'_>
112where
113	Self: From<I>,
114{
115	fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
116		iter.into_iter()
117			.map(Data::from)
118			.collect::<Vec<Data>>()
119			.into()
120	}
121}
122
123impl<'a> From<Vec<Data<'a>>> for Data<'a> {
124	fn from(data: Vec<Data<'a>>) -> Self {
125		Self::Array(data)
126	}
127}
128
129impl From<()> for Data<'_> {
130	fn from(_: ()) -> Self {
131		Data::Null
132	}
133}
134
135impl PartialEq<str> for Data<'_> {
136	fn eq(&self, other: &str) -> bool {
137		matches!(self, Data::SimpleString(str) if str == other)
138	}
139}
140
141impl PartialEq<&str> for Data<'_> {
142	fn eq(&self, other: &&str) -> bool {
143		matches!(self, Data::SimpleString(str) if str == other)
144	}
145}
146
147impl PartialEq<[u8]> for Data<'_> {
148	fn eq(&self, other: &[u8]) -> bool {
149		matches!(self, Data::BulkString(bytes) if bytes.as_ref() == other)
150	}
151}
152
153impl PartialEq<&[u8]> for Data<'_> {
154	fn eq(&self, other: &&[u8]) -> bool {
155		matches!(self, Data::BulkString(bytes) if bytes == other)
156	}
157}
158
159impl<const N: usize> PartialEq<[u8; N]> for Data<'_> {
160	fn eq(&self, other: &[u8; N]) -> bool {
161		matches!(self, Data::BulkString(bytes) if bytes.as_ref() == other)
162	}
163}
164
165impl<const N: usize> PartialEq<&[u8; N]> for Data<'_> {
166	fn eq(&self, other: &&[u8; N]) -> bool {
167		matches!(self, Data::BulkString(bytes) if bytes.as_ref() == *other)
168	}
169}
170
171impl PartialEq<i64> for Data<'_> {
172	fn eq(&self, other: &i64) -> bool {
173		matches!(self, Data::Integer(i) if *i == *other)
174	}
175}
176
177impl PartialEq<()> for Data<'_> {
178	fn eq(&self, _: &()) -> bool {
179		matches!(self, Data::Null)
180	}
181}
182
183/// Macro to simplify making a [Data::Array].
184///
185/// Changes:
186/// ```rust
187/// # use redust_resp::Data;
188/// Data::Array(vec![Data::simple_string("foo"), Data::simple_string("bar")]);
189/// ```
190/// into
191/// ```rust
192/// # use redust_resp::array;
193/// array!("foo", "bar");
194/// ```
195#[macro_export]
196macro_rules! array {
197	($($items:expr),*) => {
198		$crate::Data::Array(vec![$($crate::Data::from($items)),*])
199	};
200}