Skip to main content

mlt_core/decoder/stream/
model.rs

1use derive_debug::Dbg;
2use num_enum::TryFromPrimitive;
3
4use crate::utils::formatter::{bytes_dbg, compact_dbg};
5use crate::{MltError, MltResult};
6
7/// Logical encoding technique used for a column, as stored in the tile
8///
9/// Variants are already shifted into the primary logical field of the v1 encoding byte (bits 7-5),
10/// so that field is matched with a mask rather than shifted down first.
11/// The secondary field (bits 4-2) holds the same patterns three bits lower.
12#[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/// The combinations of the two [`LogicalTechnique`] fields that are legal on the wire
23///
24/// Each variant is the whole logical part of the v1 encoding byte, i.e. the primary field
25/// (bits 7-5) or-ed with the secondary field (bits 4-2).
26/// Any other pairing of the two fields is rejected while parsing.
27#[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/// Which RLE stream layout the encoder should produce.
41///
42/// A data-less selector chosen up front by the wire format (see
43/// [`WireVersion::rle_layout`](crate::encoder::WireVersion)); the realized
44/// per-stream metadata is [`RleMeta`], whose variants mirror these.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum RleLayout {
47    /// Tag `0x01`: all run lengths first, then all values.
48    Split,
49    /// Tag `0x02`: `(run_length, value)` pairs. Requires the `unstable-v2` feature.
50    #[cfg(feature = "unstable-v2")]
51    Interleaved,
52}
53
54/// Metadata for RLE decoding, one variant per [`RleLayout`].
55#[derive(Debug, Clone, Copy, PartialEq)]
56pub enum RleMeta {
57    /// Tag `0x01`: physically-decoded words are `[run_len × runs][value × runs]`.
58    /// `runs` is the split point; `num_rle_values` is the expanded element count.
59    Split { runs: u32, num_rle_values: u32 },
60    /// Tag `0x02`: physically-decoded words are `(run_len, value)` pairs. The run
61    /// count is derived from the data length, so only the expanded element count
62    /// (`num_rle_values`, from the stream's count context) is carried.
63    /// Requires the `unstable-v2` feature.
64    #[cfg(feature = "unstable-v2")]
65    Interleaved { num_rle_values: u32 },
66}
67
68impl RleMeta {
69    /// The total expanded element count, common to both layouts.
70    #[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/// Metadata for Morton decoding
82#[derive(Debug, Clone, Copy, PartialEq)]
83pub struct Morton {
84    /// Number of bits used
85    pub(crate) bits: u32,
86    /// Coordinate shift
87    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/// How should the stream be interpreted at the logical level (second pass of decoding)
101#[derive(Debug, Clone, Copy, PartialEq)]
102pub enum LogicalEncoding {
103    None,
104    Delta,
105    DeltaRle(RleMeta),
106    ComponentwiseDelta,
107    Rle(RleMeta),
108    Morton(Morton),
109    MortonDelta(Morton),
110    MortonRle(Morton),
111}
112
113/// Carries the stream metadata needed to perform the logical decode pass.
114///
115/// Construct with [`LogicalValue::new`] after the physical decode pass fills a
116/// `&[u32]` or `&[u64]` buffer, then call the appropriate `decode_*` method,
117/// passing that slice as `data`.
118#[derive(Debug, PartialEq)]
119pub struct LogicalValue {
120    pub(crate) meta: StreamMeta,
121}
122
123// Physical encoding types
124
125/// Dictionary type used for a column, as stored in the tile
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
127#[repr(u8)]
128pub enum DictionaryType {
129    None = 0b0000_0000,
130    Single = 0b0000_0001,
131    Shared = 0b0000_0010,
132    Vertex = 0b0000_0011,
133    Morton = 0b0000_0100,
134    Fsst = 0b0000_0101,
135}
136
137/// Offset type used for a column, as stored in the tile
138#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
139#[repr(u8)]
140pub enum OffsetType {
141    Vertex = 0b0000_0000,
142    Index = 0b0000_0001,
143    String = 0b0000_0010,
144    Key = 0b0000_0011,
145}
146
147/// Length type used for a column, as stored in the tile
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
149#[repr(u8)]
150pub enum LengthType {
151    VarBinary = 0b0000_0000,
152    Geometries = 0b0000_0001,
153    Parts = 0b0000_0010,
154    Rings = 0b0000_0011,
155    Triangles = 0b0000_0100,
156    Symbol = 0b0000_0101,
157    Dictionary = 0b0000_0110,
158}
159
160/// How should the stream be interpreted at the physical level (first pass of decoding)
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
162pub enum StreamType {
163    Present,
164    Data(DictionaryType),
165    Offset(OffsetType),
166    Length(LengthType),
167}
168
169/// Physical encoding used for a column, as stored in the tile
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, TryFromPrimitive)]
171#[repr(u8)]
172pub enum PhysicalEncoding {
173    None = 0b0000_0000,
174    /// Preferred, tends to produce the best compression ratio and decoding performance.
175    /// But currently limited to 32-bit integer.
176    FastPFor256 = 0b0000_0001,
177    /// Can produce better results in combination with a heavyweight compression scheme like `Gzip`.
178    /// Simple compression scheme where the encoding is easier to implement compared to `FastPfor`.
179    VarInt = 0b0000_0010,
180}
181
182// RawStream types
183
184#[derive(Debug, Clone, Copy, PartialEq)]
185pub struct IntEncoding {
186    pub logical: LogicalEncoding,
187    pub physical: PhysicalEncoding,
188}
189
190impl IntEncoding {
191    #[must_use]
192    pub(crate) const fn new(logical: LogicalEncoding, physical: PhysicalEncoding) -> Self {
193        Self { logical, physical }
194    }
195
196    #[must_use]
197    pub(crate) const fn none() -> Self {
198        Self::new(LogicalEncoding::None, PhysicalEncoding::None)
199    }
200}
201
202/// Metadata about an encoded stream
203#[derive(Clone, Copy, Dbg, PartialEq)]
204pub struct StreamMeta {
205    #[dbg(formatter = "compact_dbg")]
206    pub stream_type: StreamType,
207    #[dbg(formatter = "compact_dbg")]
208    pub encoding: IntEncoding,
209    pub(crate) num_values: u32,
210}
211
212impl StreamMeta {
213    #[inline]
214    pub(crate) fn new(stream_type: StreamType, encoding: IntEncoding, num_values: u32) -> Self {
215        Self {
216            stream_type,
217            encoding,
218            num_values,
219        }
220    }
221
222    #[inline]
223    pub(crate) fn new2(
224        stream_type: StreamType,
225        logical: LogicalEncoding,
226        physical: PhysicalEncoding,
227        num_values: usize,
228    ) -> MltResult<Self> {
229        let enc = IntEncoding::new(logical, physical);
230        Ok(Self::new(stream_type, enc, u32::try_from(num_values)?))
231    }
232
233    #[inline]
234    pub(crate) fn new_none(stream_type: StreamType, num_values: usize) -> MltResult<Self> {
235        let enc = IntEncoding::none();
236        Ok(Self::new(stream_type, enc, u32::try_from(num_values)?))
237    }
238}
239
240/// Representation of an encoded stream
241#[derive(Clone, Dbg, PartialEq)]
242pub struct RawStream<'a> {
243    pub meta: StreamMeta,
244    #[dbg(formatter = "bytes_dbg")]
245    pub(crate) data: &'a [u8],
246}
247
248impl<'a> RawStream<'a> {
249    #[must_use]
250    pub(crate) fn new(meta: StreamMeta, data: &'a [u8]) -> Self {
251        Self { meta, data }
252    }
253}