///|
fn write_u32(out : Array[Int32], value : UInt32) -> Unit {
for shift in [24, 16, 8, 0] {
out.push(((value >> shift) & 255U).reinterpret_as_int())
}
}
///|
fn read_u32(values : Array[Int32], offset : Int32) -> UInt32 {
let mut value = 0U
for i in offset..<(offset + 4) {
value = (value << 8) | values[i].reinterpret_as_uint()
}
value
}
///|
fn read_u31(values : Array[Int32], offset : Int32) -> Int32 raise CodeError {
let value = read_u32(values, offset)
if value > 2147483647U {
raise Corrupt("unsigned field exceeds signed 31-bit domain")
}
value.reinterpret_as_int()
}
///|
pub fn Packet::wire_length(self : Packet) -> Int32 {
28 + self.generation().count() + self.generation().width()
}
///|
// MRC1: big-endian bounded header, explicit coefficients, payload, CRC32.
// This is a project format, NOT an RFC 8681 / RaptorQ / Reed-Solomon frame.
pub fn Packet::to_wire(self : Packet) -> Symbols {
let g = self.generation()
let values : Array[Int32] = [
77,
82,
67,
49,
0,
g.count(),
g.width() >> 8,
g.width() & 255,
]
write_u32(values, g.id().reinterpret_as_uint())
write_u32(values, g.length().reinterpret_as_uint())
write_u32(values, self.sequence().reinterpret_as_uint())
write_u32(values, self.wire_length().reinterpret_as_uint())
for value in self.coefficients().values {
values.push(value)
}
for value in self.payload().values {
values.push(value)
}
let checksum = crc32({ values, })
write_u32(values, checksum)
{ values, }
}
///|
pub fn packet_from_wire(frame : Symbols) -> Packet raise CodeError {
if frame.length() < 28 {
raise Truncated
}
if frame.length() > 4188 {
raise Limit("packet frame exceeds 4188 bytes")
}
let values = frame.values
if values[0] != 77 || values[1] != 82 || values[2] != 67 || values[3] != 49 {
raise Corrupt("unknown packet magic/version")
}
if values[4] != 0 {
raise Corrupt("reserved packet flags must be zero")
}
let count = values[5]
let width = (values[6] << 8) | values[7]
if count < 1 || count > 64 || width < 1 || width > 4096 {
raise Limit("packet dimensions outside supported bounds")
}
let expected = 28 + count + width
let declared = read_u31(values, 20)
if declared != expected || frame.length() != expected {
raise Shape("packet length mismatch")
}
let end = frame.length() - 4
if crc32(frame.slice(0, end)) != read_u32(values, end) {
raise Corrupt("packet CRC32 mismatch")
}
let generation = Generation::new(
read_u31(values, 8),
count,
width,
read_u31(values, 12),
)
let sequence = read_u31(values, 16)
let coefficients = frame.slice(24, 24 + count)
let payload = frame.slice(24 + count, end)
Packet::new(generation, sequence, Equation::new(coefficients, payload))
}