Xlang 序列化格式
跨语言序列化规范
本文定义 Apache Fory xlang 二进制协议的通用线格式,适用于多语言互操作场景。
目标:
- 二进制布局跨语言稳定
- 支持引用跟踪、类型元信息和 schema 演进
- 在流式序列化中支持增量写入共享元信息
类型系统
数据类型
xlang 类型分为:
- 基础类型:bool、整数、浮点、string、binary
- 容器类型:list、set、map、array
- 结构类型:enum、struct、union、ext
- 时间类型:duration、timestamp、date
Polymorphisms
协议支持多态对象。解码端可依据 type meta 判断运行时真实类型,并选择对应 serializer。
Type disambiguation
当某语言类型可映射到多个 Fory 类型(如 fixed/varint/tagged 整数)时,必须通过字段元信息或类型注 解消歧。
Type ID
类型由 internal_type_id 与(可选)user_type_id 共同表达:
- 内建类型通常直接由 internal ID 唯一表示
- 用户类型通过 internal kind + user ID(或命名类型)表示
Internal Type ID Table
核心 internal IDs(示例):
| ID | 类型 |
|---|---|
| 1 | bool |
| 2-20 | 各类数字类型 |
| 21 | string |
| 22 | list |
| 23 | set |
| 24 | map |
| 25 | enum |
| 27 | struct |
| 28 | compatible_struct |
| 31 | ext |
| 33 | union |
| 36 | none |
| 37 | duration |
| 38 | timestamp |
| 39 | date |
| 40+ | decimal/binary/array 等 |
完整映射见 Xlang 类型映射。
Type ID Encoding for User Types
用户类型采用拆分编码:
- 先写 internal type ID(8-bit kind)
- 再写
user_type_id(varuint32)
不做 bit packing,便于实现与调试。
Type mapping
跨语言类型映射总表见 xlang_type_mapping.md。
规范概览
顶层布局:
| fory header | reference meta | type meta | value payload |
协议默认 little-endian。
Fory 头部
头部是 1-byte bitmap:
| reserved(5) | oob(1) | xlang(1) | null(1) |
null=1时值为空,不再写值数据xlang=1表示采用 xlang 格式oob=1表示存在 out-of-band 缓冲区引用
Reference Meta
Reference Flags
| 标记 | 值 | 含义 |
|---|---|---|
| NULL_FLAG | -3 | null |
| REF_FLAG | -2 | 已出现对象,后接 ref id |
| NOT_NULL_VALUE_FLAG | -1 | 非空但不跟踪引用 |
| REF_VALUE_FLAG | 0 | 首次出现的可引用对象 |
Reference Tracking Algorithm
写侧:
- 先判断 null
- 若可引用且已出现,写
REF_FLAG + ref_id - 若可引用且首次出现,写
REF_VALUE_FLAG并登记 - 若不可引用,写
NOT_NULL_VALUE_FLAG
读侧:
- 读取标记
REF_FLAG时按 ref_id 回表REF_VALUE_FLAG时先构造对象再登记NOT_NULL_VALUE_FLAG时直接读值
Reference ID Assignment
ref id 按对象首次出现顺序递增分配,从 0 开始。
When Reference Tracking is Disabled
禁用引用跟踪时,仅使用 null / not-null 两类标记,不维护 ref 表。
Language-Specific Considerations
不同语言应保证:
- 对象身份判定一致(身份而非值相等)
- 容器元素引用语义一致
- 循环引用场景先占位后填充
Type Meta
Type ID encoding
type id 使用 varuint 编码写入。
Type meta payload
在以下情况写额外 type meta:
- 命名类型(
NAMED_*) - compatible struct 需要 TypeDef
- 运行时未声明类型需要动态 type info
Shared Type Meta (streaming)
共享 type meta 采用“索引 + 可选定义体”流式写法:
index_marker = (index << 1) | is_ref
is_ref=1:引用已有 typeis_ref=0:新 type,后接定义体
TypeDef (schema evolution metadata)
TypeDef 用于描述 compatible 模式的字段元信息(字段名/tag、nullable/ref、字段类型)。
Global header
TypeDef 头部包含:
- payload size
- flags(如 compress、has_fields_meta)
- payload hash
TypeDef body
主体包含:
- class 层次信息(父类到子类)
- 每层字段数量与类型标识
- 字段级元信息(名称编码/tag、nullable/ref、field type)
Meta String
meta string 用于 namespace、typename、fieldname 的压缩表示。
Encoding Type IDs
常见编码族:
- UTF8
- LOWER_SPECIAL
- LOWER_UPPER_DIGIT_SPECIAL
- FIRST_TO_LOWER_SPECIAL
- ALL_TO_LOWER_SPECIAL
Character Mapping Tables
LOWER_SPECIAL (5 bits per character)
适用于小写字母 + 高频特殊字符集合。
LOWER_UPPER_DIGIT_SPECIAL (6 bits per character)
适用于大小写字母、数字与特殊字符混合场景。
Encoding Algorithms
LOWER_SPECIAL Encoding
按 5-bit 映射逐字符编码,无法映射的字符需回退至其他编码。
FIRST_TO_LOWER_SPECIAL Encoding
首字符单独处理,其余字符按 LOWER_SPECIAL 编码。
ALL_TO_LOWER_SPECIAL Encoding
先归一化,再按 LOWER_SPECIAL 编码。
Encoding Selection Algorithm
编码选择策略:
- 尝试最紧凑编码
- 若字符集合不满足则降级
- 必要时回退 UTF8
Meta String Header Format
| size_bits | encoding_bits |
当 size 超过短头范围时追加 varuint 扩展长度。
Special Character Sets by Context
不同上下文(包名、类型名、字段名)允许字符集合可不同,编码器需按上下文选择合法表。
Deduplication
meta string 可按会话去重,减少重复写入。
Value Format
Basic types
bool
1 字节:0x00/0x01。
int8
1 字节有符号整型。
int16
2 字节 little-endian。
unsigned int32
固定 4 字节无符号整型。
unsigned varint32
varint32(无符号)编码。
signed int32
固定 4 字节有符号整型。
signed varint32
ZigZag + varint32。
unsigned int64
固定 8 字节无符号整型。
unsigned varint64
varint64(无符号)编码。
unsigned hybrid int64 (TAGGED_UINT64)
tagged 编码,兼顾小值空间效率与大值表示范围。
VarUint36Small
用于字符串头等场景的紧凑长度编码。
signed int64
固定 8 字节有符号整型。
signed varint64
ZigZag + varint64。
signed hybrid int64 (TAGGED_INT64)
tagged int64 编码。
float8
预留/实验类型,生产互操作需谨慎。
float16
16-bit 浮点。
bfloat16
bfloat16 表示。
float32
IEEE 754 float32 little-endian。