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