Skip to main content

mlt_core/decoder/
model.rs

1//! Version-agnostic decode-side layer types.
2//!
3//! [`Layer01`] is the in-memory columnar form for *both* tag `0x01` and tag
4//! `0x02` layers - the two differ only in wire format, which lives in
5//! [`super::model01`] and `model02`.
6
7use std::fmt;
8
9use crate::decoder::{Geometry, GeometryValues, Id, Property};
10use crate::tile::Extent;
11use crate::{DecodeState, Lazy, Parsed};
12
13/// A layer that can be one of the known types, or an unknown.
14///
15/// The decode-state type parameter `S` mirrors [`Layer01<'a, S>`]:
16/// - `Layer<'a>` / `Layer<'a, Lazy>` - freshly parsed; columns may still be raw bytes.
17/// - `Layer<'a, Parsed>` - returned by [`Layer::decode_all`]; all columns are decoded. Use `ParsedLayer` alias.
18#[non_exhaustive]
19pub enum Layer<'a, S: DecodeState = Lazy> {
20    /// MVT-compatible layer (tag = 1)
21    Tag01(Layer01<'a, S>),
22    /// Experimental v2 layer (tag = 2).
23    ///
24    /// Parsed into the same in-memory columnar representation as `Tag01` but with an more compact wire format.
25    #[cfg(feature = "unstable-v2")]
26    Tag02(Layer01<'a, S>),
27    /// Unknown layer with tag, size, and value
28    Unknown(Unknown<'a>),
29}
30pub type ParsedLayer<'a> = Layer<'a, Parsed>;
31
32impl<'a, S: DecodeState> fmt::Debug for Layer<'a, S>
33where
34    Layer01<'a, S>: fmt::Debug,
35{
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        match self {
38            Self::Tag01(l) => f.debug_tuple("Tag01").field(l).finish(),
39            #[cfg(feature = "unstable-v2")]
40            Self::Tag02(l) => f.debug_tuple("Tag02").field(l).finish(),
41            Self::Unknown(u) => f.debug_tuple("Unknown").field(u).finish(),
42        }
43    }
44}
45
46/// Unknown layer data, stored as encoded bytes.
47///
48/// Returned inside [`Layer::Unknown`] for any layer tag that is not recognized
49/// by this version of the library. Consumers can inspect the tag and raw bytes
50/// to forward or log the layer without losing data.
51#[derive(Debug, Clone, Default, PartialEq)]
52pub struct Unknown<'a> {
53    pub(crate) tag: u8,
54    pub(crate) value: &'a [u8],
55}
56
57impl<'a> Unknown<'a> {
58    /// The raw layer tag identifying this unrecognised layer type.
59    #[must_use]
60    pub fn tag(&self) -> u32 {
61        u32::from(self.tag)
62    }
63
64    /// The raw encoded bytes of this layer's body.
65    #[must_use]
66    pub fn data(&self) -> &'a [u8] {
67        self.value
68    }
69}
70
71/// Representation of an MLT feature table layer during decoding.
72///
73/// Used for both tag `0x01` and tag `0x02` layers - the name is historical.
74///
75/// The type parameter `S` controls how columns are stored:
76///
77/// - `Layer01<'a>` / `Layer01<'a, Lazy>` (default) - columns are `LazyParsed` enums
78///   that may be raw or decoded. Use [`Layer01::decode_all`] to transition to `Layer01<Parsed>`.
79///
80/// - `Layer01<'a, Parsed>` - all columns are fully decoded. The fields `id`, `geometry`, and
81///   `properties` hold the parsed types directly, allowing infallible readonly access.
82///   There is a `ParsedLayer01<'a>` type alias for this.
83pub struct Layer01<'a, S: DecodeState = Lazy> {
84    pub(crate) name: &'a str,
85    pub(crate) extent: Extent,
86    pub(crate) id: Option<Id<'a, S>>,
87    pub(crate) geometry: Geometry<'a, S>,
88    pub(crate) properties: Vec<Property<'a, S>>,
89    #[cfg(fuzzing)]
90    pub(crate) layer_order: Vec<crate::decoder::fuzzing::LayerOrdering>,
91}
92
93pub type ParsedLayer01<'a> = Layer01<'a, Parsed>;
94
95impl<'a, S: DecodeState> Layer01<'a, S> {
96    #[must_use]
97    pub fn name(&self) -> &'a str {
98        self.name
99    }
100
101    #[must_use]
102    pub fn extent(&self) -> Extent {
103        self.extent
104    }
105}
106
107impl ParsedLayer01<'_> {
108    /// Returns the decoded geometry buffer for this layer.
109    ///
110    /// Provides access to the columnar geometry arrays (vertex buffer, offset arrays, geometry
111    /// types) for advanced use cases such as building typed arrays for WebAssembly or
112    /// performing spatial indexing. For iterating feature geometries as `geo_types` values,
113    /// prefer [`iter_features`](Self::iter_features) instead.
114    #[must_use]
115    pub fn geometry_values(&self) -> &GeometryValues {
116        &self.geometry
117    }
118
119    #[must_use]
120    pub fn feature_count(&self) -> usize {
121        self.geometry.vector_types.len()
122    }
123}
124
125impl<'a, S> fmt::Debug for Layer01<'a, S>
126where
127    S: DecodeState,
128    Option<Id<'a, S>>: fmt::Debug,
129    Geometry<'a, S>: fmt::Debug,
130    Vec<Property<'a, S>>: fmt::Debug,
131{
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        let mut s = f.debug_struct("Layer01");
134        s.field("name", &self.name)
135            .field("extent", &self.extent)
136            .field("id", &self.id)
137            .field("geometry", &self.geometry)
138            .field("properties", &self.properties);
139        #[cfg(fuzzing)]
140        s.field("layer_order", &self.layer_order);
141        s.finish()
142    }
143}
144
145impl<'a, S> Clone for Layer01<'a, S>
146where
147    S: DecodeState,
148    Option<Id<'a, S>>: Clone,
149    Geometry<'a, S>: Clone,
150    Vec<Property<'a, S>>: Clone,
151{
152    fn clone(&self) -> Self {
153        Self {
154            name: self.name,
155            extent: self.extent,
156            id: self.id.clone(),
157            geometry: self.geometry.clone(),
158            properties: self.properties.clone(),
159            #[cfg(fuzzing)]
160            layer_order: self.layer_order.clone(),
161        }
162    }
163}