Skip to main content

yang_db/redis/
value.rs

1/// Redis 值类型
2///
3/// 表示 Redis 中的各种数据类型,提供类型安全的值表示
4#[derive(Debug, Clone, PartialEq)]
5pub enum RedisValue {
6    /// 空值
7    Nil,
8    /// 整数
9    Int(i64),
10    /// 浮点数
11    Float(f64),
12    /// 字符串
13    String(String),
14    /// 字节数组
15    Bytes(Vec<u8>),
16    /// 数组
17    Array(Vec<RedisValue>),
18    /// 布尔值
19    Bool(bool),
20}
21
22impl RedisValue {
23    /// 转换为字符串
24    ///
25    /// # 返回
26    /// - `Some(String)`: 如果值是字符串类型
27    /// - `None`: 如果值不是字符串类型
28    ///
29    /// # 示例
30    /// ```
31    /// use yang_db::RedisValue;
32    ///
33    /// let value = RedisValue::String("hello".to_string());
34    /// assert_eq!(value.as_string(), Some("hello".to_string()));
35    ///
36    /// let nil = RedisValue::Nil;
37    /// assert_eq!(nil.as_string(), None);
38    /// ```
39    pub fn as_string(&self) -> Option<String> {
40        match self {
41            RedisValue::String(s) => Some(s.clone()),
42            _ => None,
43        }
44    }
45
46    /// 转换为整数
47    ///
48    /// # 返回
49    /// - `Some(i64)`: 如果值是整数类型
50    /// - `None`: 如果值不是整数类型
51    pub fn as_i64(&self) -> Option<i64> {
52        match self {
53            RedisValue::Int(i) => Some(*i),
54            _ => None,
55        }
56    }
57
58    /// 转换为浮点数
59    ///
60    /// # 返回
61    /// - `Some(f64)`: 如果值是浮点数类型
62    /// - `None`: 如果值不是浮点数类型
63    pub fn as_f64(&self) -> Option<f64> {
64        match self {
65            RedisValue::Float(f) => Some(*f),
66            _ => None,
67        }
68    }
69
70    /// 转换为布尔值
71    ///
72    /// # 返回
73    /// - `Some(bool)`: 如果值是布尔类型
74    /// - `None`: 如果值不是布尔类型
75    pub fn as_bool(&self) -> Option<bool> {
76        match self {
77            RedisValue::Bool(b) => Some(*b),
78            _ => None,
79        }
80    }
81
82    /// 转换为字节数组引用
83    ///
84    /// # 返回
85    /// - `Some(&[u8])`: 如果值是字节数组类型
86    /// - `None`: 如果值不是字节数组类型
87    pub fn as_bytes(&self) -> Option<&[u8]> {
88        match self {
89            RedisValue::Bytes(b) => Some(b.as_slice()),
90            _ => None,
91        }
92    }
93
94    /// 转换为数组引用
95    ///
96    /// # 返回
97    /// - `Some(&[RedisValue])`: 如果值是数组类型
98    /// - `None`: 如果值不是数组类型
99    pub fn as_array(&self) -> Option<&[RedisValue]> {
100        match self {
101            RedisValue::Array(arr) => Some(arr.as_slice()),
102            _ => None,
103        }
104    }
105
106    /// 检查是否为 Nil
107    ///
108    /// # 返回
109    /// - `true`: 如果值是 Nil
110    /// - `false`: 如果值不是 Nil
111    pub fn is_nil(&self) -> bool {
112        matches!(self, RedisValue::Nil)
113    }
114}
115
116// 实现 From trait 支持自动转换
117impl From<String> for RedisValue {
118    fn from(s: String) -> Self {
119        RedisValue::String(s)
120    }
121}
122
123impl From<&str> for RedisValue {
124    fn from(s: &str) -> Self {
125        RedisValue::String(s.to_string())
126    }
127}
128
129impl From<i64> for RedisValue {
130    fn from(i: i64) -> Self {
131        RedisValue::Int(i)
132    }
133}
134
135impl From<i32> for RedisValue {
136    fn from(i: i32) -> Self {
137        RedisValue::Int(i as i64)
138    }
139}
140
141impl From<f64> for RedisValue {
142    fn from(f: f64) -> Self {
143        RedisValue::Float(f)
144    }
145}
146
147impl From<bool> for RedisValue {
148    fn from(b: bool) -> Self {
149        RedisValue::Bool(b)
150    }
151}
152
153impl From<Vec<u8>> for RedisValue {
154    fn from(bytes: Vec<u8>) -> Self {
155        RedisValue::Bytes(bytes)
156    }
157}
158
159// 实现 redis::Value 到 RedisValue 的转换
160impl From<redis::Value> for RedisValue {
161    fn from(value: redis::Value) -> Self {
162        match value {
163            redis::Value::Nil => RedisValue::Nil,
164            redis::Value::Int(i) => RedisValue::Int(i),
165            redis::Value::BulkString(bytes) => {
166                // 尝试转换为 UTF-8 字符串
167                match String::from_utf8(bytes.clone()) {
168                    Ok(s) => RedisValue::String(s),
169                    Err(_) => RedisValue::Bytes(bytes),
170                }
171            }
172            redis::Value::Array(values) => {
173                RedisValue::Array(values.into_iter().map(RedisValue::from).collect())
174            }
175            redis::Value::SimpleString(s) => RedisValue::String(s),
176            redis::Value::Okay => RedisValue::Bool(true),
177            redis::Value::Map(_) => {
178                // Map 类型转换为字符串表示
179                RedisValue::String(format!("{:?}", value))
180            }
181            redis::Value::Attribute { .. } => {
182                // Attribute 类型转换为字符串表示
183                RedisValue::String(format!("{:?}", value))
184            }
185            redis::Value::Set(_) => {
186                // Set 类型转换为字符串表示
187                RedisValue::String(format!("{:?}", value))
188            }
189            redis::Value::Double(f) => RedisValue::Float(f),
190            redis::Value::Boolean(b) => RedisValue::Bool(b),
191            redis::Value::VerbatimString { .. } => {
192                // VerbatimString 转换为字符串表示
193                RedisValue::String(format!("{:?}", value))
194            }
195            redis::Value::BigNumber(_) => {
196                // BigNumber 转换为字符串表示
197                RedisValue::String(format!("{:?}", value))
198            }
199            redis::Value::Push { .. } => {
200                // Push 类型转换为字符串表示
201                RedisValue::String(format!("{:?}", value))
202            }
203            // 其他未知类型
204            _ => RedisValue::String(format!("{:?}", value)),
205        }
206    }
207}
208
209#[cfg(test)]
210mod tests {
211    use super::*;
212
213    #[test]
214    fn test_redis_value_nil() {
215        let value = RedisValue::Nil;
216        assert!(value.is_nil());
217        assert_eq!(value.as_string(), None);
218        assert_eq!(value.as_i64(), None);
219    }
220
221    #[test]
222    fn test_redis_value_int() {
223        let value = RedisValue::Int(42);
224        assert!(!value.is_nil());
225        assert_eq!(value.as_i64(), Some(42));
226        assert_eq!(value.as_string(), None);
227    }
228
229    #[test]
230    fn test_redis_value_float() {
231        let value = RedisValue::Float(123.456);
232        assert_eq!(value.as_f64(), Some(123.456));
233        assert_eq!(value.as_i64(), None);
234    }
235
236    #[test]
237    fn test_redis_value_string() {
238        let value = RedisValue::String("hello".to_string());
239        assert_eq!(value.as_string(), Some("hello".to_string()));
240        assert_eq!(value.as_i64(), None);
241    }
242
243    #[test]
244    fn test_redis_value_bool() {
245        let value = RedisValue::Bool(true);
246        assert_eq!(value.as_bool(), Some(true));
247        assert_eq!(value.as_string(), None);
248    }
249
250    #[test]
251    fn test_redis_value_bytes() {
252        let bytes = vec![1, 2, 3, 4];
253        let value = RedisValue::Bytes(bytes.clone());
254        assert_eq!(value.as_bytes(), Some(bytes.as_slice()));
255        assert_eq!(value.as_string(), None);
256    }
257
258    #[test]
259    fn test_redis_value_array() {
260        let arr = vec![
261            RedisValue::Int(1),
262            RedisValue::String("test".to_string()),
263            RedisValue::Nil,
264        ];
265        let value = RedisValue::Array(arr.clone());
266        assert_eq!(value.as_array(), Some(arr.as_slice()));
267        assert_eq!(value.as_string(), None);
268    }
269
270    #[test]
271    fn test_from_string() {
272        let value: RedisValue = "hello".into();
273        assert_eq!(value, RedisValue::String("hello".to_string()));
274
275        let value: RedisValue = String::from("world").into();
276        assert_eq!(value, RedisValue::String("world".to_string()));
277    }
278
279    #[test]
280    fn test_from_int() {
281        let value: RedisValue = 42i64.into();
282        assert_eq!(value, RedisValue::Int(42));
283
284        let value: RedisValue = 100i32.into();
285        assert_eq!(value, RedisValue::Int(100));
286    }
287
288    #[test]
289    fn test_from_float() {
290        let value: RedisValue = 123.456f64.into();
291        assert_eq!(value, RedisValue::Float(123.456));
292    }
293
294    #[test]
295    fn test_from_bool() {
296        let value: RedisValue = true.into();
297        assert_eq!(value, RedisValue::Bool(true));
298
299        let value: RedisValue = false.into();
300        assert_eq!(value, RedisValue::Bool(false));
301    }
302
303    #[test]
304    fn test_from_bytes() {
305        let bytes = vec![1, 2, 3];
306        let value: RedisValue = bytes.clone().into();
307        assert_eq!(value, RedisValue::Bytes(bytes));
308    }
309
310    #[test]
311    fn test_from_redis_value_nil() {
312        let redis_val = redis::Value::Nil;
313        let value: RedisValue = redis_val.into();
314        assert_eq!(value, RedisValue::Nil);
315    }
316
317    #[test]
318    fn test_from_redis_value_int() {
319        let redis_val = redis::Value::Int(42);
320        let value: RedisValue = redis_val.into();
321        assert_eq!(value, RedisValue::Int(42));
322    }
323
324    #[test]
325    fn test_from_redis_value_data_utf8() {
326        let redis_val = redis::Value::BulkString(b"hello".to_vec());
327        let value: RedisValue = redis_val.into();
328        assert_eq!(value, RedisValue::String("hello".to_string()));
329    }
330
331    #[test]
332    fn test_from_redis_value_data_binary() {
333        let bytes = vec![0xFF, 0xFE, 0xFD];
334        let redis_val = redis::Value::BulkString(bytes.clone());
335        let value: RedisValue = redis_val.into();
336        assert_eq!(value, RedisValue::Bytes(bytes));
337    }
338
339    #[test]
340    fn test_from_redis_value_bulk() {
341        let redis_val = redis::Value::Array(vec![
342            redis::Value::Int(1),
343            redis::Value::BulkString(b"test".to_vec()),
344        ]);
345        let value: RedisValue = redis_val.into();
346
347        if let RedisValue::Array(arr) = value {
348            assert_eq!(arr.len(), 2);
349            assert_eq!(arr[0], RedisValue::Int(1));
350            assert_eq!(arr[1], RedisValue::String("test".to_string()));
351        } else {
352            panic!("Expected Array");
353        }
354    }
355
356    #[test]
357    fn test_from_redis_value_status() {
358        let redis_val = redis::Value::SimpleString("OK".to_string());
359        let value: RedisValue = redis_val.into();
360        assert_eq!(value, RedisValue::String("OK".to_string()));
361    }
362
363    #[test]
364    fn test_from_redis_value_okay() {
365        let redis_val = redis::Value::Okay;
366        let value: RedisValue = redis_val.into();
367        assert_eq!(value, RedisValue::Bool(true));
368    }
369
370    #[test]
371    fn test_clone() {
372        let value = RedisValue::String("test".to_string());
373        let cloned = value.clone();
374        assert_eq!(value, cloned);
375    }
376
377    #[test]
378    fn test_debug() {
379        let value = RedisValue::Int(42);
380        let debug_str = format!("{:?}", value);
381        assert!(debug_str.contains("Int"));
382        assert!(debug_str.contains("42"));
383    }
384
385    #[test]
386    fn test_partial_eq() {
387        assert_eq!(RedisValue::Nil, RedisValue::Nil);
388        assert_eq!(RedisValue::Int(42), RedisValue::Int(42));
389        assert_ne!(RedisValue::Int(42), RedisValue::Int(43));
390        assert_ne!(RedisValue::Int(42), RedisValue::String("42".to_string()));
391    }
392}