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}
328
329#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
331pub enum StreamType {
332 Present,
333 Data(DictionaryType),
334 Offset(OffsetType),
335 Length(LengthType),
336}
337
338#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
340pub enum PhysicalEncoding {
341 None,
342 FastPFor(FastPForKind),
345 VarInt,
348}
349
350#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
352pub enum FastPForKind {
353 Block256Be,
355 #[cfg(feature = "unstable-v2")]
357 Block128Le,
358}
359
360#[derive(Debug, Clone, Copy, PartialEq)]
363pub struct IntEncoding {
364 pub logical: LogicalEncoding,
365 pub physical: PhysicalEncoding,
366}
367
368impl IntEncoding {
369 #[must_use]
370 pub(crate) const fn new(logical: LogicalEncoding, physical: PhysicalEncoding) -> Self {
371 Self { logical, physical }
372 }
373
374 #[must_use]
375 pub(crate) fn none(kind: ValueKind) -> Self {
376 Self::new(LogicalEncoding::none(kind), PhysicalEncoding::None)
377 }
378}
379
380#[derive(Clone, Copy, Dbg, PartialEq)]
382pub struct StreamMeta {
383 #[dbg(formatter = "compact_dbg")]
384 pub stream_type: StreamType,
385 #[dbg(formatter = "compact_dbg")]
386 pub encoding: IntEncoding,
387 pub(crate) num_values: u32,
388}
389
390impl StreamMeta {
391 #[inline]
392 pub(crate) fn new(stream_type: StreamType, encoding: IntEncoding, num_values: u32) -> Self {
393 Self {
394 stream_type,
395 encoding,
396 num_values,
397 }
398 }
399
400 #[inline]
401 pub(crate) fn new2(
402 stream_type: StreamType,
403 logical: LogicalEncoding,
404 physical: PhysicalEncoding,
405 num_values: usize,
406 ) -> MltResult<Self> {
407 let enc = IntEncoding::new(logical, physical);
408 Ok(Self::new(stream_type, enc, u32::try_from(num_values)?))
409 }
410
411 #[inline]
412 pub(crate) fn new_none(
413 stream_type: StreamType,
414 kind: ValueKind,
415 num_values: usize,
416 ) -> MltResult<Self> {
417 let enc = IntEncoding::none(kind);
418 Ok(Self::new(stream_type, enc, u32::try_from(num_values)?))
419 }
420}
421
422#[derive(Clone, Dbg, PartialEq)]
424pub struct RawStream<'a> {
425 pub meta: StreamMeta,
426 #[dbg(formatter = "bytes_dbg")]
427 pub(crate) data: &'a [u8],
428}
429
430impl<'a> RawStream<'a> {
431 #[must_use]
432 pub(crate) fn new(meta: StreamMeta, data: &'a [u8]) -> Self {
433 Self { meta, data }
434 }
435}