1use std::fmt::{Display, Formatter, Result as FmtResult};
2
3use derive_debug::Dbg;
4use num_enum::TryFromPrimitive;
5
6use crate::utils::formatter::{bytes_dbg, compact_dbg};
7use crate::{MltError, MltResult};
8
9#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
15#[repr(u8)]
16pub enum LogicalTechnique {
17 None = 0b0000_0000,
18 Delta = 0b0010_0000,
19 ComponentwiseDelta = 0b0100_0000,
20 Rle = 0b0110_0000,
21 Morton = 0b1000_0000,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
30#[repr(u8)]
31pub enum LogicalCombination {
32 None = 0b0000_0000,
33 Delta = 0b0010_0000,
34 DeltaRle = 0b0010_1100,
35 ComponentwiseDelta = 0b0100_0000,
36 Rle = 0b0110_0000,
37 Morton = 0b1000_0000,
38 MortonDelta = 0b1000_0100,
39 MortonRle = 0b1000_1100,
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum RleLayout {
49 Split,
51 #[cfg(feature = "unstable-v2")]
53 Interleaved,
54}
55
56#[derive(Debug, Clone, Copy, PartialEq)]
58pub enum RleMeta {
59 Split { runs: u32, num_rle_values: u32 },
62 #[cfg(feature = "unstable-v2")]
67 Interleaved { num_rle_values: u32 },
68}
69
70impl RleMeta {
71 #[cfg(feature = "unstable-v2")]
73 #[must_use]
74 pub(crate) fn num_rle_values(self) -> u32 {
75 match self {
76 Self::Split { num_rle_values, .. } => num_rle_values,
77 #[cfg(feature = "unstable-v2")]
78 Self::Interleaved { num_rle_values } => num_rle_values,
79 }
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq)]
85pub struct Morton {
86 pub(crate) bits: u32,
88 pub(crate) shift: u32,
90}
91
92impl Morton {
93 pub fn new(bits: u32, shift: u32) -> MltResult<Self> {
94 if bits <= 16 {
95 Ok(Self { bits, shift })
96 } else {
97 Err(MltError::InvalidMortonBits(bits))
98 }
99 }
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub struct AlpScale {
106 pub(crate) e: u8,
108 pub(crate) f: u8,
110}
111
112#[derive(Clone, Copy, PartialEq, Eq)]
115pub struct Alp {
116 pub(crate) scale: AlpScale,
117 pub(crate) base: i64,
119}
120
121#[cfg(feature = "unstable-v2")]
122impl AlpScale {
123 pub(crate) const MAX_EXPONENT: u8 = 18;
126
127 #[cfg(test)]
131 pub(crate) fn net(self) -> u8 {
132 self.e - self.f
133 }
134}
135
136impl std::fmt::Debug for Alp {
138 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
139 write!(
140 f,
141 "Alp {{ e: {}, f: {}, base: {} }}",
142 self.scale.e, self.scale.f, self.base
143 )
144 }
145}
146
147#[cfg(feature = "unstable-v2")]
148impl Alp {
149 pub(crate) fn new(e: u8, f: u8, base: i64) -> MltResult<Self> {
150 if e <= AlpScale::MAX_EXPONENT && f <= e {
151 Ok(Self {
152 scale: AlpScale { e, f },
153 base,
154 })
155 } else {
156 Err(MltError::InvalidAlpParams(e, f))
157 }
158 }
159
160 #[expect(
164 clippy::cast_sign_loss,
165 reason = "the bit pattern is the point; `code_at` casts it back"
166 )]
167 pub(crate) fn offset_of(self, code: i64) -> u64 {
168 (code as u64).wrapping_sub(self.base as u64)
169 }
170
171 #[expect(
173 clippy::cast_possible_wrap,
174 clippy::cast_sign_loss,
175 reason = "the bit pattern is the point; inverts `offset_of` exactly"
176 )]
177 pub(crate) fn code_at(self, offset: u64) -> i64 {
178 (self.base as u64).wrapping_add(offset) as i64
179 }
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185pub enum ValueKind {
186 Int,
187 Bool,
188 Float,
189 Vertex,
190}
191
192#[derive(Debug, Clone, Copy, PartialEq)]
195pub enum IntLogical {
196 None,
197 Delta,
198 Rle(RleMeta),
199 DeltaRle(RleMeta),
200}
201
202#[derive(Debug, Clone, Copy, PartialEq)]
204pub enum BoolLogical {
205 None,
207 ByteRle(RleMeta),
210}
211
212#[derive(Debug, Clone, Copy, PartialEq)]
214pub enum FloatLogical {
215 None,
217 Dict,
221 Alp(Alp),
224}
225
226#[derive(Debug, Clone, Copy, PartialEq)]
228pub enum VertexLogical {
229 None,
230 Delta,
231 ComponentwiseDelta,
232 Morton(Morton),
233 MortonDelta(Morton),
234 MortonRle(Morton),
235}
236
237#[derive(Debug, Clone, Copy, PartialEq)]
241pub enum LogicalEncoding {
242 Int(IntLogical),
243 Bool(BoolLogical),
244 Float(FloatLogical),
245 Vertex(VertexLogical),
246}
247
248impl LogicalEncoding {
249 #[must_use]
251 pub fn kind(self) -> ValueKind {
252 match self {
253 Self::Int(_) => ValueKind::Int,
254 Self::Bool(_) => ValueKind::Bool,
255 Self::Float(_) => ValueKind::Float,
256 Self::Vertex(_) => ValueKind::Vertex,
257 }
258 }
259
260 #[must_use]
262 pub(crate) fn none(kind: ValueKind) -> Self {
263 match kind {
264 ValueKind::Int => Self::Int(IntLogical::None),
265 ValueKind::Bool => Self::Bool(BoolLogical::None),
266 ValueKind::Float => Self::Float(FloatLogical::None),
267 ValueKind::Vertex => Self::Vertex(VertexLogical::None),
268 }
269 }
270
271 #[must_use]
275 pub(crate) fn is_identity(self) -> bool {
276 matches!(
277 self,
278 Self::Int(IntLogical::None)
279 | Self::Bool(BoolLogical::None)
280 | Self::Float(FloatLogical::None | FloatLogical::Dict)
281 | Self::Vertex(VertexLogical::None)
282 )
283 }
284}
285
286#[derive(Debug, PartialEq)]
292pub struct LogicalValue {
293 pub(crate) meta: StreamMeta,
294}
295
296#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
300#[repr(u8)]
301pub enum DictionaryType {
302 None = 0b0000_0000,
303 Single = 0b0000_0001,
304 Shared = 0b0000_0010,
305 Vertex = 0b0000_0011,
306 Morton = 0b0000_0100,
307 Fsst = 0b0000_0101,
308}
309
310#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
312#[repr(u8)]
313pub enum OffsetType {
314 Vertex = 0b0000_0000,
315 Index = 0b0000_0001,
316 String = 0b0000_0010,
317 Key = 0b0000_0011,
318}
319
320#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
322#[repr(u8)]
323pub enum LengthType {
324 VarBinary = 0b0000_0000,
325 Geometries = 0b0000_0001,
326 Parts = 0b0000_0010,
327 Rings = 0b0000_0011,
328 Triangles = 0b0000_0100,
329 Symbol = 0b0000_0101,
330 Dictionary = 0b0000_0110,
331 #[cfg(feature = "unstable-v2")]
333 Nested = 0b0000_0111,
334}
335
336#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
338pub enum StreamType {
339 Present,
340 Data(DictionaryType),
341 Offset(OffsetType),
342 Length(LengthType),
343}
344
345#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
347pub enum PhysicalEncoding {
348 None,
349 FastPFor(FastPForKind),
352 VarInt,
355 #[cfg(feature = "unstable-v2")]
359 BitPacked,
360}
361
362#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
364pub enum FastPForKind {
365 Block256Be,
367 #[cfg(feature = "unstable-v2")]
369 Block128Le,
370}
371
372#[derive(Debug, Clone, Copy, PartialEq)]
375pub struct IntEncoding {
376 pub logical: LogicalEncoding,
377 pub physical: PhysicalEncoding,
378}
379
380impl IntEncoding {
381 #[must_use]
382 pub(crate) const fn new(logical: LogicalEncoding, physical: PhysicalEncoding) -> Self {
383 Self { logical, physical }
384 }
385
386 #[must_use]
387 pub(crate) fn none(kind: ValueKind) -> Self {
388 Self::new(LogicalEncoding::none(kind), PhysicalEncoding::None)
389 }
390}
391
392#[derive(Clone, Copy, Dbg, PartialEq)]
394pub struct StreamMeta {
395 #[dbg(formatter = "compact_dbg")]
396 pub stream_type: StreamType,
397 #[dbg(formatter = "compact_dbg")]
398 pub encoding: IntEncoding,
399 pub(crate) num_values: u32,
400}
401
402impl StreamMeta {
403 #[inline]
404 pub(crate) fn new(stream_type: StreamType, encoding: IntEncoding, num_values: u32) -> Self {
405 Self {
406 stream_type,
407 encoding,
408 num_values,
409 }
410 }
411
412 #[inline]
413 pub(crate) fn new2(
414 stream_type: StreamType,
415 logical: LogicalEncoding,
416 physical: PhysicalEncoding,
417 num_values: usize,
418 ) -> MltResult<Self> {
419 let enc = IntEncoding::new(logical, physical);
420 Ok(Self::new(stream_type, enc, u32::try_from(num_values)?))
421 }
422
423 #[inline]
424 pub(crate) fn new_none(
425 stream_type: StreamType,
426 kind: ValueKind,
427 num_values: usize,
428 ) -> MltResult<Self> {
429 let enc = IntEncoding::none(kind);
430 Ok(Self::new(stream_type, enc, u32::try_from(num_values)?))
431 }
432}
433
434#[derive(Clone, Dbg, PartialEq)]
436pub struct RawStream<'a> {
437 pub meta: StreamMeta,
438 #[dbg(formatter = "bytes_dbg")]
439 pub(crate) data: &'a [u8],
440}
441
442impl<'a> RawStream<'a> {
443 #[must_use]
444 pub(crate) fn new(meta: StreamMeta, data: &'a [u8]) -> Self {
445 Self { meta, data }
446 }
447}
448
449impl Display for StreamType {
453 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
455 match self {
456 Self::Present => f.write_str("present"),
457 Self::Data(dict) => {
458 let name = match dict {
459 DictionaryType::None => return f.write_str("data"),
460 DictionaryType::Single => "single",
461 DictionaryType::Shared => "shared",
462 DictionaryType::Vertex => "vertex",
463 DictionaryType::Morton => "morton",
464 DictionaryType::Fsst => "fsst",
465 };
466 write!(f, "data[{name}]")
467 }
468 Self::Offset(offset) => {
469 let name = match offset {
470 OffsetType::Vertex => "vertex",
471 OffsetType::Index => "index",
472 OffsetType::String => "string",
473 OffsetType::Key => "key",
474 };
475 write!(f, "offset[{name}]")
476 }
477 Self::Length(length) => {
478 let name = match length {
479 LengthType::VarBinary => "var-binary",
480 LengthType::Geometries => "geometries",
481 LengthType::Parts => "parts",
482 LengthType::Rings => "rings",
483 LengthType::Triangles => "triangles",
484 LengthType::Symbol => "symbol",
485 LengthType::Dictionary => "dictionary",
486 #[cfg(feature = "unstable-v2")]
487 LengthType::Nested => "nested",
488 };
489 write!(f, "length[{name}]")
490 }
491 }
492 }
493}
494
495impl Display for LogicalEncoding {
496 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
500 let (kind, enc) = match self {
501 Self::Int(int) => (
502 "int",
503 match int {
504 IntLogical::None => "none",
505 IntLogical::Delta => "delta",
506 IntLogical::Rle(_) => "rle",
507 IntLogical::DeltaRle(_) => "delta-rle",
508 },
509 ),
510 Self::Bool(b) => (
511 "bool",
512 match b {
513 BoolLogical::None => "none",
514 BoolLogical::ByteRle(_) => "byte-rle",
515 },
516 ),
517 Self::Float(float) => (
518 "float",
519 match float {
520 FloatLogical::None => "none",
521 FloatLogical::Dict => "dict",
522 FloatLogical::Alp(_) => "alp",
523 },
524 ),
525 Self::Vertex(vertex) => (
526 "vertex",
527 match vertex {
528 VertexLogical::None => "none",
529 VertexLogical::Delta => "delta",
530 VertexLogical::ComponentwiseDelta => "componentwise-delta",
531 VertexLogical::Morton(_) => "morton",
532 VertexLogical::MortonDelta(_) => "morton-delta",
533 VertexLogical::MortonRle(_) => "morton-rle",
534 },
535 ),
536 };
537 write!(f, "{kind}/{enc}")
538 }
539}
540
541impl Display for PhysicalEncoding {
542 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
544 match self {
545 Self::None => f.write_str("none"),
546 Self::VarInt => f.write_str("varint"),
547 Self::FastPFor(kind) => {
548 let name = match kind {
549 FastPForKind::Block256Be => "256be",
550 #[cfg(feature = "unstable-v2")]
551 FastPForKind::Block128Le => "128le",
552 };
553 write!(f, "fastpfor[{name}]")
554 }
555 #[cfg(feature = "unstable-v2")]
556 Self::BitPacked => f.write_str("bit-packed"),
557 }
558 }
559}