///|
pub(all) suberror DecodeError {
InvalidData(String)
} derive(Debug)
///|
pub extend DecodeError with Debug::{to_repr}
///|
priv struct Reader {
bytes : Bytes
mut offset : Int32
}
///|
fn Reader::byte(self : Reader) -> Int32 raise DecodeError {
guard self.offset < self.bytes.length() else {
raise InvalidData("truncated binary")
}
let result = self.bytes[self.offset].to_int()
self.offset += 1
result
}
///|
fn Reader::uint(self : Reader) -> UInt64 raise DecodeError {
let mut value = 0UL
for shift = 0; shift < 70; shift = shift + 7 {
let b = self.byte()
guard shift != 63 || b <= 1 else { raise InvalidData("integer overflow") }
value = value | ((b & 127).to_uint64() << shift)
if b < 128 {
return value
}
}
raise InvalidData("integer overflow")
}
///|
fn Reader::clock(self : Reader) -> UInt32 raise DecodeError {
let value = self.uint()
guard value <= 0xffff_ffffUL else { raise InvalidData("clock overflow") }
value.to_uint()
}
///|
fn Reader::count(self : Reader) -> Int32 raise DecodeError {
let value = self.uint()
// Each element must consume at least one byte. Never preallocate from an
// untrusted length; this also bounds loops over malformed nested values.
guard value <= (self.bytes.length() - self.offset).to_uint64() else {
raise InvalidData("length exceeds remaining bytes")
}
value.to_int()
}
///|
fn Reader::buffer(self : Reader) -> Bytes raise DecodeError {
let len = self.count()
let result = self.bytes[self.offset:self.offset + len].to_owned()
self.offset += len
result
}
///|
fn Reader::string(self : Reader) -> String raise DecodeError {
@utf8.decode(self.buffer(), ignore_bom=false) catch {
_ => raise InvalidData("invalid UTF-8")
}
}
///|
fn Reader::id(self : Reader) -> Id raise DecodeError {
{ client: self.uint(), clock: self.clock(), }
}
///|
fn Reader::finish(self : Reader) -> Unit raise DecodeError {
guard self.offset == self.bytes.length() else {
raise InvalidData("trailing bytes")
}
}
///|
priv struct Writer {
bytes : Array[Byte]
}
///|
fn Writer::byte(self : Writer, value : Int32) -> Unit {
self.bytes.push(value.to_byte())
}
///|
fn Writer::uint(self : Writer, value : UInt64) -> Unit {
let mut value = value
while value > 127UL {
self.byte((value & 127UL).to_int() | 128)
value = value >> 7
}
self.byte(value.to_int())
}
///|
fn Writer::buffer(self : Writer, bytes : Bytes) -> Unit {
self.uint(bytes.length().to_uint64())
for b in bytes {
self.bytes.push(b)
}
}
///|
fn Writer::string(self : Writer, value : String) -> Unit {
self.buffer(@utf8.encode(value))
}
///|
fn Writer::id(self : Writer, id : Id) -> Unit {
self.uint(id.client)
self.uint(id.clock.to_uint64())
}
///|
fn Writer::finish(self : Writer) -> Bytes {
Bytes::from_array(self.bytes[:])
}