///|
/// Type conversion failures for the lossless CRDT value decoder.
pub(all) suberror ValueDecodeError {
TypeMismatch(String)
OutOfRange(String)
} derive(Debug)
///|
pub extend ValueDecodeError with Debug::{to_repr}
///|
/// Application-defined deserialization from lib0 values, without an intermediate
/// JSON conversion. Implement this for structured application types.
pub(open) trait FromAny {
fn from_any(Any) -> Self raise ValueDecodeError
}
///|
pub fn[T : FromAny] from_any(value : Any) -> T raise ValueDecodeError {
T::from_any(value)
}
///|
pub impl FromAny for Any with fn from_any(value) {
value
}
///|
pub impl FromAny for Bool with fn from_any(value) {
guard value is Bool(value) else { raise TypeMismatch("Bool") }
value
}
///|
pub impl FromAny for String with fn from_any(value) {
guard value is String(value) else { raise TypeMismatch("String") }
value
}
///|
pub impl FromAny for Bytes with fn from_any(value) {
guard value is Buffer(value) else { raise TypeMismatch("Bytes") }
value
}
///|
pub impl FromAny for Int64 with fn from_any(value) {
match value {
Integer(value) => value
Float(value) => {
guard value >= -9223372036854775808.0 && value <= 9223372036854775808.0 else {
raise TypeMismatch("Int64")
}
// Rust's float-to-integer cast saturates at this rounded endpoint.
if value == 9223372036854775808.0 {
return 9223372036854775807L
}
let integer = value.to_int64()
guard integer.to_double() == value else { raise TypeMismatch("Int64") }
integer
}
_ => raise TypeMismatch("Int64")
}
}
///|
pub impl FromAny for Int32 with fn from_any(value) {
let integer : Int64 = from_any(value)
guard integer >= -2147483648L && integer <= 2147483647L else {
raise OutOfRange("Int")
}
integer.to_int()
}
///|
pub impl FromAny for UInt32 with fn from_any(value) {
let integer : Int64 = from_any(value)
guard integer >= 0L && integer <= 4294967295L else {
raise OutOfRange("UInt")
}
integer.to_int().reinterpret_as_uint()
}
///|
pub impl FromAny for UInt64 with fn from_any(value) {
let integer : Int64 = from_any(value)
guard integer >= 0L else { raise OutOfRange("UInt64") }
integer.reinterpret_as_uint64()
}
///|
pub impl FromAny for Double with fn from_any(value) {
match value {
Float(value) => value
Integer(value) => {
let number = value.to_double()
if value == 9223372036854775807L {
return number
}
guard number < 9223372036854775808.0 && number.to_int64() == value else {
raise TypeMismatch("Double")
}
number
}
_ => raise TypeMismatch("Double")
}
}
///|
pub impl FromAny for Float with fn from_any(value) {
let number : Double = from_any(value)
Float::from_double(number)
}
///|
pub impl[T : FromAny] FromAny for T? with fn from_any(value) {
match value {
Null | Undefined => None
_ => Some(T::from_any(value))
}
}
///|
pub impl[T : FromAny] FromAny for Array[T] with fn from_any(value) {
guard value is Array(values) else { raise TypeMismatch("Array") }
let result = []
for value in values {
result.push(T::from_any(value))
}
result
}
///|
pub impl[T : FromAny] FromAny for Map[String, T] with fn from_any(value) {
guard value is Object(values) else { raise TypeMismatch("Map") }
let result : Map[String, T] = Map([])
for (key, value) in values {
result[key] = T::from_any(value)
}
result
}
///|
pub impl[A : FromAny, B : FromAny] FromAny for (A, B) with fn from_any(value) {
guard value is Array(values) && values.length() == 2 else {
raise TypeMismatch("pair")
}
(A::from_any(values[0]), B::from_any(values[1]))
}
///|
pub impl FromAny for Unit with fn from_any(value) {
guard value is Null || value is Undefined else { raise TypeMismatch("Unit") }
}
///|
pub extend Any with FromAny::{from_any}