///|
/// Encode one lib0 value through an application-supplied byte writer.
/// Large integers retain exact bits, as with Any.encode, rather than selecting
/// Rust's potentially lossy floating representation at the Int64 endpoints.
pub fn Any::encode_to(self : Any, writer : &Write) -> Unit {
match self {
Undefined => writer.write_u8(127)
Null => writer.write_u8(126)
Bool(value) => writer.write_u8(if value { 120 } else { 121 })
Integer(value) =>
if value >= -2147483647L && value <= 2147483647L {
writer.write_u8(125)
writer.write_var_int(value)
} else {
writer.write_u8(122)
writer.write_i64(value)
}
Float(value) =>
if Float::from_double(value).to_double() == value {
writer.write_u8(124)
writer.write_f32(Float::from_double(value))
} else {
writer.write_u8(123)
writer.write_f64(value)
}
String(value) => {
writer.write_u8(119)
writer.write_string(value)
}
Buffer(value) => {
writer.write_u8(116)
writer.write_buf(value)
}
Array(values) => {
writer.write_u8(117)
writer.write_var_uint(values.length().to_uint64())
for value in values {
value.encode_to(writer)
}
}
Object(entries) => {
writer.write_u8(118)
writer.write_var_uint(entries.length().to_uint64())
for (key, value) in entries {
writer.write_string(key)
value.encode_to(writer)
}
}
}
}
///|
/// Decode one value and leave the following bytes available to the reader.
/// The value budget bounds compressed container expansion before iteration.
pub fn Any::decode_from(
reader : &Read,
max_values~ : Int32 = 1000000,
) -> Any raise DecodeError {
guard max_values >= 0 else { raise InvalidData("negative value budget") }
let mut remaining = max_values
fn count() -> Int32 raise DecodeError {
let n = reader.read_var_uint()
guard n <= remaining.to_uint64() else {
raise InvalidData("lib0 value exceeds decode budget")
}
n.to_int()
}
fn decode(depth : Int32) -> Any raise DecodeError {
guard depth <= 256 else {
raise InvalidData("lib0 value nesting exceeds 256")
}
guard remaining > 0 else {
raise InvalidData("lib0 value exceeds decode budget")
}
remaining -= 1
match reader.read_u8().to_int() {
127 => Undefined
126 => Null
125 => Integer(reader.read_var_int())
124 => Float(reader.read_f32().to_double())
123 => Float(reader.read_f64())
122 => Integer(reader.read_i64())
121 => Bool(false)
120 => Bool(true)
119 => String(reader.read_string())
116 => Buffer(reader.read_buf())
117 => {
let values = []
for _ in 0.. {
let values : Map[String, Any] = Map([])
for _ in 0.. raise InvalidData("unknown lib0 value tag")
}
}
decode(0)
}