Skip to main content
Version: 1.1.0

Xlang Type Mapping

Note:

  • For type definition, see Type Systems in Spec
  • int16_t[n]/vector<T> indicates int16_t[n]/vector<int16_t>
  • Xlang serialization is the portable wire format shared by Java, Python, C++, Go, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, and Kotlin. Keep type IDs, names, schemas, and compatibility settings aligned across every peer.

User Type IDs

When registering user types (struct/ext/enum/union), the internal type ID is written as the 8-bit kind, and the user type ID is written separately as an unsigned varint32. There is no bit shift/packing, and user_type_id can be in the range 0~0xFFFFFFFE.

Examples:

User IDTypeInternal IDEncoded User IDDecimal
0STRUCT2700
0ENUM2500
1STRUCT2711
1COMPATIBLE_STRUCT2811
2NAMED_STRUCT2922

When reading type IDs:

  • Read internal type ID from the type ID field.
  • If the internal type is a user-registered kind, read user_type_id as varuint32.

Type Mapping

The first column names the Fory schema expression or canonical wire tag. Scalar encoding rows such as fixed int32 and tagged int64 are not FDL type names; FDL spells them as an encoding modifier plus a semantic integer type.

Fory schema / wire tagFory Type IDJavaPythonJavaScript/TypeScriptC++GoRustC#SwiftDartScalaKotlin
bool1bool/BooleanboolBooleanboolboolboolboolBoolboolBooleanBoolean
int82byte/Byteint/pyfory.Int8Type.int8()int8_tint8i8sbyteInt8int + Int8TypeByteByte
int163short/Shortint/pyfory.Int16Type.int16()int16_tint16i16shortInt16int + Int16TypeShortShort
fixed int324int/Integerint/pyfory.FixedInt32Type.int32({ encoding: "fixed" })int32_tint32i32int + S.Fixed<S.Int32>Int32 + .fixedint + fixed metadataInt + fixed metadata@Fixed Int
int325int/Integerint/pyfory.Int32Type.int32()int32_tint32i32intInt32int + Int32TypeIntInt
fixed int646long/Longint/pyfory.FixedInt64Type.int64({ encoding: "fixed" })int64_tint64i64long + S.Fixed<S.Int64>Int64 + .fixedInt64 + fixed metadataLong + fixed metadata@Fixed Long
int647long/Longint/pyfory.Int64Type.int64()int64_tint64i64longInt64int / Int64LongLong
tagged int648long/Longint/pyfory.TaggedInt64Type.int64({ encoding: "tagged" })int64_tint64i64long + S.Tagged<S.Int64>Int64 + .taggedInt64 + tagged metadataLong + tagged metadata@Tagged Long
uint89short/Shortint/pyfory.UInt8Type.uint8()uint8_tuint8u8byteUInt8int + Uint8TypeInt + unsigned metadataUByte
uint1610int/Integerint/pyfory.UInt16Type.uint16()uint16_tuint16u16ushortUInt16int + Uint16TypeInt + unsigned metadataUShort
fixed uint3211long/Longint/pyfory.FixedUInt32Type.uint32({ encoding: "fixed" })uint32_tuint32u32uint + S.Fixed<S.UInt32>UInt32 + .fixedint + fixed uint32 metadataLong + fixed unsigned metadata@Fixed UInt
uint3212long/Longint/pyfory.UInt32Type.uint32()uint32_tuint32u32uintUInt32int + Uint32TypeLong + unsigned metadataUInt
fixed uint6413long/Longint/pyfory.FixedUInt64Type.uint64({ encoding: "fixed" })uint64_tuint64u64ulong + S.Fixed<S.UInt64>UInt64 + .fixedUint64 + fixed metadataLong + fixed unsigned metadata@Fixed ULong
uint6414long/Longint/pyfory.UInt64Type.uint64()uint64_tuint64u64ulongUInt64Uint64Long + unsigned metadataULong
tagged uint6415long/Longint/pyfory.TaggedUInt64Type.uint64({ encoding: "tagged" })uint64_tuint64u64ulong + S.Tagged<S.UInt64>UInt64 + .taggedUint64 + tagged metadataLong + tagged unsigned metadata@Tagged ULong
float816///////////
float1617Float16native float / pyfory.Float16 annotationnumberfory::float16_tfloat16.Float16Float16HalfFloat16double + Float16TypeFloat16Float16
bfloat1618BFloat16native float / pyfory.BFloat16 annotationnumberfory::bfloat16_tbfloat16.BFloat16BFloat16BFloat16BFloat16double + Bfloat16TypeBFloat16BFloat16
float3219float/Floatfloat/pyfory.Float32Type.float32()floatfloat32f32floatFloatFloat32FloatFloat
float6420double/Doublefloat/pyfory.Float64Type.float64()doublefloat64f64doubleDoubledoubleDoubleDouble
string21StringstrStringstringstringString/strstringStringStringStringString
list22List/Collectionlist/tuplearrayvectorsliceVecList<T>[T]List<T>List[T]List<T>
set23Setset/setfory.SetSetHashSet<T>Set<T>Set<T>Set[T]Set<T>
map24MapdictMapunordered_mapmapHashMapDictionary<K,V>[K: V]Map<K, V>Map[K, V]Map<K, V>
enum25Enum subclassesenum subclasses/enum/enum[ForyEnum] enumenumenumScala 3 enumenum class
named_enum26Enum subclassesenum subclasses/enum/enum[ForyEnum] enumenumenumScala 3 enumenum class
struct27pojo/recorddata classobjectstruct/classstructstruct[ForyStruct] class/struct@ForyStruct struct/class@ForyStruct classcase class/classdata class/class
compatible_struct28pojo/recorddata classobjectstruct/classstructstruct[ForyStruct] class/struct@ForyStruct struct/class@ForyStruct classcase class/classdata class/class
named_struct29pojo/recorddata classobjectstruct/classstructstruct[ForyStruct] class/struct@ForyStruct struct/class@ForyStruct classcase class/classdata class/class
named_compatible_struct30pojo/recorddata classobjectstruct/classstructstruct[ForyStruct] class/struct@ForyStruct struct/class@ForyStruct classcase class/classdata class/class
ext31pojo/recorddata classobjectstruct/classstructstruct[ForyStruct] class/struct@ForyStruct struct/class@ForyStruct classcase class/classdata class/class
named_ext32pojo/recorddata classobjectstruct/classstructstruct[ForyStruct] class/struct@ForyStruct struct/class@ForyStruct classcase class/classdata class/class
union33Uniontyping.Union/std::variant<Ts...>/tagged union enum[ForyUnion] ADT recordtagged enum@ForyUnion classADT enumsealed class
none36nullNonenullstd::monostatenil()nullnilnullnullnull
duration37DurationtimedeltaNumberdurationDurationDurationTimeSpanDurationDurationjava.time.Durationkotlin.time.Duration
timestamp38InstantdatetimeNumberstd::chrono::nanosecondsTimeTimestampDateTime/DateTimeOffsetDateTimestampjava.time.Instantjava.time.Instant
date39LocalDatedatetime.dateDatefory::serialization::Datefory.DateDateDateOnlyLocalDateLocalDatejava.time.LocalDatejava.time.LocalDate
decimal40BigDecimalDecimalDecimal/fory.Decimalfory::DecimaldecimalDecimalDecimaljava.math.BigDecimaljava.math.BigDecimal
binary41byte[]bytes/uint8_t[n]/vector<T>[n]uint8/[]TVec<u8>byte[]DataUint8ListArray[Byte]ByteArray
array<bool> (bool_array)43bool[]BoolArray / ndarray(np.bool_)BoolArray / Type.boolArray()bool[n][n]bool/[]TVec<bool>bool[][Bool] + @ArrayFieldBoolListArray[Boolean]BooleanArray
array<int8> (int8_array)44@Int8Type byte[]Int8Array / ndarray(int8)Type.int8Array()int8_t[n]/vector<T>[n]int8/[]TVec<i8>sbyte[][Int8] + @ArrayFieldInt8ListArray[Byte] + metadataByteArray + @ArrayType
array<int16> (int16_array)45short[]Int16Array / ndarray(int16)Type.int16Array()int16_t[n]/vector<T>[n]int16/[]TVec<i16>short[][Int16] + @ArrayFieldInt16ListArray[Short]ShortArray
array<int32> (int32_array)46int[]Int32Array / ndarray(int32)Type.int32Array()int32_t[n]/vector<T>[n]int32/[]TVec<i32>int[][Int32] + @ArrayFieldInt32ListArray[Int]IntArray
array<int64> (int64_array)47long[]Int64Array / ndarray(int64)Type.int64Array()int64_t[n]/vector<T>[n]int64/[]TVec<i64>long[][Int64] + @ArrayFieldInt64ListArray[Long]LongArray
array<uint8> (uint8_array)48@UInt8Type byte[]UInt8Array / ndarray(uint8)Type.uint8Array()uint8_t[n]/vector<T>[n]uint8/[]TVec<u8>byte[][UInt8] + @ArrayFieldUint8ListArray[Byte] + metadataUByteArray
array<uint16> (uint16_array)49@UInt16Type short[]UInt16Array / ndarray(uint16)Type.uint16Array()uint16_t[n]/vector<T>[n]uint16/[]TVec<u16>ushort[][UInt16] + @ArrayFieldUint16ListArray[Short] + metadataUShortArray
array<uint32> (uint32_array)50@UInt32Type int[]UInt32Array / ndarray(uint32)Type.uint32Array()uint32_t[n]/vector<T>[n]uint32/[]TVec<u32>uint[][UInt32] + @ArrayFieldUint32ListArray[Int] + metadataUIntArray
array<uint64> (uint64_array)51@UInt64Type long[]UInt64Array / ndarray(uint64)Type.uint64Array()uint64_t[n]/vector<T>[n]uint64/[]TVec<u64>ulong[][UInt64] + @ArrayFieldUint64ListArray[Long] + metadataULongArray
array<float8> (float8_array)52///////////
array<float16> (float16_array)53Float16Array / @Float16Type short[]Float16Array / ndarray(float16)Float16Array / Type.float16Array()fory::float16_t[n]/std::vector<fory::float16_t>[N]float16.Float16 / []float16.Float16Vec<Float16> / [Float16; N]Half[] / S.Array<S.Float16>[Float16] + @ArrayFieldFloat16ListArray[Short] + metadataFloat16Array
array<bfloat16> (bfloat16_array)54BFloat16Array / @BFloat16Type short[]BFloat16Array / ndarray(bfloat16)BFloat16Array / Type.bfloat16Array()fory::bfloat16_t[n]/std::vector<fory::bfloat16_t>[N]bfloat16.BFloat16 / []bfloat16.BFloat16Vec<BFloat16> / [BFloat16; N]BFloat16[] / S.Array<S.BFloat16>[BFloat16] + @ArrayFieldBfloat16ListArray[Short] + metadataBFloat16Array
array<float32> (float32_array)55float[]Float32Array / ndarray(float32)Type.float32Array()float[n]/vector<T>[n]float32/[]TVec<f32>float[][Float] + @ArrayFieldFloat32ListArray[Float]FloatArray
array<float64> (float64_array)56double[]Float64Array / ndarray(float64)Type.float64Array()double[n]/vector<T>[n]float64/[]TVec<f64>double[][Double] + @ArrayFieldFloat64ListArray[Double]DoubleArray

