1use chrono::{DateTime, FixedOffset};
4use ordered_float::OrderedFloat;
5
6#[derive(Clone, Debug, PartialEq)]
10pub enum Value {
11 String(String),
13
14 Double(OrderedFloat<f64>),
16
17 Bool(bool),
19
20 Long(i64),
22
23 UnsignedLong(u64),
25
26 Duration(chrono::Duration),
28
29 Base64Binary(Vec<u8>),
31
32 TimeRFC(DateTime<FixedOffset>),
34
35 Null,
37}
38
39impl Value {
40 pub fn as_string(&self) -> Option<&str> {
42 match self {
43 Value::String(s) => Some(s),
44 _ => None,
45 }
46 }
47
48 pub fn string(&self) -> Option<String> {
50 match self {
51 Value::String(s) => Some(s.clone()),
52 _ => None,
53 }
54 }
55
56 pub fn as_double(&self) -> Option<f64> {
58 match self {
59 Value::Double(f) => Some(f.into_inner()),
60 _ => None,
61 }
62 }
63
64 pub fn as_bool(&self) -> Option<bool> {
66 match self {
67 Value::Bool(b) => Some(*b),
68 _ => None,
69 }
70 }
71
72 pub fn as_long(&self) -> Option<i64> {
74 match self {
75 Value::Long(i) => Some(*i),
76 _ => None,
77 }
78 }
79
80 pub fn as_unsigned_long(&self) -> Option<u64> {
82 match self {
83 Value::UnsignedLong(u) => Some(*u),
84 _ => None,
85 }
86 }
87
88 pub fn as_duration(&self) -> Option<&chrono::Duration> {
90 match self {
91 Value::Duration(d) => Some(d),
92 _ => None,
93 }
94 }
95
96 pub fn as_binary(&self) -> Option<&[u8]> {
98 match self {
99 Value::Base64Binary(b) => Some(b),
100 _ => None,
101 }
102 }
103
104 pub fn as_time(&self) -> Option<&DateTime<FixedOffset>> {
106 match self {
107 Value::TimeRFC(t) => Some(t),
108 _ => None,
109 }
110 }
111
112 pub fn is_null(&self) -> bool {
114 matches!(self, Value::Null)
115 }
116}
117
118impl std::fmt::Display for Value {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 match self {
121 Value::String(s) => write!(f, "{}", s),
122 Value::Double(d) => write!(f, "{}", d),
123 Value::Bool(b) => write!(f, "{}", b),
124 Value::Long(i) => write!(f, "{}", i),
125 Value::UnsignedLong(u) => write!(f, "{}", u),
126 Value::Duration(d) => write!(f, "{}ns", d.num_nanoseconds().unwrap_or(0)),
127 Value::Base64Binary(b) => write!(f, "<binary {} bytes>", b.len()),
128 Value::TimeRFC(t) => write!(f, "{}", t.to_rfc3339()),
129 Value::Null => write!(f, "null"),
130 }
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
143 fn test_as_string() {
144 let v = Value::String("hello".to_string());
145 assert_eq!(v.as_string(), Some("hello"));
146
147 assert_eq!(Value::Long(42).as_string(), None);
149 assert_eq!(Value::Null.as_string(), None);
150 }
151
152 #[test]
153 fn test_string() {
154 let v = Value::String("hello".to_string());
155 assert_eq!(v.string(), Some("hello".to_string()));
156
157 assert_eq!(Value::Long(42).string(), None);
159 assert_eq!(Value::Null.string(), None);
160 }
161
162 #[test]
163 fn test_as_double() {
164 let v = Value::Double(OrderedFloat::from(2.72));
165 assert_eq!(v.as_double(), Some(2.72));
166
167 assert_eq!(Value::Long(42).as_double(), None);
169 assert_eq!(Value::String("2.72".to_string()).as_double(), None);
170 assert_eq!(Value::Null.as_double(), None);
171 }
172
173 #[test]
174 fn test_as_bool() {
175 assert_eq!(Value::Bool(true).as_bool(), Some(true));
176 assert_eq!(Value::Bool(false).as_bool(), Some(false));
177
178 assert_eq!(Value::Long(1).as_bool(), None);
180 assert_eq!(Value::String("true".to_string()).as_bool(), None);
181 assert_eq!(Value::Null.as_bool(), None);
182 }
183
184 #[test]
185 fn test_as_long() {
186 assert_eq!(Value::Long(42).as_long(), Some(42));
187 assert_eq!(Value::Long(-100).as_long(), Some(-100));
188 assert_eq!(Value::Long(i64::MAX).as_long(), Some(i64::MAX));
189
190 assert_eq!(Value::UnsignedLong(42).as_long(), None);
192 assert_eq!(Value::Double(OrderedFloat::from(42.0)).as_long(), None);
193 assert_eq!(Value::Null.as_long(), None);
194 }
195
196 #[test]
197 fn test_as_unsigned_long() {
198 assert_eq!(Value::UnsignedLong(42).as_unsigned_long(), Some(42));
199 assert_eq!(
200 Value::UnsignedLong(u64::MAX).as_unsigned_long(),
201 Some(u64::MAX)
202 );
203
204 assert_eq!(Value::Long(42).as_unsigned_long(), None);
206 assert_eq!(
207 Value::Double(OrderedFloat::from(42.0)).as_unsigned_long(),
208 None
209 );
210 assert_eq!(Value::Null.as_unsigned_long(), None);
211 }
212
213 #[test]
214 fn test_as_duration() {
215 let dur = chrono::Duration::nanoseconds(1_000_000_000);
216 let v = Value::Duration(dur);
217 assert!(v.as_duration().is_some());
218 assert_eq!(v.as_duration().unwrap().num_seconds(), 1);
219
220 assert!(Value::Long(1000).as_duration().is_none());
222 assert!(Value::Null.as_duration().is_none());
223 }
224
225 #[test]
226 fn test_as_binary() {
227 let v = Value::Base64Binary(vec![1, 2, 3, 4]);
228 assert_eq!(v.as_binary(), Some(&[1u8, 2, 3, 4][..]));
229
230 assert!(Value::String("data".to_string()).as_binary().is_none());
232 assert!(Value::Null.as_binary().is_none());
233 }
234
235 #[test]
236 fn test_as_time() {
237 let dt = DateTime::parse_from_rfc3339("2023-11-14T12:00:00Z").unwrap();
238 let v = Value::TimeRFC(dt);
239 assert!(v.as_time().is_some());
240
241 assert!(Value::String("2023-11-14".to_string()).as_time().is_none());
243 assert!(Value::Long(1699963200).as_time().is_none());
244 assert!(Value::Null.as_time().is_none());
245 }
246
247 #[test]
248 fn test_is_null() {
249 assert!(Value::Null.is_null());
250
251 assert!(!Value::String("".to_string()).is_null());
253 assert!(!Value::Long(0).is_null());
254 assert!(!Value::Bool(false).is_null());
255 assert!(!Value::Double(OrderedFloat::from(0.0)).is_null());
256 }
257
258 #[test]
263 fn test_display_string() {
264 let v = Value::String("hello world".to_string());
265 assert_eq!(v.to_string(), "hello world");
266 }
267
268 #[test]
269 fn test_display_double() {
270 let v = Value::Double(OrderedFloat::from(1.23456));
271 assert!(v.to_string().starts_with("1.23"));
272 }
273
274 #[test]
275 fn test_display_bool() {
276 assert_eq!(Value::Bool(true).to_string(), "true");
277 assert_eq!(Value::Bool(false).to_string(), "false");
278 }
279
280 #[test]
281 fn test_display_long() {
282 assert_eq!(Value::Long(42).to_string(), "42");
283 assert_eq!(Value::Long(-100).to_string(), "-100");
284 }
285
286 #[test]
287 fn test_display_unsigned_long() {
288 assert_eq!(Value::UnsignedLong(42).to_string(), "42");
289 assert_eq!(
290 Value::UnsignedLong(u64::MAX).to_string(),
291 "18446744073709551615"
292 );
293 }
294
295 #[test]
296 fn test_display_duration() {
297 let dur = chrono::Duration::nanoseconds(1_500_000_000);
298 let v = Value::Duration(dur);
299 assert_eq!(v.to_string(), "1500000000ns");
300 }
301
302 #[test]
303 fn test_display_base64_binary() {
304 let v = Value::Base64Binary(vec![1, 2, 3, 4, 5]);
305 assert_eq!(v.to_string(), "<binary 5 bytes>");
306 }
307
308 #[test]
309 fn test_display_time_rfc() {
310 let dt = DateTime::parse_from_rfc3339("2023-11-14T12:30:45Z").unwrap();
311 let v = Value::TimeRFC(dt);
312 assert!(v.to_string().contains("2023-11-14"));
313 assert!(v.to_string().contains("12:30:45"));
314 }
315
316 #[test]
317 fn test_display_null() {
318 assert_eq!(Value::Null.to_string(), "null");
319 }
320
321 #[test]
326 fn test_value_equality() {
327 assert_eq!(
328 Value::String("a".to_string()),
329 Value::String("a".to_string())
330 );
331 assert_ne!(
332 Value::String("a".to_string()),
333 Value::String("b".to_string())
334 );
335
336 assert_eq!(Value::Long(42), Value::Long(42));
337 assert_ne!(Value::Long(42), Value::Long(43));
338
339 assert_eq!(Value::Null, Value::Null);
340
341 assert_ne!(Value::Long(42), Value::UnsignedLong(42));
343 assert_ne!(Value::String("42".to_string()), Value::Long(42));
344 }
345
346 #[test]
347 fn test_value_clone() {
348 let original = Value::String("test".to_string());
349 let cloned = original.clone();
350 assert_eq!(original, cloned);
351
352 let original = Value::Base64Binary(vec![1, 2, 3]);
353 let cloned = original.clone();
354 assert_eq!(original, cloned);
355 }
356}