mf_expression/variable/
conv.rs

1use crate::variable::Variable;
2use crate::vm::helpers::date_time;
3use crate::vm::VMError;
4use chrono::NaiveDateTime;
5use rust_decimal::prelude::ToPrimitive;
6use rust_decimal::Decimal;
7use serde_json::{Number, Value};
8use std::rc::Rc;
9
10impl From<Value> for Variable {
11    fn from(value: Value) -> Self {
12        match value {
13            Value::Null => Variable::Null,
14            Value::Bool(b) => Variable::Bool(b),
15            Value::Number(n) => Variable::Number(
16                Decimal::from_str_exact(n.as_str())
17                    .or_else(|_| Decimal::from_scientific(n.as_str()))
18                    .expect("Allowed number"),
19            ),
20            Value::String(s) => Variable::String(Rc::from(s.as_str())),
21            Value::Array(arr) => Variable::from_array(
22                arr.into_iter().map(Variable::from).collect(),
23            ),
24            Value::Object(obj) => Variable::from_object(
25                obj.into_iter()
26                    .map(|(k, v)| (Rc::from(k.as_str()), Variable::from(v)))
27                    .collect(),
28            ),
29        }
30    }
31}
32
33impl From<&Value> for Variable {
34    fn from(value: &Value) -> Self {
35        match value {
36            Value::Null => Variable::Null,
37            Value::Bool(b) => Variable::Bool(*b),
38            Value::Number(n) => Variable::Number(
39                Decimal::from_str_exact(n.as_str())
40                    .or_else(|_| Decimal::from_scientific(n.as_str()))
41                    .expect("Allowed number"),
42            ),
43            Value::String(s) => Variable::String(Rc::from(s.as_str())),
44            Value::Array(arr) => {
45                Variable::from_array(arr.iter().map(Variable::from).collect())
46            },
47            Value::Object(obj) => Variable::from_object(
48                obj.iter()
49                    .map(|(k, v)| (Rc::from(k.as_str()), Variable::from(v)))
50                    .collect(),
51            ),
52        }
53    }
54}
55
56impl From<Variable> for Value {
57    fn from(value: Variable) -> Self {
58        match value {
59            Variable::Null => Value::Null,
60            Variable::Bool(b) => Value::Bool(b),
61            Variable::Number(n) => Value::Number(
62                Number::from_string_unchecked(n.normalize().to_string()),
63            ),
64            Variable::String(s) => Value::String(s.to_string()),
65            Variable::Array(arr) => {
66                let vec = Rc::try_unwrap(arr)
67                    .map(|a| a.into_inner())
68                    .unwrap_or_else(|s| {
69                        let borrowed = s.borrow();
70                        borrowed.clone()
71                    });
72
73                Value::Array(vec.into_iter().map(Value::from).collect())
74            },
75            Variable::Object(obj) => {
76                let hmap = Rc::try_unwrap(obj)
77                    .map(|a| a.into_inner())
78                    .unwrap_or_else(|s| {
79                        let borrowed = s.borrow();
80                        borrowed.clone()
81                    });
82
83                Value::Object(
84                    hmap.into_iter()
85                        .map(|(k, v)| (k.to_string(), Value::from(v)))
86                        .collect(),
87                )
88            },
89            Variable::Dynamic(d) => d.to_value(),
90        }
91    }
92}
93
94impl TryFrom<&Variable> for NaiveDateTime {
95    type Error = VMError;
96
97    fn try_from(value: &Variable) -> Result<Self, Self::Error> {
98        match value {
99            Variable::String(a) => date_time(a),
100            #[allow(deprecated)]
101            Variable::Number(a) => NaiveDateTime::from_timestamp_opt(
102                a.to_i64().ok_or_else(|| VMError::OpcodeErr {
103                    opcode: "DateManipulation".into(),
104                    message: "Failed to extract date".into(),
105                })?,
106                0,
107            )
108            .ok_or_else(|| VMError::ParseDateTimeErr {
109                timestamp: a.to_string(),
110            }),
111            _ => Err(VMError::OpcodeErr {
112                opcode: "DateManipulation".into(),
113                message: "Unsupported type".into(),
114            }),
115        }
116    }
117}