Notes:

  • Python pyfory.Float16 and pyfory.BFloat16 are reserved annotation markers; scalar values deserialize as native Python float.
  • Python BoolArray, Int8Array, Int16Array, Int32Array, Int64Array, UInt8Array, UInt16Array, UInt32Array, UInt64Array, Float16Array, BFloat16Array, Float32Array, and Float64Array are public dense-array wrappers with list-like sequence behavior.
  • JavaScript BoolArray, fallback Float16Array, and BFloat16Array are public dense-array wrappers backed by Uint8Array or Uint16Array. Scalar float16 and bfloat16 values use number. A JavaScript runtime with native Float16Array may return that native carrier for array<float16>.
  • Java plain byte[] maps to binary. Numeric byte arrays use type-use annotations: @Int8Type byte[] for array<int8> and @UInt8Type byte[] for array<uint8>.
  • Dart uses double plus Float16Type or Bfloat16Type metadata for scalar float16 and bfloat16, BoolList for array<bool>, typed-data lists for integer/float32/float64 arrays, and Float16List / Bfloat16List for array<float16> / array<bfloat16>. Plain Dart List<bool> maps to list<bool> unless a field uses @ArrayField(element: BoolType()) or @ForyField(type: ArrayType(element: BoolType())) with a BoolList carrier.
  • Float16[] and BFloat16[] remain object arrays in xlang mode and serialize with the list wire type.
  • ARRAY (42) is reserved for a future dedicated multi-dimensional array encoding and is not part of the current xlang type-mapping surface.
  • Current xlang uses *_ARRAY for one-dimensional primitive arrays and nested list for multi-dimensional arrays.
  • Kotlin KSP xlang maps UByte, UShort, UInt, and ULong to uint8, uint16, uint32, and uint64. Kotlin primitive and unsigned array carriers map to dense arrays. ByteArray maps to binary by default and to array<int8> when its type use is marked with Fory ArrayType. array<float16> and array<bfloat16> use Java core Float16Array and BFloat16Array.
  • Kotlin xlang duration uses kotlin.time.Duration. Infinite values are not representable by the xlang duration payload and must raise a serialization error.
  • list<T> and array<T> remain distinct schema kinds. In schema-compatible struct/class field matching only, a direct top-level list<T> field may be read as a direct top-level array<T> field, and a direct top-level array<T> field may be read as a direct top-level list<T> field, when T is one of the dense bool/numeric array domains. Integer list element encodings in the same signedness and width domain match the corresponding dense array element domain. The rule does not apply inside nested collection, map, array, union, or generic positions. A peer list<T> payload that declares nullable or ref-tracked elements must raise a compatible-read error when the local matched field is array<T>.

