redust_resp/
data.rs

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