use std::fmt::{Display, Formatter, Result as FmtResult};
use derive_debug::Dbg;
use num_enum::TryFromPrimitive;
use crate::utils::formatter::{bytes_dbg, compact_dbg};
use crate::{MltError, MltResult};
#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum LogicalTechnique {
None = 0b0000_0000,
Delta = 0b0010_0000,
ComponentwiseDelta = 0b0100_0000,
Rle = 0b0110_0000,
Morton = 0b1000_0000,
}
#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum LogicalCombination {
None = 0b0000_0000,
Delta = 0b0010_0000,
DeltaRle = 0b0010_1100,
ComponentwiseDelta = 0b0100_0000,
Rle = 0b0110_0000,
Morton = 0b1000_0000,
MortonDelta = 0b1000_0100,
MortonRle = 0b1000_1100,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RleLayout {
Split,
#[cfg(feature = "unstable-v2")]
Interleaved,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RleMeta {
Split { runs: u32, num_rle_values: u32 },
#[cfg(feature = "unstable-v2")]
Interleaved { num_rle_values: u32 },
}
impl RleMeta {
#[cfg(feature = "unstable-v2")]
#[must_use]
pub(crate) fn num_rle_values(self) -> u32 {
match self {
Self::Split { num_rle_values, .. } => num_rle_values,
#[cfg(feature = "unstable-v2")]
Self::Interleaved { num_rle_values } => num_rle_values,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Morton {
pub(crate) bits: u32,
pub(crate) shift: u32,
}
impl Morton {
pub fn new(bits: u32, shift: u32) -> MltResult<Self> {
if bits <= 16 {
Ok(Self { bits, shift })
} else {
Err(MltError::InvalidMortonBits(bits))
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AlpScale {
pub(crate) e: u8,
pub(crate) f: u8,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Alp {
pub(crate) scale: AlpScale,
pub(crate) base: i64,
}
#[cfg(feature = "unstable-v2")]
impl AlpScale {
pub(crate) const MAX_EXPONENT: u8 = 18;
#[cfg(test)]
pub(crate) fn net(self) -> u8 {
self.e - self.f
}
}
impl std::fmt::Debug for Alp {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(
f,
"Alp {{ e: {}, f: {}, base: {} }}",
self.scale.e, self.scale.f, self.base
)
}
}
#[cfg(feature = "unstable-v2")]
impl Alp {
pub(crate) fn new(e: u8, f: u8, base: i64) -> MltResult<Self> {
if e <= AlpScale::MAX_EXPONENT && f <= e {
Ok(Self {
scale: AlpScale { e, f },
base,
})
} else {
Err(MltError::InvalidAlpParams(e, f))
}
}
#[expect(
clippy::cast_sign_loss,
reason = "the bit pattern is the point; `code_at` casts it back"
)]
pub(crate) fn offset_of(self, code: i64) -> u64 {
(code as u64).wrapping_sub(self.base as u64)
}
#[expect(
clippy::cast_possible_wrap,
clippy::cast_sign_loss,
reason = "the bit pattern is the point; inverts `offset_of` exactly"
)]
pub(crate) fn code_at(self, offset: u64) -> i64 {
(self.base as u64).wrapping_add(offset) as i64
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValueKind {
Int,
Bool,
Float,
Vertex,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum IntLogical {
None,
Delta,
Rle(RleMeta),
DeltaRle(RleMeta),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BoolLogical {
None,
ByteRle(RleMeta),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FloatLogical {
None,
Dict,
Alp(Alp),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum VertexLogical {
None,
Delta,
ComponentwiseDelta,
Morton(Morton),
MortonDelta(Morton),
MortonRle(Morton),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LogicalEncoding {
Int(IntLogical),
Bool(BoolLogical),
Float(FloatLogical),
Vertex(VertexLogical),
}
impl LogicalEncoding {
#[must_use]
pub fn kind(self) -> ValueKind {
match self {
Self::Int(_) => ValueKind::Int,
Self::Bool(_) => ValueKind::Bool,
Self::Float(_) => ValueKind::Float,
Self::Vertex(_) => ValueKind::Vertex,
}
}
#[must_use]
pub(crate) fn none(kind: ValueKind) -> Self {
match kind {
ValueKind::Int => Self::Int(IntLogical::None),
ValueKind::Bool => Self::Bool(BoolLogical::None),
ValueKind::Float => Self::Float(FloatLogical::None),
ValueKind::Vertex => Self::Vertex(VertexLogical::None),
}
}
#[must_use]
pub(crate) fn is_identity(self) -> bool {
matches!(
self,
Self::Int(IntLogical::None)
| Self::Bool(BoolLogical::None)
| Self::Float(FloatLogical::None | FloatLogical::Dict)
| Self::Vertex(VertexLogical::None)
)
}
}
#[derive(Debug, PartialEq)]
pub struct LogicalValue {
pub(crate) meta: StreamMeta,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
#[repr(u8)]
pub enum DictionaryType {
None = 0b0000_0000,
Single = 0b0000_0001,
Shared = 0b0000_0010,
Vertex = 0b0000_0011,
Morton = 0b0000_0100,
Fsst = 0b0000_0101,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
#[repr(u8)]
pub enum OffsetType {
Vertex = 0b0000_0000,
Index = 0b0000_0001,
String = 0b0000_0010,
Key = 0b0000_0011,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
#[repr(u8)]
pub enum LengthType {
VarBinary = 0b0000_0000,
Geometries = 0b0000_0001,
Parts = 0b0000_0010,
Rings = 0b0000_0011,
Triangles = 0b0000_0100,
Symbol = 0b0000_0101,
Dictionary = 0b0000_0110,
#[cfg(feature = "unstable-v2")]
Nested = 0b0000_0111,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum StreamType {
Present,
Data(DictionaryType),
Offset(OffsetType),
Length(LengthType),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum PhysicalEncoding {
None,
FastPFor(FastPForKind),
VarInt,
#[cfg(feature = "unstable-v2")]
BitPacked,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum FastPForKind {
Block256Be,
#[cfg(feature = "unstable-v2")]
Block128Le,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct IntEncoding {
pub logical: LogicalEncoding,
pub physical: PhysicalEncoding,
}
impl IntEncoding {
#[must_use]
pub(crate) const fn new(logical: LogicalEncoding, physical: PhysicalEncoding) -> Self {
Self { logical, physical }
}
#[must_use]
pub(crate) fn none(kind: ValueKind) -> Self {
Self::new(LogicalEncoding::none(kind), PhysicalEncoding::None)
}
}
#[derive(Clone, Copy, Dbg, PartialEq)]
pub struct StreamMeta {
#[dbg(formatter = "compact_dbg")]
pub stream_type: StreamType,
#[dbg(formatter = "compact_dbg")]
pub encoding: IntEncoding,
pub(crate) num_values: u32,
}
impl StreamMeta {
#[inline]
pub(crate) fn new(stream_type: StreamType, encoding: IntEncoding, num_values: u32) -> Self {
Self {
stream_type,
encoding,
num_values,
}
}
#[inline]
pub(crate) fn new2(
stream_type: StreamType,
logical: LogicalEncoding,
physical: PhysicalEncoding,
num_values: usize,
) -> MltResult<Self> {
let enc = IntEncoding::new(logical, physical);
Ok(Self::new(stream_type, enc, u32::try_from(num_values)?))
}
#[inline]
pub(crate) fn new_none(
stream_type: StreamType,
kind: ValueKind,
num_values: usize,
) -> MltResult<Self> {
let enc = IntEncoding::none(kind);
Ok(Self::new(stream_type, enc, u32::try_from(num_values)?))
}
}
#[derive(Clone, Dbg, PartialEq)]
pub struct RawStream<'a> {
pub meta: StreamMeta,
#[dbg(formatter = "bytes_dbg")]
pub(crate) data: &'a [u8],
}
impl<'a> RawStream<'a> {
#[must_use]
pub(crate) fn new(meta: StreamMeta, data: &'a [u8]) -> Self {
Self { meta, data }
}
}
impl Display for StreamType {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::Present => f.write_str("present"),
Self::Data(dict) => {
let name = match dict {
DictionaryType::None => return f.write_str("data"),
DictionaryType::Single => "single",
DictionaryType::Shared => "shared",
DictionaryType::Vertex => "vertex",
DictionaryType::Morton => "morton",
DictionaryType::Fsst => "fsst",
};
write!(f, "data[{name}]")
}
Self::Offset(offset) => {
let name = match offset {
OffsetType::Vertex => "vertex",
OffsetType::Index => "index",
OffsetType::String => "string",
OffsetType::Key => "key",
};
write!(f, "offset[{name}]")
}
Self::Length(length) => {
let name = match length {
LengthType::VarBinary => "var-binary",
LengthType::Geometries => "geometries",
LengthType::Parts => "parts",
LengthType::Rings => "rings",
LengthType::Triangles => "triangles",
LengthType::Symbol => "symbol",
LengthType::Dictionary => "dictionary",
#[cfg(feature = "unstable-v2")]
LengthType::Nested => "nested",
};
write!(f, "length[{name}]")
}
}
}
}
impl Display for LogicalEncoding {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let (kind, enc) = match self {
Self::Int(int) => (
"int",
match int {
IntLogical::None => "none",
IntLogical::Delta => "delta",
IntLogical::Rle(_) => "rle",
IntLogical::DeltaRle(_) => "delta-rle",
},
),
Self::Bool(b) => (
"bool",
match b {
BoolLogical::None => "none",
BoolLogical::ByteRle(_) => "byte-rle",
},
),
Self::Float(float) => (
"float",
match float {
FloatLogical::None => "none",
FloatLogical::Dict => "dict",
FloatLogical::Alp(_) => "alp",
},
),
Self::Vertex(vertex) => (
"vertex",
match vertex {
VertexLogical::None => "none",
VertexLogical::Delta => "delta",
VertexLogical::ComponentwiseDelta => "componentwise-delta",
VertexLogical::Morton(_) => "morton",
VertexLogical::MortonDelta(_) => "morton-delta",
VertexLogical::MortonRle(_) => "morton-rle",
},
),
};
write!(f, "{kind}/{enc}")
}
}
impl Display for PhysicalEncoding {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::None => f.write_str("none"),
Self::VarInt => f.write_str("varint"),
Self::FastPFor(kind) => {
let name = match kind {
FastPForKind::Block256Be => "256be",
#[cfg(feature = "unstable-v2")]
FastPForKind::Block128Le => "128le",
};
write!(f, "fastpfor[{name}]")
}
#[cfg(feature = "unstable-v2")]
Self::BitPacked => f.write_str("bit-packed"),
}
}
}