redis_oxide/core/
value.rs1use crate::core::error::{RedisError, RedisResult};
4use bytes::Bytes;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum RespValue {
9 SimpleString(String),
11 Error(String),
13 Integer(i64),
15 BulkString(Bytes),
17 Null,
19 Array(Vec<RespValue>),
21}
22
23impl RespValue {
24 pub fn as_string(&self) -> RedisResult<String> {
30 match self {
31 Self::SimpleString(s) => Ok(s.clone()),
32 Self::BulkString(b) => String::from_utf8(b.to_vec())
33 .map_err(|e| RedisError::Type(format!("Invalid UTF-8: {e}"))),
34 Self::Null => Err(RedisError::Type("Value is null".to_string())),
35 _ => Err(RedisError::Type(format!(
36 "Cannot convert {self:?} to string"
37 ))),
38 }
39 }
40
41 pub fn as_int(&self) -> RedisResult<i64> {
47 match self {
48 Self::Integer(i) => Ok(*i),
49 Self::BulkString(b) => {
50 let s = String::from_utf8(b.to_vec())
51 .map_err(|e| RedisError::Type(format!("Invalid UTF-8: {e}")))?;
52 s.parse::<i64>()
53 .map_err(|e| RedisError::Type(format!("Cannot parse integer: {e}")))
54 }
55 _ => Err(RedisError::Type(format!(
56 "Cannot convert {self:?} to integer"
57 ))),
58 }
59 }
60
61 pub fn as_bytes(&self) -> RedisResult<Bytes> {
67 match self {
68 Self::BulkString(b) => Ok(b.clone()),
69 Self::SimpleString(s) => Ok(Bytes::from(s.as_bytes().to_vec())),
70 Self::Null => Err(RedisError::Type("Value is null".to_string())),
71 _ => Err(RedisError::Type(format!(
72 "Cannot convert {self:?} to bytes"
73 ))),
74 }
75 }
76
77 pub fn as_array(&self) -> RedisResult<Vec<Self>> {
83 match self {
84 Self::Array(arr) => Ok(arr.clone()),
85 _ => Err(RedisError::Type(format!(
86 "Cannot convert {self:?} to array"
87 ))),
88 }
89 }
90
91 #[must_use]
93 pub const fn is_null(&self) -> bool {
94 matches!(self, Self::Null)
95 }
96
97 #[must_use]
99 pub const fn is_error(&self) -> bool {
100 matches!(self, Self::Error(_))
101 }
102
103 pub fn as_bool(&self) -> RedisResult<bool> {
109 match self {
110 Self::Integer(1) => Ok(true),
111 Self::Integer(0) => Ok(false),
112 Self::SimpleString(s) if s == "OK" => Ok(true),
113 Self::BulkString(b) => {
114 let s = String::from_utf8(b.to_vec())
115 .map_err(|e| RedisError::Type(format!("Invalid UTF-8: {e}")))?;
116 Ok(s == "1" || s.to_lowercase() == "true")
117 }
118 _ => Err(RedisError::Type(format!(
119 "Cannot convert {self:?} to boolean"
120 ))),
121 }
122 }
123
124 #[must_use]
126 pub fn into_error(self) -> Option<String> {
127 match self {
128 Self::Error(msg) => Some(msg),
129 _ => None,
130 }
131 }
132}
133
134impl From<String> for RespValue {
135 fn from(s: String) -> Self {
136 Self::BulkString(Bytes::from(s.into_bytes()))
137 }
138}
139impl From<&str> for RespValue {
140 fn from(s: &str) -> Self {
141 Self::BulkString(Bytes::from(s.as_bytes().to_vec()))
142 }
143}
144impl From<i64> for RespValue {
145 fn from(i: i64) -> Self {
146 Self::Integer(i)
147 }
148}
149impl From<Vec<u8>> for RespValue {
150 fn from(b: Vec<u8>) -> Self {
151 Self::BulkString(Bytes::from(b))
152 }
153}
154impl From<Bytes> for RespValue {
155 fn from(b: Bytes) -> Self {
156 Self::BulkString(b)
157 }
158}
159
160impl TryFrom<RespValue> for String {
161 type Error = RedisError;
162
163 fn try_from(value: RespValue) -> Result<Self, Self::Error> {
164 value.as_string()
165 }
166}
167
168impl TryFrom<RespValue> for i64 {
169 type Error = RedisError;
170
171 fn try_from(value: RespValue) -> Result<Self, Self::Error> {
172 value.as_int()
173 }
174}
175
176impl TryFrom<RespValue> for bool {
177 type Error = RedisError;
178
179 fn try_from(value: RespValue) -> Result<Self, Self::Error> {
180 match value {
181 RespValue::Integer(1) => Ok(true),
182 RespValue::Integer(0) => Ok(false),
183 RespValue::SimpleString(s) if s == "OK" => Ok(true),
184 _ => Err(RedisError::Type(format!(
185 "Cannot convert {:?} to bool",
186 value
187 ))),
188 }
189 }
190}
191
192impl TryFrom<RespValue> for Option<String> {
193 type Error = RedisError;
194
195 fn try_from(value: RespValue) -> Result<Self, Self::Error> {
196 match value {
197 RespValue::BulkString(b) => String::from_utf8(b.to_vec())
198 .map(Some)
199 .map_err(|e| RedisError::Type(format!("Invalid UTF-8: {e}"))),
200 RespValue::SimpleString(s) => Ok(Some(s)),
201 RespValue::Null => Ok(None),
202 _ => Err(RedisError::Type(format!(
203 "Cannot convert {:?} to Option<String>",
204 value
205 ))),
206 }
207 }
208}
209
210impl TryFrom<RespValue> for Vec<String> {
211 type Error = RedisError;
212
213 fn try_from(value: RespValue) -> Result<Self, Self::Error> {
214 match value {
215 RespValue::Array(items) => {
216 let mut result = Self::new();
217 for item in items {
218 match item {
219 RespValue::BulkString(b) => {
220 let s = String::from_utf8(b.to_vec())
221 .map_err(|e| RedisError::Type(format!("Invalid UTF-8: {e}")))?;
222 result.push(s);
223 }
224 RespValue::SimpleString(s) => result.push(s),
225 RespValue::Null => {} _ => {
227 return Err(RedisError::Type(format!(
228 "Cannot convert array item {:?} to string",
229 item
230 )))
231 }
232 }
233 }
234 Ok(result)
235 }
236 _ => Err(RedisError::Type(format!(
237 "Cannot convert {:?} to Vec<String>",
238 value
239 ))),
240 }
241 }
242}
243
244impl TryFrom<RespValue> for Vec<i64> {
245 type Error = RedisError;
246
247 fn try_from(value: RespValue) -> Result<Self, Self::Error> {
248 match value {
249 RespValue::Array(items) => {
250 let mut result = Self::new();
251 for item in items {
252 let i = item.as_int()?;
253 result.push(i);
254 }
255 Ok(result)
256 }
257 _ => Err(RedisError::Type(format!(
258 "Cannot convert {:?} to Vec<i64>",
259 value
260 ))),
261 }
262 }
263}