// ===== encode:EtfTerm → ETF 字节流(带 VERSION_MAGIC)=====
// 规范形输出:atom→'w'(SMALL_ATOM_UTF8,OTP26 主形);float→'F';list→108+106;
// 整数→97(<256)/98;pid→'X';ref→'Z'(creation u32)。
///|
pub fn encode(t : EtfTerm) -> Bytes raise EtfError {
let out : Array[Byte] = [VERSION_MAGIC.to_byte()]
encode_term(t, out)
Bytes::from_array(out)
}
///|
/// 段内编码(无 magic):组合用
pub fn encode_term(t : EtfTerm, out : Array[Byte]) -> Unit raise EtfError {
match t {
EtfTerm::EAtom(s) => encode_atom(s, out)
EtfTerm::EInt(v) =>
if v >= 0 && v < 256 {
out.push(TAG_SMALL_INTEGER.to_byte())
out.push((v & 255).to_byte())
} else {
out.push(TAG_INTEGER.to_byte())
put_u32(out, v)
}
EtfTerm::EFloat(f) => {
out.push(TAG_NEW_FLOAT.to_byte())
put_u64(out, f.reinterpret_as_uint64())
}
EtfTerm::ETuple(items) => {
out.push(TAG_SMALL_TUPLE.to_byte())
out.push(items.length().to_byte())
for it in items {
encode_term(it, out)
}
}
EtfTerm::EList(items) => {
out.push(TAG_LIST.to_byte())
put_u32(out, items.length())
for it in items {
encode_term(it, out)
}
out.push(TAG_NIL.to_byte())
}
EtfTerm::ENil => out.push(TAG_NIL.to_byte())
EtfTerm::EString(s) => {
out.push(TAG_STRING.to_byte())
put_u16(out, s.length())
for ch in s {
out.push((ch.to_int() & 255).to_byte())
}
}
EtfTerm::EBinary(b) => {
out.push(TAG_BINARY.to_byte())
put_u32(out, b.length())
for byte in b {
out.push(byte)
}
}
EtfTerm::EMap(pairs) => {
out.push(TAG_MAP.to_byte())
put_u32(out, pairs.length())
for pair in pairs {
encode_term(pair.0, out)
encode_term(pair.1, out)
}
}
EtfTerm::EPid(node, id, serial, creation) => {
out.push(TAG_NEW_PID.to_byte())
encode_atom(node, out)
put_u32(out, id)
put_u32(out, serial)
put_u32(out, creation)
}
EtfTerm::EPort(node, id, creation) => {
out.push(TAG_NEW_PORT.to_byte())
encode_atom(node, out)
put_u32(out, id)
put_u32(out, creation)
}
EtfTerm::ERef(node, id, _, creation) => {
// 'Z' NEW_REFERENCE:idlen=1(骨架 v0 单字 id)
out.push(TAG_NEW_REFERENCE.to_byte())
put_u16(out, 1)
encode_atom(node, out)
put_u32(out, creation)
put_u32(out, id)
}
}
}
///|
/// atom 规范形:'w'(len u8;>255 退 'v' len u16)
fn encode_atom(s : String, out : Array[Byte]) -> Unit raise EtfError {
let n = s.length()
if n < 256 {
out.push(TAG_SMALL_ATOM_UTF8.to_byte())
out.push(n.to_byte())
} else {
out.push(TAG_ATOM_UTF8.to_byte())
put_u16(out, n)
}
for ch in s {
let code = ch.to_int()
if code > 255 {
raise EtfError::Malformed("atom 非 latin1 域(骨架 v0)")
}
out.push((code & 255).to_byte())
}
}
///|
fn put_u16(out : Array[Byte], v : Int32) -> Unit {
out.push(((v >> 8) & 255).to_byte())
out.push((v & 255).to_byte())
}
///|
fn put_u32(out : Array[Byte], v : Int32) -> Unit {
out.push(((v >> 24) & 255).to_byte())
out.push(((v >> 16) & 255).to_byte())
out.push(((v >> 8) & 255).to_byte())
out.push((v & 255).to_byte())
}
///|
fn put_u64(out : Array[Byte], v : UInt64) -> Unit {
for k in 0..<8 {
let sh = 56 - k * 8
out.push(((v >> sh).to_int() & 255).to_byte())
}
}