///|
/// Encode an unsigned 64-bit integer using the Multiformats unsigned varint
/// representation (unsigned LEB128, minimal form).
pub fn encode_u64(value : UInt64) -> Bytes {
let buffer = @buffer.Buffer(size_hint=10)
let mut remaining = value
while remaining >= 0x80UL {
buffer.write_byte((remaining & 0x7FUL).to_int().to_byte() | b'\x80')
remaining = remaining >> 7
}
buffer.write_byte(remaining.to_int().to_byte())
buffer.to_bytes()
}
///|
/// Decode an unsigned varint with the default resource limits.
pub fn decode_u64(input : BytesView) -> Result[(UInt64, Int), MoonLoomError] {
decode_u64_with_limits(input, Limits::default())
}
///|
/// Decode one unsigned varint and return the value together with the number of
/// bytes consumed. Trailing bytes are intentionally left to the caller.
pub fn decode_u64_with_limits(
input : BytesView,
limits : Limits,
) -> Result[(UInt64, Int), MoonLoomError] {
match limits.check_input("varint", input.length()) {
Ok(_) => ()
Err(err) => return Err(err)
}
if input.length() == 0 {
return Err(Truncated("varint", 0))
}
let max_bytes = limits.max_varint_bytes()
if max_bytes <= 0 || max_bytes > 10 {
return Err(InvalidVarint("varint limit", 0))
}
let mut value = 0UL
let mut shift = 0
let mut offset = 0
while offset < input.length() && offset < max_bytes {
let byte = input[offset]
let byte_value = byte.to_int()
let payload = (byte_value & 0x7F).to_uint64()
if offset == 9 && payload > 1UL {
return Err(InvalidVarint("varint overflow", offset))
}
value = value | (payload << shift)
if (byte_value & 0x80) == 0 {
if offset > 0 && payload == 0UL {
return Err(NonCanonicalVarint(offset))
}
return Ok((value, offset + 1))
}
shift += 7
offset += 1
}
if offset >= max_bytes {
Err(InvalidVarint("varint length", offset))
} else {
Err(Truncated("varint", offset))
}
}