// segment.mbt — KCP Segment 线格式(K1;刀1 Bytes 化)
//
// Segment = 24B 固定头 + 可选 data。线格式全 Bytes:构造单趟 makei、
// 零 push 循环(茗篇 moonbit_throughput_ming.md 刀1;Bytes 不可变 ⇒
// send 侧载荷零拷贝共享)。
///|
pub const CMD_PUSH : Int32 = 81
///|
pub const CMD_ACK : Int32 = 82
///|
pub const CMD_WASK : Int32 = 83
///|
pub const CMD_WINS : Int32 = 84
///|
pub const HEADER_SIZE : Int32 = 24
///|
/// KCP 段:24B 线格式字段 + snd_buf 在途态。data 为 FixedArray[Byte]
/// (纪律不可变,发送侧与载荷共享同一对象,零拷贝;批拷走 unsafe_blit)。
pub(all) struct KcpSegment {
mut conv : Int32
mut cmd : Int32
mut frg : Int32
mut wnd : Int32
mut ts : Int32
mut sn : Int32
mut una : Int32
mut len : Int32
mut data : FixedArray[Byte]
mut xmit : Int32
mut fastack : Int32
mut resendts : Int32
mut rto : Int32
}
///|
/// 线格式段构造(在途态清零)。
fn KcpSegment::make(
conv : Int32,
cmd : Int32,
frg : Int32,
wnd : Int32,
ts : Int32,
sn : Int32,
una : Int32,
data : FixedArray[Byte],
) -> KcpSegment {
{
conv,
cmd,
frg,
wnd,
ts,
sn,
una,
len: data.length(),
data,
xmit: 0,
fastack: 0,
resendts: 0,
rto: 0,
}
}
///|
/// 段线字节求值:i < 24 为头字段 little-endian 展开,其余为载荷直通。
fn segment_byte(seg : KcpSegment, data_len : Int32, i : Int32) -> Byte {
if i < 4 {
((seg.conv >> (i * 8)) & 0xFF).to_byte()
} else if i == 4 {
seg.cmd.to_byte()
} else if i == 5 {
seg.frg.to_byte()
} else if i < 8 {
((seg.wnd >> ((i - 6) * 8)) & 0xFF).to_byte()
} else if i < 12 {
((seg.ts >> ((i - 8) * 8)) & 0xFF).to_byte()
} else if i < 16 {
((seg.sn >> ((i - 12) * 8)) & 0xFF).to_byte()
} else if i < 20 {
((seg.una >> ((i - 16) * 8)) & 0xFF).to_byte()
} else if i < 24 {
((data_len >> ((i - 20) * 8)) & 0xFF).to_byte()
} else {
seg.data[i - 24]
}
}
///|
/// 编码 Segment 为线格式 Bytes(单趟 makei,头 + 载荷一体成形)。
pub fn encode_segment(seg : KcpSegment) -> FixedArray[Byte] {
let data_len = seg.data.length()
FixedArray::makei(HEADER_SIZE + data_len, fn(i) {
segment_byte(seg, data_len, i)
})
}
///|
/// 读取 little-endian u16。
fn read_u16(buf : FixedArray[Byte], offset : Int32) -> Int32 {
buf[offset].to_int() | (buf[offset + 1].to_int() << 8)
}
///|
/// 读取 little-endian u32。
fn read_u32(buf : FixedArray[Byte], offset : Int32) -> Int32 {
buf[offset].to_int() |
(buf[offset + 1].to_int() << 8) |
(buf[offset + 2].to_int() << 16) |
(buf[offset + 3].to_int() << 24)
}
///|
/// 从 Bytes 报文 offset 处解码一段。返回 (段, 消耗字节数);
/// 头不完整或声明 len 越界返回 None。
pub fn decode_segment(
buf : FixedArray[Byte],
offset : Int32,
) -> (KcpSegment, Int32)? {
let remaining = buf.length() - offset
if remaining < HEADER_SIZE {
return None
}
let conv = read_u32(buf, offset)
let cmd = buf[offset + 4].to_int()
let frg = buf[offset + 5].to_int()
let wnd = read_u16(buf, offset + 6)
let ts = read_u32(buf, offset + 8)
let sn = read_u32(buf, offset + 12)
let una = read_u32(buf, offset + 16)
let data_len = read_u32(buf, offset + 20)
if offset + HEADER_SIZE + data_len > buf.length() {
return None
}
let data : FixedArray[Byte] = FixedArray::make(data_len, 0b0)
if data_len > 0 {
FixedArray::unsafe_blit(data, 0, buf, offset + HEADER_SIZE, data_len)
}
let seg = KcpSegment::make(conv, cmd, frg, wnd, ts, sn, una, data)
Some((seg, HEADER_SIZE + data_len))
}