// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0
///|
/// The internal type ID: the byte that begins a value's type meta, and the
/// number every language agrees on.
///
/// The numbers are the specification's, and they are not ours to choose: a
/// reader in Go reads `21` as a string because the type mapping says so. The
/// variant names are the specification's too, except `NoneType`, which Python
/// calls `NoneType` and the table calls `NONE`; MoonBit spells nothing `None`,
/// so the spelling here is Python's.
pub(all) enum TypeId {
Unknown
Bool
Int8
Int16
Int32
VarInt32
Int64
VarInt64
TaggedInt64
UInt8
UInt16
UInt32
VarUInt32
UInt64
VarUInt64
TaggedUInt64
Float8
Float16
BFloat16
Float32
Float64
String
List
Set
Map
Enum
NamedEnum
Struct
CompatibleStruct
NamedStruct
NamedCompatibleStruct
Ext
NamedExt
Union
TypedUnion
NamedUnion
NoneType
Duration
Timestamp
Date
Decimal
Binary
Array
BoolArray
Int8Array
Int16Array
Int32Array
Int64Array
UInt8Array
UInt16Array
UInt32Array
UInt64Array
Float8Array
Float16Array
BFloat16Array
Float32Array
Float64Array
} derive(Eq, Debug)
///|
pub extend TypeId with Eq::{not_equal, equal}
///|
pub extend TypeId with Debug::{to_repr}
///|
/// The name of the type, which is how a fixture and an error message name it.
pub impl Show for TypeId with fn output(self, logger) {
logger.write_string("\{self.to_repr()}")
}
///|
pub extend TypeId with Show::{to_string, output}
///|
/// The number on the wire.
pub fn TypeId::code(self : TypeId) -> Int32 {
match self {
Unknown => 0
Bool => 1
Int8 => 2
Int16 => 3
Int32 => 4
VarInt32 => 5
Int64 => 6
VarInt64 => 7
TaggedInt64 => 8
UInt8 => 9
UInt16 => 10
UInt32 => 11
VarUInt32 => 12
UInt64 => 13
VarUInt64 => 14
TaggedUInt64 => 15
Float8 => 16
Float16 => 17
BFloat16 => 18
Float32 => 19
Float64 => 20
String => 21
List => 22
Set => 23
Map => 24
Enum => 25
NamedEnum => 26
Struct => 27
CompatibleStruct => 28
NamedStruct => 29
NamedCompatibleStruct => 30
Ext => 31
NamedExt => 32
Union => 33
TypedUnion => 34
NamedUnion => 35
NoneType => 36
Duration => 37
Timestamp => 38
Date => 39
Decimal => 40
Binary => 41
Array => 42
BoolArray => 43
Int8Array => 44
Int16Array => 45
Int32Array => 46
Int64Array => 47
UInt8Array => 48
UInt16Array => 49
UInt32Array => 50
UInt64Array => 51
Float8Array => 52
Float16Array => 53
BFloat16Array => 54
Float32Array => 55
Float64Array => 56
}
}
///|
/// The type a number on the wire stands for, when the mapping has one.
///
/// `57` and up are unmapped: the specification reserves them, and a reader that
/// met one could not know what to build.
pub fn TypeId::of(code : Int32) -> TypeId? {
match code {
0 => Some(Unknown)
1 => Some(Bool)
2 => Some(Int8)
3 => Some(Int16)
4 => Some(Int32)
5 => Some(VarInt32)
6 => Some(Int64)
7 => Some(VarInt64)
8 => Some(TaggedInt64)
9 => Some(UInt8)
10 => Some(UInt16)
11 => Some(UInt32)
12 => Some(VarUInt32)
13 => Some(UInt64)
14 => Some(VarUInt64)
15 => Some(TaggedUInt64)
16 => Some(Float8)
17 => Some(Float16)
18 => Some(BFloat16)
19 => Some(Float32)
20 => Some(Float64)
21 => Some(String)
22 => Some(List)
23 => Some(Set)
24 => Some(Map)
25 => Some(Enum)
26 => Some(NamedEnum)
27 => Some(Struct)
28 => Some(CompatibleStruct)
29 => Some(NamedStruct)
30 => Some(NamedCompatibleStruct)
31 => Some(Ext)
32 => Some(NamedExt)
33 => Some(Union)
34 => Some(TypedUnion)
35 => Some(NamedUnion)
36 => Some(NoneType)
37 => Some(Duration)
38 => Some(Timestamp)
39 => Some(Date)
40 => Some(Decimal)
41 => Some(Binary)
42 => Some(Array)
43 => Some(BoolArray)
44 => Some(Int8Array)
45 => Some(Int16Array)
46 => Some(Int32Array)
47 => Some(Int64Array)
48 => Some(UInt8Array)
49 => Some(UInt16Array)
50 => Some(UInt32Array)
51 => Some(UInt64Array)
52 => Some(Float8Array)
53 => Some(Float16Array)
54 => Some(BFloat16Array)
55 => Some(Float32Array)
56 => Some(Float64Array)
_ => None
}
}
///|
/// Whether a field of this type belongs to the primitive groups when the field
/// order is decided: numbers and booleans, not strings and not containers.
pub fn TypeId::is_primitive(self : TypeId) -> Bool {
match self {
Bool
| Int8
| Int16
| Int32
| VarInt32
| Int64
| VarInt64
| TaggedInt64
| UInt8
| UInt16
| UInt32
| VarUInt32
| UInt64
| VarUInt64
| TaggedUInt64
| Float8
| Float16
| BFloat16
| Float32
| Float64 => true
_ => false
}
}
///|
/// Whether the width of this type is decided by the value rather than by the
/// type: the compressed integers, which sort after every fixed-width one.
pub fn TypeId::is_compressed(self : TypeId) -> Bool {
match self {
VarInt32 | VarInt64 | TaggedInt64 | VarUInt32 | VarUInt64 | TaggedUInt64 =>
true
_ => false
}
}
///|
/// How many bytes a value of this type occupies, when the type decides it.
///
/// `None` for the compressed integers and for everything whose length is part
/// of the value.
pub fn TypeId::fixed_size(self : TypeId) -> Int32? {
match self {
Bool | Int8 | UInt8 | Float8 => Some(1)
Int16 | UInt16 | Float16 | BFloat16 => Some(2)
Int32 | UInt32 | Float32 => Some(4)
Int64 | UInt64 | Float64 => Some(8)
_ => None
}
}
///|
/// Whether a value of this kind names a type of the writer's own, and so
/// carries a user type ID or type meta after the type ID byte.
///
/// These are the kinds a field must write type information for. An enum or a
/// union inside a struct field does not: its type is the field's declared one.
pub fn TypeId::is_user(self : TypeId) -> Bool {
match self {
Struct
| CompatibleStruct
| NamedStruct
| NamedCompatibleStruct
| Ext
| NamedExt
| Enum
| NamedEnum
| Union
| TypedUnion
| NamedUnion => true
_ => false
}
}
///|
/// Whether this kind is one of the five that hold a user type ID in
/// same-schema mode: the four that a struct can be, and the enum.
pub fn TypeId::is_named_by_id(self : TypeId) -> Bool {
match self {
Struct | CompatibleStruct | NamedStruct | NamedCompatibleStruct | Enum =>
true
_ => false
}
}
///|
/// Whether values of this kind are counted: a list, a set or a map.
pub fn TypeId::is_collection(self : TypeId) -> Bool {
match self {
List | Set | Map => true
_ => false
}
}
///|
/// Whether this kind is one of the dense primitive arrays: a run of raw
/// little-endian elements rather than a list of values.
pub fn TypeId::is_dense(self : TypeId) -> Bool {
match self {
BoolArray
| Int8Array
| Int16Array
| Int32Array
| Int64Array
| UInt8Array
| UInt16Array
| UInt32Array
| UInt64Array
| Float8Array
| Float16Array
| BFloat16Array
| Float32Array
| Float64Array => true
_ => false
}
}
///|
/// The element type of a dense array, which is what the bytes are.
pub fn TypeId::element(self : TypeId) -> TypeId? {
match self {
BoolArray => Some(Bool)
Int8Array => Some(Int8)
Int16Array => Some(Int16)
Int32Array => Some(Int32)
Int64Array => Some(Int64)
UInt8Array => Some(UInt8)
UInt16Array => Some(UInt16)
UInt32Array => Some(UInt32)
UInt64Array => Some(UInt64)
Float8Array => Some(Float8)
Float16Array => Some(Float16)
BFloat16Array => Some(BFloat16)
Float32Array => Some(Float32)
Float64Array => Some(Float64)
_ => None
}
}
///|
/// The dense array of this element type, when there is one.
///
/// Only the fourteen element types above have one; `array` stays a
/// list, which is why the answer is optional.
pub fn TypeId::arrayed(self : TypeId) -> TypeId? {
match self {
Bool => Some(BoolArray)
Int8 => Some(Int8Array)
Int16 => Some(Int16Array)
Int32 => Some(Int32Array)
Int64 => Some(Int64Array)
UInt8 => Some(UInt8Array)
UInt16 => Some(UInt16Array)
UInt32 => Some(UInt32Array)
UInt64 => Some(UInt64Array)
Float8 => Some(Float8Array)
Float16 => Some(Float16Array)
BFloat16 => Some(BFloat16Array)
Float32 => Some(Float32Array)
Float64 => Some(Float64Array)
_ => None
}
}