use shape_value::{HeapKind, NativeKind};
pub const SENTINEL: u8 = 255;
pub const C_FLOAT64: u8 = 0;
pub const C_NULLABLE_FLOAT64: u8 = 1;
pub const C_INT8: u8 = 2;
pub const C_NULLABLE_INT8: u8 = 3;
pub const C_UINT8: u8 = 4;
pub const C_NULLABLE_UINT8: u8 = 5;
pub const C_INT16: u8 = 6;
pub const C_NULLABLE_INT16: u8 = 7;
pub const C_UINT16: u8 = 8;
pub const C_NULLABLE_UINT16: u8 = 9;
pub const C_INT32: u8 = 10;
pub const C_NULLABLE_INT32: u8 = 11;
pub const C_UINT32: u8 = 12;
pub const C_NULLABLE_UINT32: u8 = 13;
pub const C_INT64: u8 = 14;
pub const C_NULLABLE_INT64: u8 = 15;
pub const C_UINT64: u8 = 16;
pub const C_NULLABLE_UINT64: u8 = 17;
pub const C_INTSIZE: u8 = 18;
pub const C_NULLABLE_INTSIZE: u8 = 19;
pub const C_UINTSIZE: u8 = 20;
pub const C_NULLABLE_UINTSIZE: u8 = 21;
pub const C_BOOL: u8 = 22;
pub const C_STRING: u8 = 23;
pub const C_FLOAT32: u8 = 24;
pub const C_CHAR: u8 = 25;
pub const C_STRING_V2: u8 = 26;
pub const C_DECIMAL_V2: u8 = 27;
pub const C_NULL: u8 = 28;
pub const PTR_BASE: u8 = 128;
#[inline]
pub const fn encode(kind: NativeKind) -> u8 {
match kind {
NativeKind::Float64 => C_FLOAT64,
NativeKind::NullableFloat64 => C_NULLABLE_FLOAT64,
NativeKind::Int8 => C_INT8,
NativeKind::NullableInt8 => C_NULLABLE_INT8,
NativeKind::UInt8 => C_UINT8,
NativeKind::NullableUInt8 => C_NULLABLE_UINT8,
NativeKind::Int16 => C_INT16,
NativeKind::NullableInt16 => C_NULLABLE_INT16,
NativeKind::UInt16 => C_UINT16,
NativeKind::NullableUInt16 => C_NULLABLE_UINT16,
NativeKind::Int32 => C_INT32,
NativeKind::NullableInt32 => C_NULLABLE_INT32,
NativeKind::UInt32 => C_UINT32,
NativeKind::NullableUInt32 => C_NULLABLE_UINT32,
NativeKind::Int64 => C_INT64,
NativeKind::NullableInt64 => C_NULLABLE_INT64,
NativeKind::UInt64 => C_UINT64,
NativeKind::NullableUInt64 => C_NULLABLE_UINT64,
NativeKind::IntSize => C_INTSIZE,
NativeKind::NullableIntSize => C_NULLABLE_INTSIZE,
NativeKind::UIntSize => C_UINTSIZE,
NativeKind::NullableUIntSize => C_NULLABLE_UINTSIZE,
NativeKind::Bool => C_BOOL,
NativeKind::String => C_STRING,
NativeKind::Float32 => C_FLOAT32,
NativeKind::Char => C_CHAR,
NativeKind::StringV2 => C_STRING_V2,
NativeKind::DecimalV2 => C_DECIMAL_V2,
NativeKind::Null => C_NULL,
NativeKind::Ptr(hk) => PTR_BASE.wrapping_add(hk as u8),
}
}
#[inline]
pub fn decode(code: u8) -> Option<NativeKind> {
match code {
SENTINEL => None,
C_FLOAT64 => Some(NativeKind::Float64),
C_NULLABLE_FLOAT64 => Some(NativeKind::NullableFloat64),
C_INT8 => Some(NativeKind::Int8),
C_NULLABLE_INT8 => Some(NativeKind::NullableInt8),
C_UINT8 => Some(NativeKind::UInt8),
C_NULLABLE_UINT8 => Some(NativeKind::NullableUInt8),
C_INT16 => Some(NativeKind::Int16),
C_NULLABLE_INT16 => Some(NativeKind::NullableInt16),
C_UINT16 => Some(NativeKind::UInt16),
C_NULLABLE_UINT16 => Some(NativeKind::NullableUInt16),
C_INT32 => Some(NativeKind::Int32),
C_NULLABLE_INT32 => Some(NativeKind::NullableInt32),
C_UINT32 => Some(NativeKind::UInt32),
C_NULLABLE_UINT32 => Some(NativeKind::NullableUInt32),
C_INT64 => Some(NativeKind::Int64),
C_NULLABLE_INT64 => Some(NativeKind::NullableInt64),
C_UINT64 => Some(NativeKind::UInt64),
C_NULLABLE_UINT64 => Some(NativeKind::NullableUInt64),
C_INTSIZE => Some(NativeKind::IntSize),
C_NULLABLE_INTSIZE => Some(NativeKind::NullableIntSize),
C_UINTSIZE => Some(NativeKind::UIntSize),
C_NULLABLE_UINTSIZE => Some(NativeKind::NullableUIntSize),
C_BOOL => Some(NativeKind::Bool),
C_STRING => Some(NativeKind::String),
C_FLOAT32 => Some(NativeKind::Float32),
C_CHAR => Some(NativeKind::Char),
C_STRING_V2 => Some(NativeKind::StringV2),
C_DECIMAL_V2 => Some(NativeKind::DecimalV2),
C_NULL => Some(NativeKind::Null),
c if c >= PTR_BASE && c < SENTINEL => {
decode_heap_kind(c - PTR_BASE).map(NativeKind::Ptr)
}
_ => None,
}
}
#[inline]
fn decode_heap_kind(ord: u8) -> Option<HeapKind> {
Some(match ord {
0 => HeapKind::String,
1 => HeapKind::TypedObject,
2 => HeapKind::Closure,
3 => HeapKind::Decimal,
4 => HeapKind::BigInt,
5 => HeapKind::DataTable,
6 => HeapKind::Future,
7 => HeapKind::TaskGroup,
8 => HeapKind::TypedArray,
9 => HeapKind::Temporal,
10 => HeapKind::TableView,
11 => HeapKind::Content,
12 => HeapKind::Instant,
13 => HeapKind::IoHandle,
14 => HeapKind::NativeScalar,
15 => HeapKind::NativeView,
16 => HeapKind::Char,
17 => HeapKind::HashMap,
18 => HeapKind::FilterExpr,
19 => HeapKind::Reference,
20 => HeapKind::SharedCell,
21 => HeapKind::HashSet,
22 => HeapKind::Iterator,
23 => HeapKind::Deque,
24 => HeapKind::Channel,
25 => HeapKind::PriorityQueue,
26 => HeapKind::Range,
27 => HeapKind::Result,
28 => HeapKind::Option,
29 => HeapKind::TraitObject,
30 => HeapKind::Mutex,
31 => HeapKind::Atomic,
32 => HeapKind::Lazy,
33 => HeapKind::ModuleFn,
_ => return None,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scalar_roundtrip() {
for kind in [
NativeKind::Float64,
NativeKind::Int64,
NativeKind::UInt64,
NativeKind::Bool,
NativeKind::String,
NativeKind::Int32,
NativeKind::NullableInt64,
] {
let code = encode(kind);
assert!(code < PTR_BASE, "scalar code {} must be < PTR_BASE", code);
assert_eq!(decode(code), Some(kind));
}
}
#[test]
fn ptr_roundtrip() {
for hk in [
HeapKind::Closure,
HeapKind::TypedArray,
HeapKind::TypedObject,
HeapKind::HashMap,
HeapKind::Result,
HeapKind::Option,
HeapKind::String,
] {
let kind = NativeKind::Ptr(hk);
let code = encode(kind);
assert!(
code >= PTR_BASE && code < SENTINEL,
"Ptr code {} must be in [PTR_BASE, SENTINEL)",
code
);
assert_eq!(decode(code), Some(kind));
}
}
#[test]
fn sentinel_decodes_to_none() {
assert_eq!(decode(SENTINEL), None);
}
}