pnwkit_core/
value.rs

1use serde::{de::Visitor, Deserialize, Serialize};
2
3use crate::{
4    data::{Object, ObjectVisitor},
5    Variable,
6};
7
8#[derive(Clone, Debug)]
9pub enum Value {
10    None,
11    Bool(bool),
12    Int(i64),
13    Float(f64),
14    String(String),
15    Variable(Variable),
16    Object(Object),
17    Array(Vec<Value>),
18}
19
20impl<'de> Deserialize<'de> for Value {
21    fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
22    where
23        D: serde::Deserializer<'de>,
24    {
25        deserializer.deserialize_any(ValueVisitor::new())
26    }
27}
28
29#[derive(Clone, Copy, Debug)]
30struct ValueVisitor {}
31
32impl ValueVisitor {
33    fn new() -> Self {
34        Self {}
35    }
36}
37
38impl<'de> Visitor<'de> for ValueVisitor {
39    type Value = Value;
40
41    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
42        formatter.write_str("any value")
43    }
44
45    fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
46    where
47        E: serde::de::Error,
48    {
49        Ok(v.into())
50    }
51
52    fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
53    where
54        E: serde::de::Error,
55    {
56        Ok(v.into())
57    }
58
59    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
60    where
61        E: serde::de::Error,
62    {
63        Ok(v.into())
64    }
65
66    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
67    where
68        E: serde::de::Error,
69    {
70        Ok(v.into())
71    }
72
73    fn visit_none<E>(self) -> Result<Self::Value, E>
74    where
75        E: serde::de::Error,
76    {
77        Ok(Value::None)
78    }
79
80    fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
81    where
82        E: serde::de::Error,
83    {
84        Ok(v.into())
85    }
86
87    fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
88    where
89        A: serde::de::MapAccess<'de>,
90    {
91        Ok(ObjectVisitor::new().visit_map(map)?.into())
92    }
93
94    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
95    where
96        E: serde::de::Error,
97    {
98        Ok(v.into())
99    }
100
101    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
102    where
103        E: serde::de::Error,
104    {
105        Ok(v.into())
106    }
107
108    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
109    where
110        A: serde::de::SeqAccess<'de>,
111    {
112        let mut vec: Vec<Value> = Vec::new();
113        while let Some(value) = seq.next_element::<Value>()? {
114            vec.push(value);
115        }
116        Ok(vec.into())
117    }
118
119    fn visit_unit<E>(self) -> Result<Self::Value, E>
120    where
121        E: serde::de::Error,
122    {
123        Ok(Value::None)
124    }
125}
126
127impl Serialize for Value {
128    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
129    where
130        S: serde::Serializer,
131    {
132        match self {
133            Value::None => serializer.serialize_none(),
134            Value::Bool(b) => serializer.serialize_bool(*b),
135            Value::Int(i) => serializer.serialize_i64(*i),
136            Value::Float(f) => serializer.serialize_f64(*f),
137            Value::String(s) => serializer.serialize_str(s),
138            Value::Variable(v) => v.serialize(serializer),
139            Value::Object(o) => o.serialize(serializer),
140            Value::Array(a) => a.serialize(serializer),
141        }
142    }
143}
144
145macro_rules! into {
146    ($($v:ident, $e:ident)*) => {
147        $(
148            impl From<$v> for Value {
149                fn from(v: $v) -> Self {
150                    Self::$e(v.try_into().unwrap())
151                }
152            }
153        )*
154    };
155}
156
157macro_rules! from {
158    ($($f:ident, $v:ident)*) => {
159        $(
160            impl From<Value> for $v {
161                fn from(v: Value) -> Self {
162                    paste::paste! {
163                        v.[<as_ $f>]().unwrap()
164                    }
165                }
166            }
167
168            impl From<&Value> for $v {
169                fn from(v: &Value) -> Self {
170                    paste::paste! {
171                        v.[<as_ $f>]().unwrap()
172                    }
173                }
174            }
175
176            impl From<Value> for Option<$v> {
177                fn from(v: Value) -> Self {
178                    match v {
179                        Value::None => None,
180                        _ => Some(paste::paste! { v.[<as_ $f>]().unwrap() }),
181                    }
182                }
183            }
184
185            impl From<&Value> for Option<$v> {
186                fn from(v: &Value) -> Self {
187                    match v {
188                        Value::None => None,
189                        _ => Some(paste::paste! { v.[<as_ $f>]().unwrap() }),
190                    }
191                }
192            }
193        )*
194    };
195}
196
197type VecValue = Vec<Value>;
198
199into!(
200    bool, Bool
201    i8, Int
202    i16, Int
203    i32, Int
204    i64, Int
205    u64, Int
206    f64, Float
207    String, String
208    Object, Object
209    VecValue, Array
210);
211
212from!(
213    bool, bool
214    i8, i8
215    i16, i16
216    i32, i32
217    i64, i64
218    u64, u64
219    f64, f64
220    string, String
221    object, Object
222    array, VecValue
223);
224
225#[cfg(feature = "uuid")]
226use uuid::Uuid;
227
228#[cfg(feature = "uuid")]
229from!(uuid, Uuid);
230
231#[cfg(feature = "bigdecimal")]
232use bigdecimal::BigDecimal;
233
234#[cfg(feature = "bigdecimal")]
235from!(bigdecimal, BigDecimal);
236
237#[cfg(feature = "time")]
238use time::OffsetDateTime;
239
240#[cfg(feature = "time")]
241from!(time, OffsetDateTime);
242
243#[cfg(feature = "chrono")]
244use chrono::{DateTime, Utc};
245
246#[cfg(feature = "chrono")]
247type Chrono = DateTime<Utc>;
248#[cfg(feature = "chrono")]
249from!(chrono, Chrono);
250
251impl From<Variable> for Value {
252    fn from(v: Variable) -> Self {
253        Self::Variable(v)
254    }
255}
256
257impl From<&str> for Value {
258    fn from(v: &str) -> Self {
259        Self::String(v.into())
260    }
261}
262
263impl<'a> From<&'a Value> for &'a str {
264    fn from(v: &'a Value) -> Self {
265        v.as_str().unwrap()
266    }
267}
268
269impl<'a> From<&'a Value> for Option<&'a str> {
270    fn from(v: &'a Value) -> Self {
271        match v {
272            Value::None => None,
273            _ => Some(v.as_str().unwrap()),
274        }
275    }
276}
277
278impl Value {
279    pub fn as_i8(&self) -> Option<i8> {
280        match self {
281            Value::Int(v) => Some(*v as i8),
282            Value::Float(v) => Some(*v as i8),
283            Value::String(v) => v.parse().ok(),
284            _ => None,
285        }
286    }
287
288    pub fn as_i16(&self) -> Option<i16> {
289        match self {
290            Value::Int(v) => Some(*v as i16),
291            Value::Float(v) => Some(*v as i16),
292            Value::String(v) => v.parse().ok(),
293            _ => None,
294        }
295    }
296
297    pub fn as_i32(&self) -> Option<i32> {
298        match self {
299            Value::Int(v) => Some(*v as i32),
300            Value::Float(v) => Some(*v as i32),
301            Value::String(v) => v.parse().ok(),
302            _ => None,
303        }
304    }
305
306    pub fn as_i64(&self) -> Option<i64> {
307        match self {
308            Value::Int(v) => Some(*v),
309            Value::Float(v) => Some(*v as i64),
310            Value::String(v) => v.parse().ok(),
311            _ => None,
312        }
313    }
314
315    pub fn as_u64(&self) -> Option<u64> {
316        match self {
317            Value::Int(v) => Some(*v as u64),
318            Value::Float(v) => Some(*v as u64),
319            Value::String(v) => v.parse().ok(),
320            _ => None,
321        }
322    }
323
324    pub fn as_f64(&self) -> Option<f64> {
325        match self {
326            Value::Int(v) => Some(*v as f64),
327            Value::Float(v) => Some(*v),
328            Value::String(v) => v.parse().ok(),
329            _ => None,
330        }
331    }
332
333    pub fn as_bool(&self) -> Option<bool> {
334        match self {
335            Value::Bool(v) => Some(*v),
336            Value::Int(v) => Some(*v != 0),
337            _ => None,
338        }
339    }
340
341    pub fn as_string(&self) -> Option<String> {
342        match self {
343            Value::String(v) => Some(v.clone()),
344            _ => None,
345        }
346    }
347
348    pub fn as_str(&self) -> Option<&str> {
349        match self {
350            Value::String(v) => Some(v),
351            _ => None,
352        }
353    }
354
355    pub fn as_object(&self) -> Option<Object> {
356        match self {
357            Value::Object(v) => Some(v.clone()),
358            _ => None,
359        }
360    }
361
362    pub fn parse_object(&self) -> Option<Object> {
363        match self {
364            Value::Object(v) => Some(v.clone()),
365            Value::String(v) => serde_json::from_str(v).ok(),
366            _ => None,
367        }
368    }
369
370    pub fn as_array(&self) -> Option<Vec<Value>> {
371        match self {
372            Value::Array(v) => Some(v.clone()),
373            _ => None,
374        }
375    }
376
377    #[cfg(feature = "uuid")]
378    pub fn as_uuid(&self) -> Option<uuid::Uuid> {
379        match self {
380            Value::String(v) => uuid::Uuid::parse_str(v.as_str()).ok(),
381            _ => None,
382        }
383    }
384
385    #[cfg(feature = "bigdecimal")]
386    pub fn as_bigdecimal(&self) -> Option<bigdecimal::BigDecimal> {
387        use std::str::FromStr;
388
389        use bigdecimal::FromPrimitive;
390
391        match self {
392            Value::Float(v) => bigdecimal::BigDecimal::from_f64(*v),
393            Value::Int(v) => bigdecimal::BigDecimal::from_i64(*v),
394            Value::String(v) => bigdecimal::BigDecimal::from_str(v.as_str()).ok(),
395            _ => None,
396        }
397    }
398
399    #[cfg(feature = "time")]
400    pub fn as_time(&self) -> Option<time::OffsetDateTime> {
401        match self {
402            Value::String(v) => {
403                if v.as_str() == "0000-00-00" || v.starts_with('-') {
404                    Some(time::OffsetDateTime::UNIX_EPOCH)
405                } else if v.len() == 10 {
406                    time::OffsetDateTime::parse(
407                        format!("{}T00:00:00Z", v).as_str(),
408                        &time::format_description::well_known::Iso8601::DEFAULT,
409                    )
410                    .ok()
411                } else {
412                    time::OffsetDateTime::parse(
413                        v.as_str(),
414                        &time::format_description::well_known::Iso8601::DEFAULT,
415                    )
416                    .ok()
417                }
418            },
419            _ => None,
420        }
421    }
422
423    #[cfg(feature = "chrono")]
424    pub fn as_chrono(&self) -> Option<chrono::DateTime<chrono::Utc>> {
425        match self {
426            Value::String(v) => {
427                if v.as_str() == "0000-00-00" || v.starts_with('-') {
428                    Some(chrono::DateTime::<chrono::Utc>::MIN_UTC)
429                } else if v.len() == 10 {
430                    chrono::DateTime::parse_from_rfc3339(format!("{}T00:00:00Z", v).as_str())
431                        .ok()
432                        .map(|v| v.with_timezone(&chrono::Utc))
433                } else {
434                    chrono::DateTime::parse_from_rfc3339(v.as_str())
435                        .ok()
436                        .map(|v| v.with_timezone(&chrono::Utc))
437                }
438            },
439            _ => None,
440        }
441    }
442
443    pub fn string_to_value(&self) -> Option<Value> {
444        if let Some(s) = self.as_str() {
445            serde_json::from_str::<Value>(s).ok()
446        } else {
447            Some(self.clone())
448        }
449    }
450
451    pub fn is_string(&self) -> bool {
452        matches!(self, Value::String(_))
453    }
454}