///|
/// Reading a value out of a JSON object, and writing the small shapes every dialect
/// needs. Vendors omit fields freely, so every reader here returns `Option` rather than
/// inventing a value. They are free functions rather than methods because `Json` belongs
/// to core.
///|
/// The member at `key`, when this is an object that has it.
pub fn json_field(json : Json, key : String) -> Json? {
match json {
Object(map) => map.get(key)
_ => None
}
}
///|
/// The string at `key`, when it is a string.
pub fn json_string(json : Json, key : String) -> String? {
match json {
Object(map) =>
match map.get(key) {
Some(value) => json_as_string(value)
None => None
}
_ => None
}
}
///|
/// The number at `key`, when it is a number.
pub fn json_number(json : Json, key : String) -> Double? {
match json {
Object(map) =>
match map.get(key) {
Some(value) => json_as_number(value)
None => None
}
_ => None
}
}
///|
/// The integer at `key`, when it is a number.
pub fn json_int(json : Json, key : String) -> Int32? {
match json_number(json, key) {
Some(value) => Some(value.to_int())
None => None
}
}
///|
/// The boolean at `key`, when it is a boolean.
pub fn json_bool(json : Json, key : String) -> Bool? {
match json {
Object(map) =>
match map.get(key) {
Some(value) => json_as_bool(value)
None => None
}
_ => None
}
}
///|
/// The array at `key`, or an empty one.
pub fn json_array(json : Json, key : String) -> Array[Json] {
match json {
Object(map) =>
match map.get(key) {
Some(Array(items)) => items
_ => []
}
_ => []
}
}
///|
/// The object at `key`, or `None`.
pub fn json_object(json : Json, key : String) -> Map[String, Json]? {
match json {
Object(map) =>
match map.get(key) {
Some(Object(inner)) => Some(inner)
_ => None
}
_ => None
}
}
///|
/// The string at `key`, or `fallback`.
pub fn json_string_or(json : Json, key : String, fallback : String) -> String {
json_string(json, key).unwrap_or(fallback)
}
///|
/// A JSON array of the strings in `items`.
pub fn strings_json(items : Array[String]) -> Json {
Json::array(items.map(item => Json::string(item)))
}
///|
/// The strings in an array value, skipping anything that is not a string.
pub fn json_strings(value : Json) -> Array[String] {
match value {
Array(items) => items.filter_map(item => json_as_string(item))
_ => []
}
}
///|
/// A JSON array of the numbers in `values`.
pub fn numbers_json(values : Array[Double]) -> Json {
Json::array(values.map(value => Json::number(value)))
}
///|
/// The numbers in an array value.
pub fn json_numbers(value : Json) -> Array[Double] {
match value {
Array(items) => items.filter_map(item => json_as_number(item))
_ => []
}
}
///|
/// `base` with `overrides` merged over it, key by key. `extra` reaches the wire this
/// way: a caller's field wins over the one this library wrote.
pub fn merge_json(
base : Map[String, Json],
overrides : Map[String, Json],
) -> Map[String, Json] {
let merged = Map([])
for key, value in base {
merged[key] = value
}
for key, value in overrides {
merged[key] = value
}
merged
}
///|
/// A JSON object from key/value pairs, in order.
pub fn object_json(fields : Array[(String, Json)]) -> Json {
let map = Map([])
for pair in fields {
map[pair.0] = pair.1
}
Json::object(map)
}
///|
/// The text of a JSON string.
pub fn json_as_string(json : Json) -> String? {
match json {
String(text) => Some(text)
_ => None
}
}
///|
/// The value of a JSON number.
pub fn json_as_number(json : Json) -> Double? {
match json {
Number(value, ..) => Some(value)
_ => None
}
}
///|
/// The value of a JSON boolean.
pub fn json_as_bool(json : Json) -> Bool? {
match json {
True => Some(true)
False => Some(false)
_ => None
}
}
///|
/// An integer from a decimal string, or zero. Used where a stream carries an index in a
/// text field; a vendor that sends something else should not crash the reader.
pub fn parse_int_lossy(text : String) -> Int32 {
let mut sign = 1
let mut value = 0
let mut seen = false
for char in text {
if char == '-' && !seen {
sign = -1
} else if char >= '0' && char <= '9' {
value = value * 10 + (char.to_int() - '0'.to_int())
seen = true
}
}
value * sign
}