///|
fn object_key_text(key : Value) -> String {
match key {
StringVal(text) => text
_ => key.to_rego_text()
}
}
///|
/// Converts a value to JSON.
///
/// Sets become arrays, which is what Rego does when it serialises a set to
/// JSON. Object keys that are not strings are rendered with `to_rego_text`.
pub fn Value::to_json(self : Value) -> Json {
match self {
NullVal => Json::null()
BoolVal(value) => Json::boolean(value)
IntVal(value) => Json::number(value.to_double(), repr=value.to_string())
FloatVal(value) => Json::number(value)
StringVal(text) => Json::string(text)
ArrayVal(items) => Json::array(items.map(fn(item) { item.to_json() }))
SetVal(items) => Json::array(items.map(fn(item) { item.to_json() }))
ObjectVal(pairs) => {
let map : Map[String, Json] = Map([])
for pair in pairs {
map[object_key_text(pair.0)] = pair.1.to_json()
}
Json::object(map)
}
}
}
///|
/// Converts JSON to a value.
///
/// Numbers that are integral and within the safe integer range become
/// `IntVal`; other numbers stay `FloatVal`.
pub fn Value::from_json(json : Json) -> Value {
match json {
Json::Null => NullVal
Json::True => BoolVal(true)
Json::False => BoolVal(false)
Json::Number(value, ..) =>
if value >= -9007199254740992.0 &&
value <= 9007199254740992.0 &&
value.to_int64().to_double() == value {
IntVal(value.to_int64())
} else {
FloatVal(value)
}
Json::String(text) => StringVal(text)
Json::Array(items) =>
ArrayVal(items.map(fn(item) { Value::from_json(item) }))
Json::Object(map) => {
let pairs : Array[(Value, Value)] = []
for entry in map.to_array() {
pairs.push((StringVal(entry.0), Value::from_json(entry.1)))
}
ObjectVal(pairs)
}
}
}
///|
/// Parses JSON text into a value.
pub fn parse_json_value(source : String) -> Value raise @json.ParseError {
Value::from_json(@json.parse(source))
}