1use core::fmt;
9
10use serde::de::{self, MapAccess, SeqAccess, Visitor};
11use serde::ser::{SerializeMap, SerializeSeq};
12use serde::{Deserialize, Deserializer, Serialize, Serializer};
13use vertep_core::datamodel::Value;
14
15const TAG: &str = "$vt";
16
17#[derive(Clone, Debug, PartialEq)]
19pub struct JsonValue(pub Value);
20
21impl Serialize for JsonValue {
22 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
23 ser(&self.0, s)
24 }
25}
26
27fn tagged<S: Serializer>(tag: &str, s: S) -> Result<S::Ok, S::Error> {
28 let mut m = s.serialize_map(Some(1))?;
29 m.serialize_entry(TAG, tag)?;
30 m.end()
31}
32
33fn ser<S: Serializer>(v: &Value, s: S) -> Result<S::Ok, S::Error> {
34 match v {
35 Value::Undefined => tagged("undefined", s),
36 Value::Null => s.serialize_unit(),
37 Value::Bool(b) => s.serialize_bool(*b),
38 Value::Number(n) if n.is_nan() => tagged("NaN", s),
39 Value::Number(n) if n.is_infinite() && *n > 0.0 => tagged("Infinity", s),
40 Value::Number(n) if n.is_infinite() => tagged("-Infinity", s),
41 Value::Number(n) => s.serialize_f64(*n),
42 Value::String(t) => s.serialize_str(t),
43 Value::Array(items) => {
44 let mut q = s.serialize_seq(Some(items.len()))?;
45 for i in items {
46 q.serialize_element(&JsonValue(i.clone()))?;
47 }
48 q.end()
49 }
50 Value::Object(entries) => {
51 let mut m = s.serialize_map(Some(entries.len()))?;
52 for (k, v) in entries {
53 m.serialize_entry(k, &JsonValue(v.clone()))?;
54 }
55 m.end()
56 }
57 }
58}
59
60impl<'de> Deserialize<'de> for JsonValue {
61 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
62 d.deserialize_any(ValueVisitor).map(JsonValue)
63 }
64}
65
66struct ValueVisitor;
67
68impl<'de> Visitor<'de> for ValueVisitor {
69 type Value = Value;
70
71 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 f.write_str("a JSON value")
73 }
74
75 fn visit_unit<E: de::Error>(self) -> Result<Value, E> {
76 Ok(Value::Null)
77 }
78 fn visit_none<E: de::Error>(self) -> Result<Value, E> {
79 Ok(Value::Null)
80 }
81 fn visit_bool<E: de::Error>(self, b: bool) -> Result<Value, E> {
82 Ok(Value::Bool(b))
83 }
84 fn visit_i64<E: de::Error>(self, n: i64) -> Result<Value, E> {
85 Ok(Value::Number(n as f64))
86 }
87 fn visit_u64<E: de::Error>(self, n: u64) -> Result<Value, E> {
88 Ok(Value::Number(n as f64))
89 }
90 fn visit_f64<E: de::Error>(self, n: f64) -> Result<Value, E> {
91 Ok(Value::Number(n))
92 }
93 fn visit_str<E: de::Error>(self, s: &str) -> Result<Value, E> {
94 Ok(Value::String(s.to_owned()))
95 }
96 fn visit_string<E: de::Error>(self, s: String) -> Result<Value, E> {
97 Ok(Value::String(s))
98 }
99 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Value, A::Error> {
100 let mut items = Vec::new();
101 while let Some(JsonValue(v)) = seq.next_element()? {
102 items.push(v);
103 }
104 Ok(Value::Array(items))
105 }
106 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Value, A::Error> {
107 let mut entries: Vec<(String, Value)> = Vec::new();
108 while let Some((k, JsonValue(v))) = map.next_entry::<String, JsonValue>()? {
109 entries.push((k, v));
110 }
111 if let [(k, Value::String(tag))] = entries.as_slice()
112 && k == TAG
113 {
114 return Ok(match tag.as_str() {
115 "undefined" => Value::Undefined,
116 "NaN" => Value::Number(f64::NAN),
117 "Infinity" => Value::Number(f64::INFINITY),
118 "-Infinity" => Value::Number(f64::NEG_INFINITY),
119 _ => Value::Object(entries),
120 });
121 }
122 Ok(Value::Object(entries))
123 }
124}
125
126pub fn to_text(v: &Value) -> String {
128 serde_json::to_string(&JsonValue(v.clone())).unwrap_or_else(|_| "null".into())
129}
130
131pub fn from_text(text: &str) -> Result<Value, serde_json::Error> {
137 serde_json::from_str::<JsonValue>(text).map(|j| j.0)
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn round_trip_keeps_order_and_undefined() {
146 let v = Value::Object(vec![
147 ("z".into(), Value::Number(1.5)),
148 ("a".into(), Value::Undefined),
149 (
150 "list".into(),
151 Value::Array(vec![
152 Value::Null,
153 Value::Bool(true),
154 Value::String("x".into()),
155 ]),
156 ),
157 ]);
158 let t = to_text(&v);
159 assert_eq!(
160 t,
161 r#"{"z":1.5,"a":{"$vt":"undefined"},"list":[null,true,"x"]}"#
162 );
163 assert_eq!(from_text(&t).unwrap(), v);
164 assert_eq!(
165 from_text(&to_text(&Value::Undefined)).unwrap(),
166 Value::Undefined
167 );
168 }
169}