1use derive_debug::Dbg;
2use num_enum::TryFromPrimitive;
3
4use crate::utils::formatter::{bytes_dbg, compact_dbg};
5use crate::{MltError, MltResult};
6
7#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
13#[repr(u8)]
14pub enum LogicalTechnique {
15 None = 0b0000_0000,
16 Delta = 0b0010_0000,
17 ComponentwiseDelta = 0b0100_0000,
18 Rle = 0b0110_0000,
19 Morton = 0b1000_0000,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
28#[repr(u8)]
29pub enum LogicalCombination {
30 None = 0b0000_0000,
31 Delta = 0b0010_0000,
32 DeltaRle = 0b0010_1100,
33 ComponentwiseDelta = 0b0100_0000,
34 Rle = 0b0110_0000,
35 Morton = 0b1000_0000,
36 MortonDelta = 0b1000_0100,
37 MortonRle = 0b1000_1100,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum RleLayout {
47 Split,
49 #[cfg(feature = "unstable-v2")]
51 Interleaved,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq)]
56pub enum RleMeta {
57 Split { runs: u32, num_rle_values: u32 },
60 #[cfg(feature = "unstable-v2")]
65 Interleaved { num_rle_values: u32 },
66}
67
68impl RleMeta {
69 #[cfg(feature = "unstable-v2")]
71 #[must_use]
72 pub(crate) fn num_rle_values(self) -> u32 {
73 match self {
74 Self::Split { num_rle_values, .. } => num_rle_values,
75 #[cfg(feature = "unstable-v2")]
76 Self::Interleaved { num_rle_values } => num_rle_values,
77 }
78 }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq)]
83pub struct Morton {
84 pub(crate) bits: u32,
86 pub(crate) shift: u32,
88}
89
90impl Morton {
91 pub fn new(bits: u32, shift: u32) -> MltResult<Self> {
92 if bits <= 16 {
93 Ok(Self { bits, shift })
94 } else {
95 Err(MltError::InvalidMortonBits(bits))
96 }
97 }
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub struct AlpScale {
104 pub(crate) e: u8,
106 pub(crate) f: u8,
108}
109
110#[derive(Clone, Copy, PartialEq, Eq)]
113pub struct Alp {
114 pub(crate) scale: AlpScale,
115 pub(crate) base: i64,
117}
118
119#[cfg(feature = "unstable-v2")]
120impl AlpScale {
121 pub(crate) const MAX_EXPONENT: u8 = 18;
123
124 #[cfg(test)]
128 pub(crate) fn net(self) -> u8 {
129 self.e - self.f
130 }
131}
132
133impl std::fmt::Debug for Alp {
135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136 write!(
137 f,
138 "Alp {{ e: {}, f: {}, base: {} }}",
139 self.scale.e, self.scale.f, self.base
140 )
141 }
142}
143
144#[cfg(feature = "unstable-v2")]
145impl Alp {
146 pub(crate) fn new(e: u8, f: u8, base: i64) -> MltResult<Self> {
147 if e <= AlpScale::MAX_EXPONENT && f <= e {
148 Ok(Self {
149 scale: AlpScale { e, f },
150 base,
151 })
152 } else {
153 Err(MltError::InvalidAlpParams(e, f))
154 }
155 }
156
157 #[expect(
160 clippy::cast_sign_loss,
161 reason = "the bit pattern is the point; `code_at` casts it back"
162 )]
163 pub(crate) fn offset_of(self, code: i64) -> u64 {
164 (code as u64).wrapping_sub(self.base as u64)
165 }
166
167 #[expect(
169 clippy::cast_possible_wrap,
170 clippy::cast_sign_loss,
171 reason = "the bit pattern is the point; inverts `offset_of` exactly"
172 )]
173 pub(crate) fn code_at(self, offset: u64) -> i64 {
174 (self.base as u64).wrapping_add(offset) as i64
175 }
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
181pub enum ValueKind {
182 Int,
183 Bool,
184 Float,
185 Vertex,
186}
187
188#[derive(Debug, Clone, Copy, PartialEq)]
191pub enum IntLogical {
192 None,
193 Delta,
194 Rle(RleMeta),
195 DeltaRle(RleMeta),
196}
197
198#[derive(Debug, Clone, Copy, PartialEq)]
200pub enum BoolLogical {
201 None,
203 ByteRle(RleMeta),
206}
207
208#[derive(Debug, Clone, Copy, PartialEq)]
210pub enum FloatLogical {
211 None,
213 Dict,
217 Alp(Alp),
220}
221
222#[derive(Debug, Clone, Copy, PartialEq)]
224pub enum VertexLogical {
225 None,
226 Delta,
227 ComponentwiseDelta,
228 Morton(Morton),
229 MortonDelta(Morton),
230 MortonRle(Morton),
231}
232
233#[derive(Debug, Clone, Copy, PartialEq)]
237pub enum LogicalEncoding {
238 Int(IntLogical),
239 Bool(BoolLogical),
240 Float(FloatLogical),
241 Vertex(VertexLogical),
242}
243
244impl LogicalEncoding {
245 #[must_use]
247 pub fn kind(self) -> ValueKind {
248 match self {
249 Self::Int(_) => ValueKind::Int,
250 Self::Bool(_) => ValueKind::Bool,
251 Self::Float(_) => ValueKind::Float,
252 Self::Vertex(_) => ValueKind::Vertex,
253 }
254 }
255
256 #[must_use]
258 pub(crate) fn none(kind: ValueKind) -> Self {
259 match kind {
260 ValueKind::Int => Self::Int(IntLogical::None),
261 ValueKind::Bool => Self::Bool(BoolLogical::None),
262 ValueKind::Float => Self::Float(FloatLogical::None),
263 ValueKind::Vertex => Self::Vertex(VertexLogical::None),
264 }
265 }
266
267 #[must_use]
271 pub(crate) fn is_identity(self) -> bool {
272 matches!(
273 self,
274 Self::Int(IntLogical::None)
275 | Self::Bool(BoolLogical::None)
276 | Self::Float(FloatLogical::None | FloatLogical::Dict)
277 | Self::Vertex(VertexLogical::None)
278 )
279 }
280}
281
282#[derive(Debug, PartialEq)]
288pub struct LogicalValue {
289 pub(crate) meta: StreamMeta,
290}
291
292#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
296#[repr(u8)]
297pub enum DictionaryType {
298 None = 0b0000_0000,
299 Single = 0b0000_0001,
300 Shared = 0b0000_0010,
301 Vertex = 0b0000_0011,
302 Morton = 0b0000_0100,
303 Fsst = 0b0000_0101,
304}
305
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
308#[repr(u8)]
309pub enum OffsetType {
310 Vertex = 0b0000_0000,
311 Index = 0b0000_0001,
312 String = 0b0000_0010,
313 Key = 0b0000_0011,
314}
315
316#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
318#[repr(u8)]
319pub enum LengthType {
320 VarBinary = 0b0000_0000,
321 Geometries = 0b0000_0001,
322 Parts = 0b0000_0010,
323 Rings = 0b0000_0011,
324 Triangles = 0b0000_0100,
325 Symbol = 0b0000_0101,
326 Dictionary = 0b0000_0110,
327 #[cfg(feature = "unstable-v2")]
329 Nested = 0b0000_0111,
330}
331
332#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
334pub enum StreamType {
335 Present,
336 Data(DictionaryType),
337 Offset(OffsetType),
338 Length(LengthType),
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
343pub enum PhysicalEncoding {
344 None,
345 FastPFor(FastPForKind),
348 VarInt,
351 #[cfg(feature = "unstable-v2")]
355 BitPacked,
356}
357
358#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
360pub enum FastPForKind {
361 Block256Be,
363 #[cfg(feature = "unstable-v2")]
365 Block128Le,
366}
367
368#[derive(Debug, Clone, Copy, PartialEq)]
371pub struct IntEncoding {
372 pub logical: LogicalEncoding,
373 pub physical: PhysicalEncoding,
374}
375
376impl IntEncoding {
377 #[must_use]
378 pub(crate) const fn new(logical: LogicalEncoding, physical: PhysicalEncoding) -> Self {
379 Self { logical, physical }
380 }
381
382 #[must_use]
383 pub(crate) fn none(kind: ValueKind) -> Self {
384 Self::new(LogicalEncoding::none(kind), PhysicalEncoding::None)
385 }
386}
387
388#[derive(Clone, Copy, Dbg, PartialEq)]
390pub struct StreamMeta {
391 #[dbg(formatter = "compact_dbg")]
392 pub stream_type: StreamType,
393 #[dbg(formatter = "compact_dbg")]
394 pub encoding: IntEncoding,
395 pub(crate) num_values: u32,
396}
397
398impl StreamMeta {
399 #[inline]
400 pub(crate) fn new(stream_type: StreamType, encoding: IntEncoding, num_values: u32) -> Self {
401 Self {
402 stream_type,
403 encoding,
404 num_values,
405 }
406 }
407
408 #[inline]
409 pub(crate) fn new2(
410 stream_type: StreamType,
411 logical: LogicalEncoding,
412 physical: PhysicalEncoding,
413 num_values: usize,
414 ) -> MltResult<Self> {
415 let enc = IntEncoding::new(logical, physical);
416 Ok(Self::new(stream_type, enc, u32::try_from(num_values)?))
417 }
418
419 #[inline]
420 pub(crate) fn new_none(
421 stream_type: StreamType,
422 kind: ValueKind,
423 num_values: usize,
424 ) -> MltResult<Self> {
425 let enc = IntEncoding::none(kind);
426 Ok(Self::new(stream_type, enc, u32::try_from(num_values)?))
427 }
428}
429
430#[derive(Clone, Dbg, PartialEq)]
432pub struct RawStream<'a> {
433 pub meta: StreamMeta,
434 #[dbg(formatter = "bytes_dbg")]
435 pub(crate) data: &'a [u8],
436}
437
438impl<'a> RawStream<'a> {
439 #[must_use]
440 pub(crate) fn new(meta: StreamMeta, data: &'a [u8]) -> Self {
441 Self { meta, data }
442 }
443}