///|
/// A self-describing value: the data model made concrete.
///
/// `Serialize` is polymorphic in its serializer and therefore has no trait
/// object form, so a heterogeneous collection cannot be built out of
/// `Serialize` values directly. `Value` fills that gap, and doubles as the
/// result type of `Deserializer::deserialize_any`.
///
/// Structs and enum variants collapse into `Map` here, using serde's default
/// externally-tagged representation: a unit variant becomes `Str(name)`, and
/// any variant with a payload becomes a single-entry `Map` from the variant
/// name to its payload.
pub(all) enum Value {
Null
Boolean(Bool)
/// Any signed integer in the data model, widened.
Int(Int64)
/// Any unsigned integer in the data model, widened.
UInt(UInt64)
Double(Double)
Str(String)
Bytes(Bytes)
Seq(Array[Value])
/// Order-preserving, and keys need not be strings.
Map(Array[(Value, Value)])
} derive(Eq, Debug)
///|
/// A short name for this value's shape, used in `InvalidType` messages.
pub fn Value::type_name(self : Value) -> String {
match self {
Null => "unit"
Boolean(_) => "boolean"
Int(_) => "integer"
UInt(_) => "unsigned integer"
Double(_) => "float"
Str(_) => "string"
Bytes(_) => "byte string"
Seq(_) => "sequence"
Map(_) => "map"
}
}
///|
/// Looks up a key in a `Map` value. Returns `None` for any other shape.
pub fn Value::get(self : Value, key : String) -> Value? {
guard self is Map(entries) else { return None }
for entry in entries {
if entry.0 is Str(k) && k == key {
return Some(entry.1)
}
}
None
}
///|
pub impl Show for Value with fn output(self, logger) {
match self {
Null => logger.write_string("null")
Boolean(b) => logger.write_string(b.to_string())
Int(i) => logger.write_string(i.to_string())
UInt(u) => logger.write_string(u.to_string())
Double(d) => logger.write_string(d.to_string())
Str(s) => {
logger.write_string("\"")
logger.write_string(s)
logger.write_string("\"")
}
Bytes(b) => {
logger.write_string("b\"")
for byte in b {
logger.write_string(byte.to_hex())
}
logger.write_string("\"")
}
Seq(items) => {
logger.write_string("[")
for i, item in items {
if i > 0 {
logger.write_string(", ")
}
Show::output(item, logger)
}
logger.write_string("]")
}
Map(entries) => {
logger.write_string("{")
for i, entry in entries {
if i > 0 {
logger.write_string(", ")
}
Show::output(entry.0, logger)
logger.write_string(": ")
Show::output(entry.1, logger)
}
logger.write_string("}")
}
}
}