Scala IDL Mapping

The Scala schema IDL target emits Scala 3 source only. The fory-scala runtime artifact remains cross-built for Scala 2.13 and Scala 3.

Fory schema kindScala generated carrier
optional TOption[T]
boolBoolean
int8, int16, int32, int64Byte, Short, Int, Long
uint8, uint16, uint32, uint64Int, Int, Long, Long plus unsigned Fory type metadata
float16, bfloat16JVM Float16 and BFloat16 carriers
float32, float64Float, Double
stringString
binaryArray[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] with signed/unsigned descriptor metadata
array<int16>, array<uint16>Array[Short] with signed/unsigned descriptor metadata
array<int32>, array<uint32>Array[Int] with signed/unsigned descriptor metadata
array<int64>, array<uint64>Array[Long] with signed/unsigned descriptor metadata
array<float16>, array<bfloat16>Array[Short] with reduced-precision descriptor metadata
array<float32>, array<float64>Array[Float], Array[Double]
date, timestamp, durationjava.time.LocalDate, java.time.Instant, java.time.Duration
decimaljava.math.BigDecimal
messageScala 3 case class by default; normal class only for message/union construction cycles
enumScala 3 enum with stable Fory enum IDs on case-level @ForyEnumId annotations
unionScala 3 ADT enum derives ForySerializer
anyAnyRef

Generated Scala descriptor metadata is produced by Scala 3 macro derivation from Scala compile-time types, including nested generics, Option, arrays, scalar encoding annotations, nullability, and @Ref. Java reflection is not the source of truth for generated Scala TypeDef metadata. Scala @Ref metadata is represented by the shared org.apache.fory.annotation.Ref annotation; @Ref is the JVM owner for reference tracking metadata.

Type info

Due to differences between type systems of languages, those types can't be mapped one-to-one between languages.

If one host-language type corresponds to multiple Fory scalar encodings, for example Java long can represent fixed, varint, or tagged int64, the user must provide encoding metadata when the default is not the intended schema.

Type annotation

If the type is a field of another class, users can provide meta hints for fields of a type, or for the whole type. Such information can be provided in other languages too:

  • java: use annotation.
  • cpp: use macro and template.
  • golang: use struct tag.
  • python: use typehint.
  • rust: use macro.

Here is en example:

  • Java:

    class Foo {
    private @Int32Type int f1;
    private List<@Int32Type Integer> f2;
    }
  • Python:

    class Foo:
    f1: pyfory.Int32
    f2: List[pyfory.Int32]