///|
/// 紧凑字节协议:输入帧 / 确认帧 / 校验和帧。
///
/// 线上格式(小端,varint 为 LEB128):
/// ```
/// Input : [0x01][varint frame][varint count][varint bits] * count
/// Confirm : [0x02][varint frame]
/// Checksum : [0x03][varint frame][8 bytes hash]
/// ```
pub(all) struct InputFrame {
frame : Int
inputs : Array[UInt64]
} derive(Eq)
///|
pub(all) struct ConfirmFrame {
frame : Int
} derive(Eq)
///|
pub(all) struct ChecksumFrame {
frame : Int
hash : UInt64
} derive(Eq)
///|
pub(all) enum Message {
Input(InputFrame)
Confirm(ConfirmFrame)
Checksum(ChecksumFrame)
} derive(Eq)
///|
pub fn InputFrame::new(frame : Int, inputs : Array[UInt64]) -> InputFrame {
{ frame, inputs }
}
///|
pub fn ConfirmFrame::new(frame : Int) -> ConfirmFrame {
{ frame, }
}
///|
pub fn ChecksumFrame::new(frame : Int, hash : UInt64) -> ChecksumFrame {
{ frame, hash }
}
///|
fn put_varint(out : Array[Byte], v : UInt64) -> Unit {
let mut x = v
while x >= 128UL {
out.push(((x & 0x7FUL).to_int() | 0x80).to_byte())
x = x >> 7
}
out.push(x.to_int().to_byte())
}
///|
fn get_varint(buf : Bytes, start : Int) -> (UInt64, Int)? {
let mut x = 0UL
let mut shift = 0
let mut pos = start
while pos < buf.length() && shift <= 63 {
let b = buf[pos].to_int()
x = x | ((b.to_uint64() & 0x7FUL) << shift)
pos = pos + 1
if b < 128 {
return Some((x, pos))
}
shift = shift + 7
}
None
}
///|
fn put_u64(out : Array[Byte], v : UInt64) -> Unit {
let mut i = 0
while i < 8 {
out.push(((v >> (i * 8)) & 0xFFUL).to_int().to_byte())
i = i + 1
}
}
///|
fn get_u64(buf : Bytes, pos : Int) -> UInt64? {
if pos < 0 || pos + 8 > buf.length() {
return None
}
let mut v = 0UL
let mut i = 0
while i < 8 {
v = v | (buf[pos + i].to_int().to_uint64() << (i * 8))
i = i + 1
}
Some(v)
}
///|
fn to_bytes(arr : Array[Byte]) -> Bytes {
Bytes::makei(arr.length(), fn(i) { arr[i] })
}
///|
fn encode_into(out : Array[Byte], msg : Message) -> Unit {
match msg {
Input(f) => {
out.push((1).to_byte())
put_varint(out, f.frame.to_uint64())
put_varint(out, f.inputs.length().to_uint64())
for bits in f.inputs {
put_varint(out, bits)
}
}
Confirm(f) => {
out.push((2).to_byte())
put_varint(out, f.frame.to_uint64())
}
Checksum(f) => {
out.push((3).to_byte())
put_varint(out, f.frame.to_uint64())
put_u64(out, f.hash)
}
}
}
///|
pub fn encode(msg : Message) -> Bytes {
let out : Array[Byte] = []
encode_into(out, msg)
to_bytes(out)
}
///|
pub fn encode_batch(msgs : Array[Message]) -> Bytes {
let out : Array[Byte] = []
for m in msgs {
encode_into(out, m)
}
to_bytes(out)
}
///|
fn decode_at(buf : Bytes, start : Int) -> (Message, Int)? {
if start >= buf.length() {
return None
}
let tag = buf[start].to_int()
let pos = start + 1
if tag == 1 {
match get_varint(buf, pos) {
Some((frame, p1)) =>
match get_varint(buf, p1) {
Some((count, p2)) => {
// 一帧最多 8 个玩家的输入,超过即视为损坏
if count > 8UL {
return None
}
let inputs : Array[UInt64] = []
let mut p = p2
let mut i = 0
while i < count.to_int() {
match get_varint(buf, p) {
Some((bits, np)) => {
inputs.push(bits)
p = np
i = i + 1
}
None => return None
}
}
Some((Input({ frame: frame.to_int(), inputs }), p))
}
None => None
}
None => None
}
} else if tag == 2 {
match get_varint(buf, pos) {
Some((frame, p)) => Some((Confirm({ frame: frame.to_int() }), p))
None => None
}
} else if tag == 3 {
match get_varint(buf, pos) {
Some((frame, p1)) =>
match get_u64(buf, p1) {
Some(hash) =>
Some((Checksum({ frame: frame.to_int(), hash }), p1 + 8))
None => None
}
None => None
}
} else {
None
}
}
///|
pub fn decode(buf : Bytes) -> Message? {
match decode_at(buf, 0) {
Some((msg, _)) => Some(msg)
None => None
}
}
///|
pub fn decode_batch(buf : Bytes) -> Array[Message] {
let out : Array[Message] = []
let mut pos = 0
while pos < buf.length() {
match decode_at(buf, pos) {
Some((msg, next)) => {
out.push(msg)
pos = next
}
None => break
}
}
out
}