1use crate::evaluator::EvaluationError;
3pub use num_traits::cast::FromPrimitive;
4use pel::runtime::value::Value as PelValue;
5use serde::{Deserialize, Serialize};
6use serde_json::{Map, Number, Value as JsonValue};
7use std::collections::HashMap;
8use std::convert::TryFrom;
9use std::iter::FromIterator;
10
11#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Default)]
13#[serde(from = "serde_json::Value", into = "serde_json::Value")]
14pub enum Value {
15 #[default]
17 Null,
18
19 Bool(bool),
21
22 Number(f64),
24
25 String(String),
27
28 Array(Vec<Value>),
30
31 Object(HashMap<String, Value>),
33}
34
35impl Value {
36 pub fn is_null(&self) -> bool {
38 matches!(self, Value::Null)
39 }
40
41 pub fn as_bool(&self) -> Option<bool> {
44 match self {
45 Value::Bool(b) => Some(*b),
46 _ => None,
47 }
48 }
49
50 pub fn as_str(&self) -> Option<&str> {
53 match self {
54 Value::String(s) => Some(s),
55 _ => None,
56 }
57 }
58
59 pub fn as_num(&self) -> Option<f64> {
62 match self {
63 Value::Number(f) => Some(*f),
64 _ => None,
65 }
66 }
67
68 pub fn as_slice(&self) -> Option<&[Value]> {
71 match self {
72 Value::Array(a) => Some(a),
73 _ => None,
74 }
75 }
76
77 pub fn as_object(&self) -> Option<&HashMap<String, Value>> {
80 match self {
81 Value::Object(o) => Some(o),
82 _ => None,
83 }
84 }
85}
86
87impl From<JsonValue> for Value {
88 fn from(value: JsonValue) -> Self {
89 match value {
90 JsonValue::Null => Value::Null,
91 JsonValue::Bool(val) => val.into_value(),
92 JsonValue::Number(num) => num.as_f64().unwrap_or_default().into_value(),
93 JsonValue::String(str) => str.into_value(),
94 JsonValue::Array(vec) => vec.into_value(),
95 JsonValue::Object(map) => map.into_iter().collect(),
96 }
97 }
98}
99
100impl From<Value> for JsonValue {
101 fn from(value: Value) -> Self {
102 JsonValue::try_from_value(value).unwrap_or_default()
103 }
104}
105
106impl TryFrom<&PelValue> for Value {
107 type Error = EvaluationError;
108
109 fn try_from(value: &PelValue) -> Result<Self, Self::Error> {
110 if value.is_null() {
111 return Ok(Value::Null);
112 };
113
114 if let Some(val) = value.as_bool() {
115 return Ok(val.into_value());
116 };
117
118 if let Some(val) = value.as_f64() {
119 return Ok(val.into_value());
120 };
121
122 if let Some(val) = value.as_str() {
123 return Ok(val.into_value());
124 };
125
126 if let Some(array) = value.as_slice() {
127 let mut vec = Vec::new();
128 for item in array {
129 vec.push(Value::try_from(item)?);
130 }
131 return Ok(vec.into_value());
132 };
133
134 if let Some(obj) = value.as_object() {
135 let mut map = HashMap::new();
136 for (key, val) in obj {
137 map.insert(key.to_string(), Value::try_from(val)?);
138 }
139 return Ok(map.into_value());
140 };
141
142 Err(EvaluationError::TypeMismatch)
143 }
144}
145
146impl IntoValue for JsonValue {
147 fn into_value(self) -> Value {
148 Value::from(self)
149 }
150}
151
152impl Value {
153 pub(crate) fn into_pel(self) -> pel::runtime::value::Value {
154 match self {
155 Value::Null => pel::runtime::value::Value::null(),
156 Value::Bool(val) => pel::runtime::value::Value::bool(val),
157 Value::Number(num) => pel::runtime::value::Value::number(num),
158 Value::String(val) => pel::runtime::value::Value::string(val),
159 Value::Array(vec) => {
160 pel::runtime::value::Value::array(vec.into_iter().map(Value::into_pel).collect())
161 }
162 Value::Object(obj) => pel::runtime::value::Value::object(
163 obj.into_iter()
164 .map(|(key, value)| (key, value.into_pel()))
165 .collect(),
166 ),
167 }
168 }
169}
170
171pub trait IntoValue {
173 fn into_value(self) -> Value;
175}
176
177impl IntoValue for Value {
178 fn into_value(self) -> Value {
179 self
180 }
181}
182
183impl IntoValue for &str {
184 fn into_value(self) -> Value {
185 Value::String(self.to_string())
186 }
187}
188
189impl IntoValue for String {
190 fn into_value(self) -> Value {
191 Value::String(self)
192 }
193}
194
195macro_rules! into_value_num {
196 [$($num_type:ty), +] => {
198 $(
199 impl IntoValue for $num_type {
200 fn into_value(self) -> Value {
201 Value::Number(self as f64)
202 }
203 }
204 )*
205 };
206}
207into_value_num![i8, i16, i32, i64, u8, u16, u32, u64, f32, f64];
208
209impl IntoValue for bool {
210 fn into_value(self) -> Value {
211 Value::Bool(self)
212 }
213}
214
215impl<K: IntoValue> FromIterator<K> for Value {
216 fn from_iter<T: IntoIterator<Item = K>>(iter: T) -> Self {
217 Value::Array(iter.into_iter().map(IntoValue::into_value).collect())
218 }
219}
220
221impl<'a, K: IntoValue> FromIterator<(&'a str, K)> for Value {
222 fn from_iter<T: IntoIterator<Item = (&'a str, K)>>(iter: T) -> Self {
223 Value::Object(
224 iter.into_iter()
225 .map(|(key, val)| (key.to_string(), val.into_value()))
226 .collect(),
227 )
228 }
229}
230
231impl<K: IntoValue> FromIterator<(String, K)> for Value {
232 fn from_iter<T: IntoIterator<Item = (String, K)>>(iter: T) -> Self {
233 Value::Object(
234 iter.into_iter()
235 .map(|(key, val)| (key, val.into_value()))
236 .collect(),
237 )
238 }
239}
240
241impl<K: IntoValue> IntoValue for Vec<K> {
242 fn into_value(self) -> Value {
243 self.into_iter().collect()
244 }
245}
246
247impl<K: IntoValue> IntoValue for HashMap<String, K> {
248 fn into_value(self) -> Value {
249 self.into_iter().collect()
250 }
251}
252
253impl<K: IntoValue> IntoValue for HashMap<&str, K> {
254 fn into_value(self) -> Value {
255 self.into_iter().collect()
256 }
257}
258
259impl<K: IntoValue> IntoValue for Option<K> {
260 fn into_value(self) -> Value {
261 match self {
262 None => Value::Null,
263 Some(k) => k.into_value(),
264 }
265 }
266}
267
268pub trait TryFromValue: Sized {
270 fn try_from_value(value: Value) -> Result<Self, EvaluationError>;
272}
273
274impl TryFromValue for Value {
275 fn try_from_value(value: Value) -> Result<Self, EvaluationError> {
276 Ok(value)
277 }
278}
279
280impl TryFromValue for bool {
281 fn try_from_value(value: Value) -> Result<Self, EvaluationError> {
282 match value {
283 Value::Bool(val) => Ok(val),
284 _ => Err(EvaluationError::TypeMismatch),
285 }
286 }
287}
288macro_rules! try_from_value_num {
289 [$($num_type:ty), +] => {
291 $(
292 impl TryFromValue for $num_type {
293
294 fn try_from_value(value: Value) -> Result<Self, EvaluationError> {
295 match value {
296 Value::Number(num) => {
297 <$num_type>::from_f64(num)
298 .ok_or(EvaluationError::TypeMismatch)
299 }
300 _ => Err(EvaluationError::TypeMismatch)
301 }
302 }
303 }
304 )*
305 };
306}
307
308try_from_value_num![i8, i16, i32, i64, u8, u16, u32, u64, f32, f64];
309
310impl TryFromValue for String {
311 fn try_from_value(value: Value) -> Result<Self, EvaluationError> {
312 match value {
313 Value::String(val) => Ok(val),
314 _ => Err(EvaluationError::TypeMismatch),
315 }
316 }
317}
318
319impl<K: TryFromValue> TryFromValue for Vec<K> {
320 fn try_from_value(value: Value) -> Result<Self, EvaluationError> {
321 match value {
322 Value::Array(array) => array.into_iter().map(K::try_from_value).collect(),
323 _ => Err(EvaluationError::TypeMismatch),
324 }
325 }
326}
327
328impl<K: TryFromValue> TryFromValue for HashMap<String, K> {
329 fn try_from_value(value: Value) -> Result<Self, EvaluationError> {
330 match value {
331 Value::Object(obj) => obj
332 .into_iter()
333 .map(|(key, val)| Ok((key, K::try_from_value(val)?)))
334 .collect(),
335 _ => Err(EvaluationError::TypeMismatch),
336 }
337 }
338}
339
340impl TryFromValue for Map<String, JsonValue> {
341 fn try_from_value(value: Value) -> Result<Self, EvaluationError> {
342 match value {
343 Value::Object(obj) => obj
344 .into_iter()
345 .map(|(key, val)| Ok((key, JsonValue::try_from_value(val)?)))
346 .collect(),
347 _ => Err(EvaluationError::TypeMismatch),
348 }
349 }
350}
351
352impl TryFromValue for JsonValue {
353 fn try_from_value(value: Value) -> Result<Self, EvaluationError> {
354 match value {
355 Value::Null => Ok(JsonValue::Null),
356 Value::Bool(val) => Ok(JsonValue::Bool(val)),
357 Value::Number(n) => Number::from_f64(n)
358 .map(JsonValue::Number)
359 .ok_or(EvaluationError::TypeMismatch),
360 Value::String(s) => Ok(JsonValue::String(s)),
361 Value::Array(_) => Vec::<JsonValue>::try_from_value(value).map(JsonValue::Array),
362 Value::Object(_) => {
363 Map::<String, JsonValue>::try_from_value(value).map(JsonValue::Object)
364 }
365 }
366 }
367}