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