use crate::interop::{FromValue, ToValue};
use crate::value::Value;
use crate::vm::Fault;
impl Value {
pub fn to_json(&self) -> Result<serde_json::Value, Fault> {
use serde_json::Value as J;
Ok(match self {
Value::Unit => J::Null,
Value::Bool(b) => J::Bool(*b),
Value::Int(i) => J::Number((*i).into()),
Value::Float(f) => serde_json::Number::from_f64(*f)
.map(J::Number)
.ok_or_else(|| Fault::new(format!("cannot represent {} in JSON", f)))?,
Value::Str(s) => J::String(s.to_string()),
Value::List(items) | Value::Tuple(items) => J::Array(
items
.iter()
.map(|v| v.to_json())
.collect::<Result<_, _>>()?,
),
Value::Record(r) => J::Object(
r.iter()
.map(|(k, v)| Ok((k.clone(), v.to_json()?)))
.collect::<Result<_, Fault>>()?,
),
other => {
return Err(Fault::new(format!(
"cannot convert {} to JSON; convert it to records/lists/primitives first",
other.type_name()
)))
}
})
}
pub fn from_json(j: &serde_json::Value) -> Value {
use serde_json::Value as J;
match j {
J::Null => Value::Unit,
J::Bool(b) => Value::Bool(*b),
J::Number(n) => {
if let Some(i) = n.as_i64() {
Value::Int(i)
} else {
Value::Float(n.as_f64().unwrap_or(f64::NAN))
}
}
J::String(s) => Value::str(s.clone()),
J::Array(items) => Value::list_v(items.iter().map(Value::from_json).collect()),
J::Object(fields) => Value::Record(
fields
.iter()
.map(|(k, v)| (k.clone(), Value::from_json(v)))
.collect(),
),
}
}
}
impl FromValue for serde_json::Value {
fn from_value(v: Value) -> Result<Self, Fault> {
v.to_json()
}
}
impl ToValue for serde_json::Value {
fn to_value(self) -> Value {
Value::from_json(&self)
}
}