mlt_core/decoder/
model01.rs1use std::io;
7use std::io::Write;
8
9use num_enum::TryFromPrimitive;
10
11use crate::MltError::ParsingColumnType;
12use crate::decoder::{
13 Geometry, GeometryValues, Id, LayerBytes, ParsedId, ParsedProperty, Property,
14};
15use crate::tile::Extent;
16use crate::utils::{BinarySerializer as _, parse_string, parse_u8};
17use crate::{DecodeState, Lazy, MltRefResult, Parsed, Parser};
18
19pub(crate) const OPTIONAL_FLAG: u8 = 0b0000_0001;
21
22pub(crate) const BASE_TYPE_MASK: u8 = 0b1111_1110;
25
26#[derive(Debug, Clone)]
40pub struct Layer01<'a, S: DecodeState = Lazy> {
41 pub(crate) name: &'a str,
42 pub(crate) extent: Extent,
43 pub(crate) id: Option<Id<'a, S>>,
44 pub(crate) geometry: Geometry<'a, S>,
45 pub(crate) properties: Vec<Property<'a, S>>,
46 pub(crate) bytes: LayerBytes,
47 #[cfg(fuzzing)]
48 pub(crate) layer_order: Vec<crate::decoder::fuzzing::LayerOrdering>,
49}
50
51pub type ParsedLayer01<'a> = Layer01<'a, Parsed>;
52
53impl<'a, S: DecodeState> Layer01<'a, S> {
54 #[must_use]
55 pub fn name(&self) -> &'a str {
56 self.name
57 }
58
59 #[must_use]
60 pub fn extent(&self) -> Extent {
61 self.extent
62 }
63
64 #[must_use]
66 pub fn bytes(&self) -> LayerBytes {
67 self.bytes
68 }
69}
70
71impl ParsedLayer01<'_> {
72 #[must_use]
79 pub fn geometry_values(&self) -> &GeometryValues {
80 &self.geometry
81 }
82
83 #[must_use]
84 pub fn feature_count(&self) -> usize {
85 self.geometry.vector_types.len()
86 }
87
88 #[must_use]
90 pub fn properties(&self) -> &[ParsedProperty<'_>] {
91 &self.properties
92 }
93
94 #[must_use]
98 pub fn id(&self) -> Option<&ParsedId<'_>> {
99 self.id.as_ref()
100 }
101}
102
103#[derive(Debug, PartialEq)]
105pub struct Column<'a> {
106 pub(crate) typ: ColumnType,
107 pub(crate) name: Option<&'a str>,
108 pub(crate) children: Vec<Self>,
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
113#[repr(u8)]
114pub enum ColumnType {
115 Id = 0b0000_0000,
116 OptId = 0b0000_0001,
117 LongId = 0b0000_0010,
118 OptLongId = 0b0000_0011,
119 Geometry = 0b0000_0100,
120 Bool = 0b0000_1010,
121 OptBool = 0b0000_1011,
122 I32 = 0b0001_0000,
123 OptI32 = 0b0001_0001,
124 U32 = 0b0001_0010,
125 OptU32 = 0b0001_0011,
126 I64 = 0b0001_0100,
127 OptI64 = 0b0001_0101,
128 U64 = 0b0001_0110,
129 OptU64 = 0b0001_0111,
130 F32 = 0b0001_1000,
131 OptF32 = 0b0001_1001,
132 F64 = 0b0001_1010,
133 OptF64 = 0b0001_1011,
134 Str = 0b0001_1100,
135 OptStr = 0b0001_1101,
136 SharedDict = 0b0001_1110,
137}
138
139impl Column<'_> {
140 pub(crate) fn from_bytes<'a>(
142 input: &'a [u8],
143 _parser: &mut Parser,
144 ) -> MltRefResult<'a, Column<'a>> {
145 let (mut input, typ) = ColumnType::from_bytes(input)?;
146 let name = if typ.has_name() {
147 let pair = parse_string(input)?;
148 input = pair.0;
149 Some(pair.1)
150 } else {
151 None
152 };
153
154 Ok((
155 input,
156 Column {
157 typ,
158 name,
159 children: Vec::new(),
160 },
161 ))
162 }
163}
164
165impl ColumnType {
166 pub(crate) fn from_bytes(input: &[u8]) -> MltRefResult<'_, Self> {
168 let (input, value) = parse_u8(input)?;
169 let value = Self::try_from(value).or(Err(ParsingColumnType(value)))?;
170 Ok((input, value))
171 }
172
173 pub(crate) fn write_to<W: Write>(self, writer: &mut W) -> io::Result<()> {
174 writer.write_u8(self as u8)?;
175 Ok(())
176 }
177
178 #[must_use]
181 pub(crate) fn has_name(self) -> bool {
182 !matches!(
183 self,
184 Self::Id | Self::OptId | Self::LongId | Self::OptLongId | Self::Geometry
185 )
186 }
187
188 #[must_use]
190 pub(crate) fn is_id(self) -> bool {
191 matches!(
192 self,
193 Self::Id | Self::OptId | Self::LongId | Self::OptLongId
194 )
195 }
196
197 #[must_use]
199 pub(crate) fn is_optional(self) -> bool {
200 (self as u8) & OPTIONAL_FLAG != 0
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use rstest::rstest;
207
208 use super::ColumnType;
209 use crate::MltError;
210
211 #[rstest]
212 fn column_type_rejects_unassigned(#[values(5, 6, 7, 8, 9, 12, 13, 14, 15, 31)] byte: u8) {
213 let err = ColumnType::from_bytes(&[byte]).unwrap_err();
214 assert!(matches!(err, MltError::ParsingColumnType(b) if b == byte));
215 }
216}