///|
/// Errors always identify the byte offset or logical record involved.
pub suberror ShapeError {
InvalidData(Int, String)
} derive(Debug)
///|
priv struct ByteReader {
data : Bytes
mut pos : Int
end : Int
base : Int
}
///|
fn ByteReader::new(data : Bytes, base? : Int = 0) -> ByteReader {
{ data, pos: 0, end: data.length(), base }
}
///|
fn ByteReader::remaining(self : ByteReader) -> Int {
self.end - self.pos
}
///|
fn ByteReader::require(self : ByteReader, n : Int) -> Unit raise ShapeError {
if n < 0 || n > self.remaining() {
raise InvalidData(self.base + self.pos, "truncated binary value")
}
}
///|
fn ByteReader::le32(self : ByteReader) -> Int raise ShapeError {
self.require(4)
let p = self.pos
self.pos += 4
self.data[p].to_int() |
(self.data[p + 1].to_int() << 8) |
(self.data[p + 2].to_int() << 16) |
(self.data[p + 3].to_int() << 24)
}
///|
fn ByteReader::be32(self : ByteReader) -> Int raise ShapeError {
self.require(4)
let p = self.pos
self.pos += 4
(self.data[p].to_int() << 24) |
(self.data[p + 1].to_int() << 16) |
(self.data[p + 2].to_int() << 8) |
self.data[p + 3].to_int()
}
///|
fn ByteReader::f64(self : ByteReader) -> Double raise ShapeError {
self.require(8)
let mut bits : UInt64 = 0
for i = 0; i < 8; i = i + 1 {
bits = bits | (self.data[self.pos + i].to_int().to_uint64() << (i * 8))
}
self.pos += 8
bits.reinterpret_as_double()
}
///|
fn ByteReader::take(self : ByteReader, n : Int) -> Bytes raise ShapeError {
self.require(n)
let result = self.data[self.pos:self.pos + n].to_owned()
self.pos += n
result
}
///|
priv struct ByteWriter {
data : Array[Byte]
}
///|
fn ByteWriter::new() -> ByteWriter {
{ data: [] }
}
///|
fn ByteWriter::le32(self : ByteWriter, n : Int) -> Unit {
for i = 0; i < 4; i = i + 1 {
self.data.push((n >> (i * 8)).to_byte())
}
}
///|
fn ByteWriter::be32(self : ByteWriter, n : Int) -> Unit {
for i = 3; i >= 0; i = i - 1 {
self.data.push((n >> (i * 8)).to_byte())
}
}
///|
fn ByteWriter::f64(self : ByteWriter, n : Double) -> Unit {
let bits = n.reinterpret_as_uint64()
for i = 0; i < 8; i = i + 1 {
self.data.push((bits >> (i * 8)).to_byte())
}
}
///|
fn ByteWriter::append(self : ByteWriter, bytes : Bytes) -> Unit {
for b in bytes {
self.data.push(b)
}
}
///|
fn ByteWriter::bytes(self : ByteWriter) -> Bytes {
Bytes::from_array(self.data)
}
///|
fn finite(n : Double) -> Bool {
!n.is_nan() && n <= 1.7976931348623157e308 && n >= -1.7976931348623157e308
}
///|
fn checked_size(
count : Int,
width : Int,
available : Int,
offset : Int,
) -> Int raise ShapeError {
if count < 0 || width <= 0 || count > available / width {
raise InvalidData(offset, "count exceeds available bytes")
}
count * width
}
///|
fn words_to_bytes(words : Int, offset : Int) -> Int raise ShapeError {
if words < 0 || words > 1073741823 {
raise InvalidData(offset, "invalid 16-bit word length")
}
words * 2
}