Xlang 类型映射
说明:
- 类型定义请参见规范中的类型系统
int16_t[n]/vector<T>表示int16_t[n]/vector<int16_t>- Xlang 序列化是 Java、Python、C++、Go、Rust、JavaScript/TypeScript、C#、Swift、Dart、 Scala 和 Kotlin 共享的可移植编码格式。所有对等实现的类型 ID、名称、Schema 和兼容性 设置必须保持一致。
用户类型 ID
注册用户类型(struct/ext/enum/union)时,内部类型 ID 以 8 位类型种类写入,用户类型 ID
则单独以无符号 varint32 写入。不进行位移或打包,user_type_id 的取值范围为
0~0xFFFFFFFE。
示例:
| 用户 ID | 类型 | 内部 ID | 编码后的用户 ID | 十进制 |
|---|---|---|---|---|
| 0 | STRUCT | 27 | 0 | 0 |
| 0 | ENUM | 25 | 0 | 0 |
| 1 | STRUCT | 27 | 1 | 1 |
| 1 | COMPATIBLE_STRUCT | 28 | 1 | 1 |
| 2 | NAMED_STRUCT | 29 | 2 | 2 |
读取类型 ID 时:
- 从类型 ID 字段读取内部类型 ID。
- 如果内部类型是用户注册的类型种类,则以 varuint32 读取
user_type_id。
类型映射
第一列列出 Fory Schema 表达式或规范编码标签。fixed int32 和 tagged int64 等
标量编码行并不是 FDL 类型名称;在 FDL 中,它们由编码修饰符与具有语义的整数类型组合表示。
| Fory Schema / 编码标签 | Fory 类型 ID | Java | Python | JavaScript/TypeScript | C++ | Go | Rust | C# | Swift | Dart | Scala | Kotlin |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| bool | 1 | bool/Boolean | bool | Boolean | bool | bool | bool | bool | Bool | bool | Boolean | Boolean |
| int8 | 2 | byte/Byte | int/pyfory.Int8 | Type.int8() | int8_t | int8 | i8 | sbyte | Int8 | int + Int8Type | Byte | Byte |
| int16 | 3 | short/Short | int/pyfory.Int16 | Type.int16() | int16_t | int16 | i16 | short | Int16 | int + Int16Type | Short | Short |
| fixed int32 | 4 | int/Integer | int/pyfory.FixedInt32 | Type.int32({ encoding: "fixed" }) | int32_t | int32 | i32 | int + S.Fixed<S.Int32> | Int32 + .fixed | int + 定长元数据 | Int + 定长元数据 | @Fixed Int |
| int32 | 5 | int/Integer | int/pyfory.Int32 | Type.int32() | int32_t | int32 | i32 | int | Int32 | int + Int32Type | Int | Int |
| fixed int64 | 6 | long/Long | int/pyfory.FixedInt64 | Type.int64({ encoding: "fixed" }) | int64_t | int64 | i64 | long + S.Fixed<S.Int64> | Int64 + .fixed | Int64 + 定长元数据 | Long + 定长元数据 | @Fixed Long |
| int64 | 7 | long/Long | int/pyfory.Int64 | Type.int64() | int64_t | int64 | i64 | long | Int64 | int / Int64 | Long | Long |
| tagged int64 | 8 | long/Long | int/pyfory.TaggedInt64 | Type.int64({ encoding: "tagged" }) | int64_t | int64 | i64 | long + S.Tagged<S.Int64> | Int64 + .tagged | Int64 + tagged 元数据 | Long + tagged 元数据 | @Tagged Long |
| uint8 | 9 | short/Short | int/pyfory.UInt8 | Type.uint8() | uint8_t | uint8 | u8 | byte | UInt8 | int + Uint8Type | Int + unsigned metadata | UByte |
| uint16 | 10 | int/Integer | int/pyfory.UInt16 | Type.uint16() | uint16_t | uint16 | u16 | ushort | UInt16 | int + Uint16Type | Int + unsigned metadata | UShort |
| fixed uint32 | 11 | long/Long | int/pyfory.FixedUInt32 | Type.uint32({ encoding: "fixed" }) | uint32_t | uint32 | u32 | uint + S.Fixed<S.UInt32> | UInt32 + .fixed | int + 定长 uint32 元数据 | Long + 定长无符号元数据 | @Fixed UInt |
| uint32 | 12 | long/Long | int/pyfory.UInt32 | Type.uint32() | uint32_t | uint32 | u32 | uint | UInt32 | int + Uint32Type | Long + 无符号元数据 | UInt |
| fixed uint64 | 13 | long/Long | int/pyfory.FixedUInt64 | Type.uint64({ encoding: "fixed" }) | uint64_t | uint64 | u64 | ulong + S.Fixed<S.UInt64> | UInt64 + .fixed | Uint64 + 定长元数据 | Long + 定长无符号元数据 | @Fixed ULong |
| uint64 | 14 | long/Long | int/pyfory.UInt64 | Type.uint64() | uint64_t | uint64 | u64 | ulong | UInt64 | Uint64 | Long + 无符号元数据 | ULong |
| tagged uint64 | 15 | long/Long | int/pyfory.TaggedUInt64 | Type.uint64({ encoding: "tagged" }) | uint64_t | uint64 | u64 | ulong + S.Tagged<S.UInt64> | UInt64 + .tagged | Uint64 + tagged 元数据 | Long + tagged 无符号元数据 | @Tagged ULong |
| float8 | 16 | / | / | / | / | / | / | / | / | / | / | / |
| float16 | 17 | Float16 | 原生 float / pyfory.Float16 注解 | number | fory::float16_t | float16.Float16 | Float16 | Half | Float16 | double + Float16Type | Float16 | Float16 |
| bfloat16 | 18 | BFloat16 | 原生 float / pyfory.BFloat16 注解 | number | fory::bfloat16_t | bfloat16.BFloat16 | BFloat16 | BFloat16 | BFloat16 | double + Bfloat16Type | BFloat16 | BFloat16 |
| float32 | 19 | float/Float | float/pyfory.Float32 | Type.float32() | float | float32 | f32 | float | Float | Float32 | Float | Float |
| float64 | 20 | double/Double | float/pyfory.Float64 | Type.float64() | double | float64 | f64 | double | Double | double | Double | Double |
| string | 21 | String | str | String | string | string | String/str | string | String | String | String | String |
| list | 22 | List/Collection | list/tuple | array | vector | slice | Vec | List<T> | [T] | List<T> | List[T] | List<T> |
| set | 23 | Set | set | / | set | fory.Set | Set | HashSet<T> | Set<T> | Set<T> | Set[T] | Set<T> |
| map | 24 | Map | dict | Map | unordered_map | map | HashMap | Dictionary<K,V> | [K: V] | Map<K, V> | Map[K, V] | Map<K, V> |
| enum | 25 | Enum 子类 | enum 子类 | / | enum | / | enum | [ForyEnum] enum | enum | enum | Scala 3 enum | enum class |
| named_enum | 26 | Enum 子类 | enum 子类 | / | enum | / | enum | [ForyEnum] enum | enum | enum | Scala 3 enum | enum class |
| struct | 27 | pojo/record | data class | object | struct/class | struct | struct | [ForyStruct] class/struct | @ForyStruct struct/class | @ForyStruct class | case class/class | data class/class |
| compatible_struct | 28 | pojo/record | data class | object | struct/class | struct | struct | [ForyStruct] class/struct | @ForyStruct struct/class | @ForyStruct class | case class/class | data class/class |
| named_struct | 29 | pojo/record | data class | object | struct/class | struct | struct | [ForyStruct] class/struct | @ForyStruct struct/class | @ForyStruct class | case class/class | data class/class |
| named_compatible_struct | 30 | pojo/record | data class | object | struct/class | struct | struct | [ForyStruct] class/struct | @ForyStruct struct/class | @ForyStruct class | case class/class | data class/class |
| ext | 31 | pojo/record | data class | object | struct/class | struct | struct | [ForyStruct] class/struct | @ForyStruct struct/class | @ForyStruct class | case class/class | data class/class |
| named_ext | 32 | pojo/record | data class | object | struct/class | struct | struct | [ForyStruct] class/struct | @ForyStruct struct/class | @ForyStruct class | case class/class | data class/class |
| union | 33 | Union | typing.Union | / | std::variant<Ts...> | / | tagged union enum | [ForyUnion] ADT record | tagged enum | @ForyUnion class | ADT enum | sealed class |
| none | 36 | null | None | null | std::monostate | nil | () | null | nil | null | null | null |
| duration | 37 | Duration | timedelta | Number | fory::Duration | Duration | Duration | TimeSpan | Duration | Duration | java.time.Duration | kotlin.time.Duration |
| timestamp | 38 | Instant | datetime | Number | fory::Timestamp | Time | Timestamp | DateTime/DateTimeOffset | Date | Timestamp | java.time.Instant | java.time.Instant |
| date | 39 | LocalDate | datetime.date | Date | fory::Date | fory.Date | Date | DateOnly | LocalDate | LocalDate | java.time.LocalDate | java.time.LocalDate |
| decimal | 40 | BigDecimal | Decimal | Decimal | fory::serialization::Decimal | fory.Decimal | fory::Decimal | decimal | Decimal | Decimal | java.math.BigDecimal | java.math.BigDecimal |
| binary | 41 | byte[] | bytes | / | uint8_t[n]/vector<T> | [n]uint8/[]T | Vec<u8> | byte[] | Data | Uint8List | Array[Byte] | ByteArray |
array<bool> (bool_array) | 43 | bool[] | BoolArray / ndarray(np.bool_) | BoolArray / Type.boolArray() | bool[n] | [n]bool/[]T | Vec<bool> | bool[] | [Bool] + @ArrayField | BoolList | Array[Boolean] | BooleanArray |
array<int8> (int8_array) | 44 | @Int8Type byte[] | Int8Array / ndarray(int8) | Type.int8Array() | int8_t[n]/vector<T> | [n]int8/[]T | Vec<i8> | sbyte[] | [Int8] + @ArrayField | Int8List | Array[Byte] + 元数据 | ByteArray + @ArrayType |
array<int16> (int16_array) | 45 | short[] | Int16Array / ndarray(int16) | Type.int16Array() | int16_t[n]/vector<T> | [n]int16/[]T | Vec<i16> | short[] | [Int16] + @ArrayField | Int16List | Array[Short] | ShortArray |
array<int32> (int32_array) | 46 | int[] | Int32Array / ndarray(int32) | Type.int32Array() | int32_t[n]/vector<T> | [n]int32/[]T | Vec<i32> | int[] | [Int32] + @ArrayField | Int32List | Array[Int] | IntArray |
array<int64> (int64_array) | 47 | long[] | Int64Array / ndarray(int64) | Type.int64Array() | int64_t[n]/vector<T> | [n]int64/[]T | Vec<i64> | long[] | [Int64] + @ArrayField | Int64List | Array[Long] | LongArray |
array<uint8> (uint8_array) | 48 | @UInt8Type byte[] | UInt8Array / ndarray(uint8) | Type.uint8Array() | uint8_t[n]/vector<T> | [n]uint8/[]T | Vec<u8> | byte[] | [UInt8] + @ArrayField | Uint8List | Array[Byte] + 元数据 | UByteArray |
array<uint16> (uint16_array) | 49 | @UInt16Type short[] | UInt16Array / ndarray(uint16) | Type.uint16Array() | uint16_t[n]/vector<T> | [n]uint16/[]T | Vec<u16> | ushort[] | [UInt16] + @ArrayField | Uint16List | Array[Short] + 元数据 | UShortArray |
array<uint32> (uint32_array) | 50 | @UInt32Type int[] | UInt32Array / ndarray(uint32) | Type.uint32Array() | uint32_t[n]/vector<T> | [n]uint32/[]T | Vec<u32> | uint[] | [UInt32] + @ArrayField | Uint32List | Array[Int] + 元数据 | UIntArray |
array<uint64> (uint64_array) | 51 | @UInt64Type long[] | UInt64Array / ndarray(uint64) | Type.uint64Array() | uint64_t[n]/vector<T> | [n]uint64/[]T | Vec<u64> | ulong[] | [UInt64] + @ArrayField | Uint64List | Array[Long] + 元数据 | ULongArray |
array<float8> (float8_array) | 52 | / | / | / | / | / | / | / | / | / | / | / |
array<float16> (float16_array) | 53 | Float16Array / @Float16Type short[] | Float16Array / ndarray(float16) | Float16Array / Type.float16Array() | fory::float16_t[n]/std::vector<fory::float16_t> | [N]float16.Float16 / []float16.Float16 | Vec<Float16> / [Float16; N] | Half[] / S.Array<S.Float16> | [Float16] + @ArrayField | Float16List | Array[Short] + 元数据 | Float16Array |
array<bfloat16> (bfloat16_array) | 54 | BFloat16Array / @BFloat16Type short[] | BFloat16Array / ndarray(bfloat16) | BFloat16Array / Type.bfloat16Array() | fory::bfloat16_t[n]/std::vector<fory::bfloat16_t> | [N]bfloat16.BFloat16 / []bfloat16.BFloat16 | Vec<BFloat16> / [BFloat16; N] | BFloat16[] / S.Array<S.BFloat16> | [BFloat16] + @ArrayField | Bfloat16List | Array[Short] + 元数据 | BFloat16Array |
array<float32> (float32_array) | 55 | float[] | Float32Array / ndarray(float32) | Type.float32Array() | float[n]/vector<T> | [n]float32/[]T | Vec<f32> | float[] | [Float] + @ArrayField | Float32List | Array[Float] | FloatArray |
array<float64> (float64_array) | 56 | double[] | Float64Array / ndarray(float64) | Type.float64Array() | double[n]/vector<T> | [n]float64/[]T | Vec<f64> | double[] | [Double] + @ArrayField | Float64List | Array[Double] | DoubleArray |
说明:
- Python 的
pyfory.Float16和pyfory.BFloat16是保留的注解标记;标量值反序列化为 Python 原生float。 - Python 的
BoolArray、Int8Array、Int16Array、Int32Array、Int64Array、UInt8Array、UInt16Array、UInt32Array、UInt64Array、Float16Array、BFloat16Array、Float32Array和Float64Array是公开的稠密数组封装,提供类似列表的序列行为。 - JavaScript 的
BoolArray、回退实现Float16Array和BFloat16Array是由Uint8Array或Uint16Array支持的公开稠密数组封装。标量float16和bfloat16值使用number。原生支持Float16Array的 JavaScript 环境可能会为array<float16>返回该原生载体。 - Java 中普通的
byte[]映射到binary。数值字节数组使用类型使用位置注解:array<int8>使用@Int8Type byte[],array<uint8>使用@UInt8Type byte[]。 - Dart 对标量
float16和bfloat16使用double,并分别附加Float16Type或Bfloat16Type元数据;array<bool>使用BoolList;整数、float32 和 float64 数组使用 typed-data 列表;array<float16>和array<bfloat16>分别使用Float16List和Bfloat16List。普通 DartList<bool>映射到list<bool>;但如果字段使用@ArrayField(element: BoolType()),或使用@ForyField(type: ArrayType(element: BoolType()))并以BoolList为载体,则不适用此默认映射。 - 在 xlang 模式下,
Float16[]和BFloat16[]仍是对象数组,并使用list编码类型进行序列化。 ARRAY (42)保留给未来专用的多维数组编码,不属于当前 xlang 类型映射范围。- 当前 xlang 对一维基本类型数组使用
*_ARRAY,对多维数组使用嵌套的list。 - 在生成的 Schema 和动态
std::any值中,C++ xlang 的date、timestamp和duration分别映射到fory::Date、fory::Timestamp和fory::Duration。std::chrono时间类型 只能作为显式的 C++ 序列化和反序列化目标。 - Kotlin KSP xlang 将
UByte、UShort、UInt和ULong分别映射到uint8、uint16、uint32和uint64。Kotlin 基本类型和无符号数组载体映射到稠密数组。ByteArray默认映射到binary;当其类型使用位置通过 ForyArrayType标记时,则映射到array<int8>。array<float16>和array<bfloat16>使用 Java 核心库的Float16Array和BFloat16Array。 - Kotlin xlang 的
duration使用kotlin.time.Duration。xlang duration 载荷无法表示无穷值, 遇到无穷值时必须抛出序列化错误。 list<T>和array<T>是不同的 Schema 种类。仅在兼容模式的 struct/class 字段匹配中, 当T属于稠密布尔或数值数组域时,顶层直接字段list<T>可以读取为顶层直接字段array<T>,反向也同样允许。具有相同符号性和位宽的整数列表元素编码,与对应的稠密数组 元素域相匹配。该规则不适用于嵌套的 collection、map、array、union 或泛型位置。对等端的list<T?>元素 Schema 仍可与本地array<T>字段兼容匹配;如果实际载荷包含 null 元素, 稠密数组读取器会抛出兼容读取错误,而不是强制转换该值。列表元素的引用跟踪帧结构与元素 Schema 是否可空相互独立;当本地匹配字段为array<T>,而运行时无法在不经过泛型或引用 路径的情况下将其具体化时,兼容字段分类可能会拒绝这种引用跟踪帧结构。binary和array<uint8>是不同的 Schema 种类。仅在兼容模式的 struct/class 字段匹配中, 顶层直接字段binary可以读取为顶层直接字段array<uint8>,反向也可以读取为相同的字节序列。 该规则不适用于嵌套的 collection、map、array、union 或泛型位置,也不包括array<int8>。- 上表是规范的 xlang Schema 映射。在兼容模式的 struct/class 字段匹配中,兼容读取器可以应用
xlang_serialization_spec.md定义的标量字段适配规则。这些规则不会改变 TypeDef 元数据、动态根 类型映射、同 Schema 模式,也不适用于嵌套的 collection、map、array、union 或泛型位置。
Scala IDL 映射
Scala Schema IDL 目标仅生成 Scala 3 源代码。fory-scala 构件仍会同时为 Scala 2.13 和
Scala 3 进行交叉构建。
| Fory Schema 种类 | Scala 生成载体 |
|---|---|
optional T | Option[T] |
bool | Boolean |
int8, int16, int32, int64 | Byte, Short, Int, Long |
uint8, uint16, uint32, uint64 | Int、Int、Long、Long,并附加 Fory 无符号类型元数据 |
float16, bfloat16 | JVM Float16 和 BFloat16 载体 |
float32, float64 | Float, Double |
string | String |
binary | Array[Byte] |
list<T>, set<T>, map<K, V> | List[T], Set[T], Map[K, V] |
array<bool> | Array[Boolean] |
array<int8>, array<uint8> | 带有有符号/无符号描述符元数据的 Array[Byte] |
array<int16>, array<uint16> | 带有有符号/无符号描述符元数据的 Array[Short] |
array<int32>, array<uint32> | 带有有符号/无符号描述符元数据的 Array[Int] |
array<int64>, array<uint64> | 带有有符号/无符号描述符元数据的 Array[Long] |
array<float16>, array<bfloat16> | 带有低精度描述符元数据的 Array[Short] |
array<float32>, array<float64> | Array[Float], Array[Double] |
date, timestamp, duration | java.time.LocalDate, java.time.Instant, java.time.Duration |
decimal | java.math.BigDecimal |
message | 默认生成 Scala 3 case class;仅在 message/union 构造循环中使用普通 class |
enum | Scala 3 enum,通过 case 级 @ForyEnumId 注解提供稳定的 Fory 枚举 ID |
union | Scala 3 ADT enum derives ForySerializer |
any | AnyRef |
生成的 Scala 描述符元数据由 Scala 3 宏基于 Scala 编译期类型推导得出,其中包括嵌套泛型、
Option、数组、标量编码注解、可空性和 @Ref。Java 反射并不是生成 Scala TypeDef 元数据的
事实来源。Scala 的 @Ref 元数据由共享注解 org.apache.fory.annotation.Ref 表示;@Ref
是 JVM 引用跟踪元数据的所有者。
类型信息
由于各语言的类型系统存在差异,这些类型无法在语言之间一一映射。
如果一种宿主语言类型对应多种 Fory 标量编码,例如 Java long 可以表示定长、varint 或
tagged int64,当默认编码并非预期 Schema 时,用户必须提供编码元数据。
类型注解
当类型作为另一个类的字段时,用户可以为该类型的字段或整个类型提供元数据提示。 其他语言也可以提供这类信息:
- Java:使用注解。
- C++:使用宏和模板。
- Go:使用 struct tag。
- Python:使用类型提示。
- Rust:使用宏。
示例:
-
Java:
class Foo {private @Int32Type int f1;private List<@Int32Type Integer> f2;} -
Python:
class Foo:f1: pyfory.Int32f2: List[pyfory.Int32]