1#[cfg(feature = "time")]
2use chrono::Duration;
3use thiserror::Error;
4
5use crate::Value;
6
7#[derive(Debug, Clone, Error)]
8#[error("unable to convert value to json: {0:?}")]
9pub enum ConvertToJsonError<'a> {
10 #[error("unable to convert value to json: {0:?}")]
13 Value(&'a Value),
14
15 #[cfg(feature = "time")]
16 #[error("duration too large to convert to nanoseconds: {0:?}")]
20 DurationOverflow(&'a Duration),
21}
22
23impl Value {
24 pub fn json(&self) -> Result<serde_json::Value, ConvertToJsonError<'_>> {
37 Ok(match *self {
38 Value::List(ref vec) => {
39 serde_json::Value::Array(vec.iter().map(|v| v.json()).collect::<Result<Vec<_>, _>>()?)
40 }
41 Value::Map(ref map) => {
42 let mut obj = serde_json::Map::new();
43 for (k, v) in map.map.iter() {
44 obj.insert(k.to_string(), v.json()?);
45 }
46 serde_json::Value::Object(obj)
47 }
48 Value::Int(i) => i.into(),
49 Value::Float(f) => f.into(),
51 Value::String(ref s) => s.to_string().into(),
52 Value::Bool(b) => b.into(),
53 Value::Bytes(ref b) => base64::encode(b.as_slice(), base64::Alphabet::Standard).into(),
54 Value::Null => serde_json::Value::Null,
55 #[cfg(feature = "time")]
56 Value::Timestamp(ref dt) => dt.to_rfc3339().into(),
57 #[cfg(feature = "time")]
58 Value::Duration(ref v) => serde_json::Value::Number(serde_json::Number::from(
59 v.num_nanoseconds().ok_or(ConvertToJsonError::DurationOverflow(v))?,
60 )),
61 _ => return Err(ConvertToJsonError::Value(self)),
62 })
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use std::collections::HashMap;
69
70 #[cfg(feature = "time")]
71 use chrono::Duration;
72 use serde_json::json;
73
74 use crate::{Value as CelValue, objects::Map};
75
76 #[test]
77 fn test_cel_value_to_json() {
78 let mut tests = vec![
79 (json!("hello"), CelValue::String("hello".to_string().into())),
80 (json!(42), CelValue::Int(42)),
81 (json!(42.0), CelValue::Float(42.0)),
82 (json!(true), CelValue::Bool(true)),
83 (json!(null), CelValue::Null),
84 (
85 json!([true, null]),
86 CelValue::List(vec![CelValue::Bool(true), CelValue::Null].into()),
87 ),
88 (
89 json!({"hello": "world"}),
90 CelValue::Map(Map::from(HashMap::from([(
91 "hello".to_string(),
92 CelValue::String("world".to_string().into()),
93 )]))),
94 ),
95 ];
96
97 #[cfg(feature = "time")]
98 if true {
99 tests.push((json!(1_000_000_000), CelValue::Duration(Duration::seconds(1))));
100 }
101
102 for (expected, value) in tests.iter() {
103 assert_eq!(value.json().unwrap(), *expected, "{value:?}={expected:?}");
104 }
105 }
106}