use core::fmt;
use serde::de::{self, MapAccess, SeqAccess, Visitor};
use serde::ser::{SerializeMap, SerializeSeq};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use vertep_core::datamodel::Value;
const TAG: &str = "$vt";
#[derive(Clone, Debug, PartialEq)]
pub struct JsonValue(pub Value);
impl Serialize for JsonValue {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
ser(&self.0, s)
}
}
fn tagged<S: Serializer>(tag: &str, s: S) -> Result<S::Ok, S::Error> {
let mut m = s.serialize_map(Some(1))?;
m.serialize_entry(TAG, tag)?;
m.end()
}
fn ser<S: Serializer>(v: &Value, s: S) -> Result<S::Ok, S::Error> {
match v {
Value::Undefined => tagged("undefined", s),
Value::Null => s.serialize_unit(),
Value::Bool(b) => s.serialize_bool(*b),
Value::Number(n) if n.is_nan() => tagged("NaN", s),
Value::Number(n) if n.is_infinite() && *n > 0.0 => tagged("Infinity", s),
Value::Number(n) if n.is_infinite() => tagged("-Infinity", s),
Value::Number(n) => s.serialize_f64(*n),
Value::String(t) => s.serialize_str(t),
Value::Array(items) => {
let mut q = s.serialize_seq(Some(items.len()))?;
for i in items {
q.serialize_element(&JsonValue(i.clone()))?;
}
q.end()
}
Value::Object(entries) => {
let mut m = s.serialize_map(Some(entries.len()))?;
for (k, v) in entries {
m.serialize_entry(k, &JsonValue(v.clone()))?;
}
m.end()
}
}
}
impl<'de> Deserialize<'de> for JsonValue {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
d.deserialize_any(ValueVisitor).map(JsonValue)
}
}
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = Value;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a JSON value")
}
fn visit_unit<E: de::Error>(self) -> Result<Value, E> {
Ok(Value::Null)
}
fn visit_none<E: de::Error>(self) -> Result<Value, E> {
Ok(Value::Null)
}
fn visit_bool<E: de::Error>(self, b: bool) -> Result<Value, E> {
Ok(Value::Bool(b))
}
fn visit_i64<E: de::Error>(self, n: i64) -> Result<Value, E> {
Ok(Value::Number(n as f64))
}
fn visit_u64<E: de::Error>(self, n: u64) -> Result<Value, E> {
Ok(Value::Number(n as f64))
}
fn visit_f64<E: de::Error>(self, n: f64) -> Result<Value, E> {
Ok(Value::Number(n))
}
fn visit_str<E: de::Error>(self, s: &str) -> Result<Value, E> {
Ok(Value::String(s.to_owned()))
}
fn visit_string<E: de::Error>(self, s: String) -> Result<Value, E> {
Ok(Value::String(s))
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Value, A::Error> {
let mut items = Vec::new();
while let Some(JsonValue(v)) = seq.next_element()? {
items.push(v);
}
Ok(Value::Array(items))
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Value, A::Error> {
let mut entries: Vec<(String, Value)> = Vec::new();
while let Some((k, JsonValue(v))) = map.next_entry::<String, JsonValue>()? {
entries.push((k, v));
}
if let [(k, Value::String(tag))] = entries.as_slice()
&& k == TAG
{
return Ok(match tag.as_str() {
"undefined" => Value::Undefined,
"NaN" => Value::Number(f64::NAN),
"Infinity" => Value::Number(f64::INFINITY),
"-Infinity" => Value::Number(f64::NEG_INFINITY),
_ => Value::Object(entries),
});
}
Ok(Value::Object(entries))
}
}
pub fn to_text(v: &Value) -> String {
serde_json::to_string(&JsonValue(v.clone())).unwrap_or_else(|_| "null".into())
}
pub fn from_text(text: &str) -> Result<Value, serde_json::Error> {
serde_json::from_str::<JsonValue>(text).map(|j| j.0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip_keeps_order_and_undefined() {
let v = Value::Object(vec![
("z".into(), Value::Number(1.5)),
("a".into(), Value::Undefined),
(
"list".into(),
Value::Array(vec![
Value::Null,
Value::Bool(true),
Value::String("x".into()),
]),
),
]);
let t = to_text(&v);
assert_eq!(
t,
r#"{"z":1.5,"a":{"$vt":"undefined"},"list":[null,true,"x"]}"#
);
assert_eq!(from_text(&t).unwrap(), v);
assert_eq!(
from_text(&to_text(&Value::Undefined)).unwrap(),
Value::Undefined
);
}
}