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 std::fmt::Formatter<'_>) -> std::fmt::Result {
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 }
}
}