///|
/// Bounded binary input. Cursor reads never silently clamp a truncated frame.
pub struct Reader {
bytes : Bytes
order : ByteOrder
mut position : Int32
}
///|
pub fn Reader::new(bytes : Bytes, order~ : ByteOrder = LittleEndian) -> Reader {
{ bytes, order, position: 0, }
}
///|
pub fn Reader::position(self : Reader) -> Int32 {
self.position
}
///|
pub fn Reader::remaining(self : Reader) -> Int32 {
self.bytes.length() - self.position
}
///|
fn Reader::require(
self : Reader,
offset : Int32,
length : Int32,
) -> Unit raise SbeError {
if offset < 0 ||
length < 0 ||
offset > self.bytes.length() ||
length > self.bytes.length() - offset {
raise Truncated(offset, length, self.bytes.length())
}
}
///|
pub fn Reader::seek(self : Reader, position : Int32) -> Unit raise SbeError {
self.require(position, 0)
self.position = position
}
///|
pub fn Reader::read_bytes(
self : Reader,
length : Int32,
) -> Bytes raise SbeError {
self.require(self.position, length)
let result = self.bytes[self.position:self.position + length].to_owned()
self.position += length
result
}
///|
/// Read an unsigned word of 1, 2, 4 or 8 bytes without loss of precision.
pub fn Reader::read_uint(self : Reader, width : Int32) -> UInt64 raise SbeError {
if width != 1 && width != 2 && width != 4 && width != 8 {
raise InvalidMessage("integer width must be 1, 2, 4 or 8")
}
self.require(self.position, width)
let mut word = 0UL
for i in 0.. i * 8
BigEndian => (width - i - 1) * 8
}
word = word | (self.bytes[self.position + i].to_uint64() << shift)
}
self.position += width
word
}
///|
pub fn Reader::read_int(self : Reader, width : Int32) -> Int64 raise SbeError {
let word = self.read_uint(width)
if width == 8 {
return word.reinterpret_as_int64()
}
let bits = width * 8
let extended = if (word & (1UL << (bits - 1))) != 0UL {
word | (0xffffffffffffffffUL << bits)
} else {
word
}
extended.reinterpret_as_int64()
}
///|
pub fn Reader::read_float(
self : Reader,
width : Int32,
) -> Double raise SbeError {
match width {
4 => Float::reinterpret_from_uint(self.read_uint(4).to_uint()).to_double()
8 => self.read_uint(8).reinterpret_as_double()
_ => raise InvalidMessage("float width must be 4 or 8")
}
}
///|
/// A growable writer with an explicit output bound; padding is always zero.
pub struct Writer {
bytes : Array[Byte]
order : ByteOrder
limit : Int32
}
///|
pub fn Writer::new(
order~ : ByteOrder = LittleEndian,
limit~ : Int32 = 16777216,
) -> Writer {
{ bytes: [], order, limit, }
}
///|
pub fn Writer::position(self : Writer) -> Int32 {
self.bytes.length()
}
///|
pub fn Writer::to_bytes(self : Writer) -> Bytes {
Bytes::from_array(self.bytes)
}
///|
fn Writer::reserve(self : Writer, count : Int32) -> Unit raise SbeError {
if count < 0 || self.limit < 0 || count > self.limit - self.bytes.length() {
raise LimitExceeded("encoded message exceeds the output limit")
}
}
///|
pub fn Writer::pad_to(self : Writer, offset : Int32) -> Unit raise SbeError {
if offset < self.bytes.length() {
raise InvalidMessage("cannot pad backwards")
}
self.reserve(offset - self.bytes.length())
while self.bytes.length() < offset {
self.bytes.push(0)
}
}
///|
pub fn Writer::write_bytes(self : Writer, bytes : Bytes) -> Unit raise SbeError {
self.reserve(bytes.length())
for byte in bytes {
self.bytes.push(byte)
}
}
///|
pub fn Writer::write_uint(
self : Writer,
value : UInt64,
width : Int32,
) -> Unit raise SbeError {
if width != 1 && width != 2 && width != 4 && width != 8 {
raise InvalidMessage("integer width must be 1, 2, 4 or 8")
}
if width < 8 && value >= 1UL << (width * 8) {
raise InvalidValue("integer", "unsigned value exceeds \{width} bytes")
}
self.reserve(width)
for i in 0.. i * 8
BigEndian => (width - i - 1) * 8
}
self.bytes.push(((value >> shift) & 255UL).to_byte())
}
}
///|
pub fn Writer::write_int(
self : Writer,
value : Int64,
width : Int32,
) -> Unit raise SbeError {
if width != 1 && width != 2 && width != 4 && width != 8 {
raise InvalidMessage("integer width must be 1, 2, 4 or 8")
}
if width < 8 {
let bound = 1L << (width * 8 - 1)
if value < 0L - bound || value >= bound {
raise InvalidValue("integer", "signed value exceeds \{width} bytes")
}
}
let mask = if width == 8 {
0xffffffffffffffffUL
} else {
(1UL << (width * 8)) - 1UL
}
self.write_uint(value.reinterpret_as_uint64() & mask, width)
}
///|
pub fn Writer::write_float(
self : Writer,
value : Double,
width : Int32,
) -> Unit raise SbeError {
match width {
4 =>
self.write_uint(
Float::from_double(value).reinterpret_as_uint().to_uint64(),
4,
)
8 => self.write_uint(value.reinterpret_as_uint64(), 8)
_ => raise InvalidMessage("float width must be 4 or 8")
}
}