1use std::num::TryFromIntError;
2
3use num_enum::TryFromPrimitiveError;
4
5use crate::decoder::{
6 GeometryType, LogicalCombination, LogicalEncoding, LogicalTechnique, PhysicalEncoding,
7 StreamType, ValueKind,
8};
9
10pub type MltResult<T> = Result<T, MltError>;
11pub(crate) type MltRefResult<'a, T> = Result<(&'a [u8], T), MltError>;
12
13#[derive(Debug, thiserror::Error)]
14#[non_exhaustive]
15pub enum MltError {
16 #[error("cannot decode {0} as {1}")]
17 DataWidthMismatch(&'static str, &'static str),
18 #[error("dictionary index {0} out of bounds (len={1})")]
19 DictIndexOutOfBounds(u32, usize),
20 #[error("duplicate value found where unique required")]
21 DuplicateValue,
22 #[error("Integer overflow")]
23 IntegerOverflow,
24 #[error("missing geometry column in feature table")]
25 MissingGeometry,
26 #[error("missing layer name")]
27 MissingLayerName,
28 #[error("invalid extent: {0}")]
29 InvalidExtent(u32),
30 #[error("missing property name")]
31 MissingPropertyName,
32 #[error("duplicate column name {name}: the {role} column repeats the {taken_by} column")]
33 DuplicateColumnName {
34 name: String,
35 role: crate::tile::ColumnRole,
36 taken_by: crate::tile::ColumnRole,
37 },
38 #[error("feature property count mismatch: expected {expected}, got {actual}")]
39 PropertyLengthMismatch { expected: usize, actual: usize },
40 #[error("property {index} kind mismatch: expected {expected:?}, got {actual:?}")]
41 PropertyKindMismatch {
42 index: usize,
43 expected: crate::tile::PropKind,
44 actual: crate::tile::PropKind,
45 },
46 #[error(
47 "property {name:?} holds a nested array or object, which is not supported; flatten it or remove it"
48 )]
49 NestedPropertyValue { name: String },
50 #[error("property {name:?} value {value} does not fit its {kind:?} column")]
51 PropertyValueMismatch {
52 name: String,
53 value: String,
54 kind: crate::tile::PropKind,
55 },
56 #[error("staged column {column} feature count mismatch: expected {expected}, got {actual}")]
57 StagedFeatureCountMismatch {
58 column: String,
59 expected: usize,
60 actual: usize,
61 },
62 #[error("missing string stream: {0}")]
63 MissingStringStream(&'static str),
64 #[error("multiple geometry columns found (only one allowed)")]
65 MultipleGeometryColumns,
66 #[error("multiple ID columns found (only one allowed)")]
67 MultipleIdColumns,
68 #[error("varint uses more bytes than necessary (non-canonical encoding)")]
69 NonCanonicalVarInt,
70 #[error("{0} is not decoded")]
71 NotDecoded(&'static str),
72 #[error("decoded data is not in encoded form")]
73 NotEncoded,
74 #[error("error parsing column type: code={0}")]
75 ParsingColumnType(u8),
76 #[error("error parsing v2 stream encoding byte: 0x{0:02X}")]
77 ParsingEncodingByte(u8),
78 #[cfg(feature = "unstable-v2")]
79 #[error(
80 "a v2 {0:?} stream carries no value count, and nothing in its context implies one: encoding byte 0x{1:02X}"
81 )]
82 StreamWithoutCount(StreamType, u8),
83 #[cfg(feature = "unstable-v2")]
84 #[error("error parsing v2 geometry layout: code={0}")]
85 ParsingGeoLayout(u8),
86 #[cfg(feature = "unstable-v2")]
87 #[error("error parsing v2 layer header byte: 0x{0:02X}")]
88 ParsingLayerHeader02(u8),
89 #[cfg(feature = "unstable-v2")]
90 #[error("error parsing v2 layer layout byte: 0x{0:02X}")]
91 ParsingLayerLayout02(u8),
92 #[cfg(feature = "unstable-v2")]
93 #[error("v2 extent {0} is not a power of two in 64..=2097152")]
94 UnsupportedExtent02(u32),
95 #[cfg(feature = "unstable-v2")]
96 #[error(
97 "v2 geometry layout {0} gives no per-feature vertex count, so it cannot carry m-values"
98 )]
99 MValuesNeedVertexCounts(&'static str),
100 #[cfg(feature = "unstable-v2")]
101 #[error("the v2 layer header byte claims an m-value section, but it holds no columns")]
102 EmptyMValueSection,
103 #[cfg(feature = "unstable-v2")]
104 #[error(
105 "m-value column {name} has no implied count, so its leading stream must write one: encoding byte 0x{byte:02X}"
106 )]
107 MValueImplicitCount { name: String, byte: u8 },
108 #[cfg(feature = "unstable-v2")]
109 #[error(
110 "m-value column {name} holds {actual} values, but its features have {expected} vertices"
111 )]
112 MValueColumnLengthMismatch {
113 name: String,
114 expected: usize,
115 actual: usize,
116 },
117 #[cfg(feature = "unstable-v2")]
118 #[error(
119 "m-value column {name} holds {actual} values, so a feature's run of {count} at offset {start} is out of range"
120 )]
121 MValueRunOutOfRange {
122 name: String,
123 start: usize,
124 count: usize,
125 actual: usize,
126 },
127 #[cfg(feature = "unstable-v2")]
128 #[error("a feature carries {actual} m-value columns, but the layer has {expected}")]
129 MValueColumnCountMismatch { expected: usize, actual: usize },
130 #[cfg(feature = "unstable-v2")]
131 #[error("m-value key {index} belongs to another layer: this feature has {columns} columns")]
132 UnknownMValueKey { index: usize, columns: usize },
133 #[cfg(feature = "unstable-v2")]
134 #[error("m-value {index} kind mismatch: expected {expected:?}, got {actual:?}")]
135 MValueKindMismatch {
136 index: usize,
137 expected: crate::tile::PropKind,
138 actual: crate::tile::PropKind,
139 },
140 #[cfg(feature = "unstable-v2")]
141 #[error("m-value {index} holds {actual} values, but the feature has {expected} vertices")]
142 MValueVertexCountMismatch {
143 index: usize,
144 expected: usize,
145 actual: usize,
146 },
147 #[error("8-bit integers are a v2 feature, so column {0} cannot be written as v1")]
148 EightBitNeedsV2(String),
149 #[cfg(feature = "unstable-v2")]
150 #[error("m-values are a v2 feature, so layer {0} cannot be written as v1")]
151 MValuesNeedV2(String),
152 #[error("a vertex stream of {0} words does not hold whole vertices of {1} words")]
153 PartialVertex(u32, u32),
154 #[cfg(feature = "unstable-v2")]
155 #[error("z coordinates are a v2 feature, so layer {0} cannot be written as v1")]
156 ZNeedsV2(String),
157 #[cfg(feature = "unstable-v2")]
158 #[error("a z step of 10^{0} m is outside 10^-3..=10^4 m")]
159 InvalidZStep(i8),
160 #[cfg(feature = "unstable-v2")]
161 #[error("z step code {0} is outside 0..=7")]
162 InvalidZStepCode(u8),
163 #[cfg(feature = "unstable-v2")]
164 #[error(
165 "layer {0} already holds features without z coordinates, so it cannot be given a z step"
166 )]
167 ZStepOnNonEmptyLayer(String),
168 #[cfg(feature = "unstable-v2")]
169 #[error("a feature carries {actual} z coordinates, but the layer expects {expected}")]
170 ZVertexCountMismatch { expected: usize, actual: usize },
171 #[cfg(feature = "unstable-v2")]
172 #[error("the vertices already carry z coordinates")]
173 ZAlreadySet,
174 #[cfg(feature = "unstable-v2")]
175 #[error("a vertex stream of {0} words does not hold whole (x, y, z) triples")]
176 InvalidTripleStreamSize(usize),
177 #[cfg(feature = "unstable-v2")]
178 #[error("nested properties are a v2 feature, so layer {0} cannot be written as v1")]
179 NestedNeedsV2(String),
180 #[cfg(feature = "unstable-v2")]
181 #[error("duplicate field name in a struct node: {0}")]
182 DuplicateFieldName(String),
183 #[cfg(feature = "unstable-v2")]
184 #[error("a struct node holds no fields")]
185 EmptyStructNode,
186 #[cfg(feature = "unstable-v2")]
187 #[error("nested column {0} has a scalar root, which is an ordinary column")]
188 NestedRootIsLeaf(String),
189 #[cfg(feature = "unstable-v2")]
190 #[error("a nested column is {0} levels deep, more than the 8 the format allows")]
191 NestedTooDeep(usize),
192 #[cfg(feature = "unstable-v2")]
193 #[error("a nested lengths stream sums to {expected}, but the node below it holds {actual}")]
194 NestedCountMismatch { expected: u32, actual: u32 },
195 #[cfg(feature = "unstable-v2")]
196 #[error(
197 "nested node {name} has no implied count, so its leading stream must write one: encoding byte 0x{byte:02X}"
198 )]
199 NestedImplicitCount { name: String, byte: u8 },
200 #[cfg(feature = "unstable-v2")]
201 #[error("a feature carries {actual} nested columns, but the layer has {expected}")]
202 NestedColumnCountMismatch { expected: usize, actual: usize },
203 #[cfg(feature = "unstable-v2")]
204 #[error("nested key {index} belongs to another layer: this feature has {columns} columns")]
205 UnknownNestedKey { index: usize, columns: usize },
206 #[cfg(feature = "unstable-v2")]
207 #[error("nested column {index} ({name}) was given a value of another shape")]
208 NestedValueMismatch { index: usize, name: String },
209 #[cfg(feature = "unstable-v2")]
210 #[error("nested column {index} was given a value of another shape")]
211 NestedShapeMismatch { index: usize },
212 #[cfg(feature = "unstable-v2")]
213 #[error("nested column {name} runs over {expected} values, but its root holds {actual}")]
214 NestedRootCountMismatch {
215 name: String,
216 expected: u32,
217 actual: u32,
218 },
219 #[cfg(feature = "unstable-v2")]
220 #[error(
221 "nested node {name} must write its presence as a raw bitmap of one bit per value: encoding byte 0x{byte:02X}"
222 )]
223 NestedPresenceEncoding { name: String, byte: u8 },
224 #[cfg(feature = "unstable-v2")]
225 #[error("a nested lengths stream holds {len} lengths, so it has no row {row}")]
226 NestedRowOutOfRange { row: usize, len: usize },
227 #[cfg(feature = "unstable-v2")]
228 #[error("a nested map holds {len} keys, so it has no key for entry {entry}")]
229 NestedKeyOutOfRange { entry: usize, len: usize },
230 #[cfg(feature = "unstable-v2")]
231 #[error("a nested leaf holds {len} values, so it has no value at index {index}")]
232 NestedValueOutOfRange { index: usize, len: usize },
233 #[cfg(feature = "unstable-v2")]
234 #[error("a row-shape table of {bits} bits does not divide into shapes of {keys} keys")]
235 NestedRowShapeTableSize { bits: usize, keys: usize },
236 #[cfg(feature = "unstable-v2")]
237 #[error("a shape-coded nested node has {len} row shapes, so it has no shape {id}")]
238 NestedRowShapeOutOfRange { id: u32, len: usize },
239 #[cfg(feature = "unstable-v2")]
240 #[error("nested node {name} is shape-coded over {expected} rows, but holds {actual} shape ids")]
241 NestedRowShapeCount {
242 name: String,
243 expected: u32,
244 actual: u32,
245 },
246 #[cfg(feature = "unstable-v2")]
247 #[error(
248 "nested node {name} reads its presence from its parent's row shapes, so it stores none of its own"
249 )]
250 NestedRowShapeChildPresence { name: String },
251 #[cfg(feature = "unstable-v2")]
252 #[error("nested node {name} is a {kind}, which has no row shapes to read")]
253 NestedRowShapeUnsupported { name: String, kind: &'static str },
254 #[error("error parsing logical technique: code={0}")]
255 ParsingLogicalTechnique(u8),
256 #[error("error parsing physical encoding: code={0}")]
257 ParsingPhysicalEncoding(u8),
258 #[error("error parsing stream type: code={0}")]
259 ParsingStreamType(u8),
260 #[error("found {0} bytes after the expected end of layer")]
261 TrailingLayerData(usize),
262 #[error("unexpected end of input (unable to take {0} bytes)")]
263 UnableToTake(u32),
264 #[error("unexpected stream type {0:?}")]
265 UnexpectedStreamType(StreamType),
266 #[error("unexpected stream type {0:?}, expected {1} for {2}")]
267 UnexpectedStreamType2(StreamType, &'static str, &'static str),
268 #[error("unsupported logical encoding {0:?} for {1}")]
269 UnsupportedLogicalEncoding(LogicalEncoding, &'static str),
270 #[error("invalid combination of logical encodings: {0:?} + {1:?}")]
271 InvalidLogicalEncodings(LogicalTechnique, LogicalTechnique),
272 #[error("logical encoding {0:?} is not one a {1:?} stream has")]
273 LogicalEncodingNotInKind(LogicalCombination, ValueKind),
274 #[error("layer has zero size")]
275 ZeroLayerSize,
276 #[error("bit-packed stream width {0} is outside 1..=32")]
277 #[cfg(feature = "unstable-v2")]
278 ParsingBitWidth(u32),
279 #[error("The encoder used to optimise data is incompatible")]
280 BadEncoderDataCombination,
281 #[error("StagedLayer::encode_explicit requires Encoder.explicit to be Some(_)")]
282 MissingExplicitEncoder,
283
284 #[error("buffer underflow: needed {0} bytes, but only {1} remain")]
286 BufferUnderflow(u32, usize),
287 #[error("FastPFor decode failed: expected={0} got={1}")]
288 FastPforDecode(u32, usize),
289 #[error("invalid RLE run length (cannot convert to usize): value={0}")]
290 RleRunLenInvalid(i128),
291 #[error("presence runs overflow the {0} features they cover")]
292 PresenceRunOverflow(u32),
293 #[error("presence names {0} present features out of {1}")]
294 PresenceRunShort(u32, u32),
295 #[error("presence indices are not strictly increasing within {0} features")]
296 PresenceIndexOrder(u32),
297 #[error("unknown presence coding byte: 0x{0:02X}")]
298 PresenceCodingByte(u8),
299
300 #[error("geometry requires at least 1 stream, got 0")]
302 GeometryWithoutStreams,
303 #[error("FastPFor data byte length expected multiple of 4, got {0}")]
304 InvalidFastPforByteLength(usize),
305 #[error("vec2 delta stream size expected to be non-empty and multiple of 2, got {0}")]
306 InvalidPairStreamSize(usize),
307 #[error("decodable stream size expected {1}, got {0}")]
308 InvalidDecodingStreamSize(usize, usize),
309 #[error("IDs missing for encoding (expected Some IDs, got None)")]
310 IdsMissingForEncoding,
311 #[error("missing struct encoder for struct")]
312 MissingStructEncoderForStruct,
313 #[error("previous decode/parsing attempt failed")]
314 PriorParseFailure,
315 #[error("FSST-compressed data is malformed: {0}")]
316 MalformedFsst(&'static str),
317 #[cfg(feature = "unstable-v2")]
318 #[error("rANS vertex stream is malformed: {0}")]
319 MalformedRans(&'static str),
320 #[cfg(feature = "unstable-v2")]
321 #[error("dictionary code {0} is out of range for a dictionary of {1} values")]
322 DictionaryCodeOutOfRange(u32, usize),
323 #[cfg(feature = "unstable-v2")]
324 #[error(
325 "front-coded lengths stream holds a prefix and a suffix length per entry, so its {0} values cannot be split in two"
326 )]
327 FrontCodedOddLengthCount(usize),
328 #[cfg(feature = "unstable-v2")]
329 #[error(
330 "front-coded entry {index} shares {shared} bytes with a predecessor of only {available}"
331 )]
332 FrontCodedPrefixTooLong {
333 index: usize,
334 shared: usize,
335 available: usize,
336 },
337 #[cfg(feature = "unstable-v2")]
338 #[error(
339 "front-coded entry {index} needs {needed} suffix bytes, but {available} remain in the blob"
340 )]
341 FrontCodedSuffixOutOfBounds {
342 index: usize,
343 needed: usize,
344 available: usize,
345 },
346 #[cfg(feature = "unstable-v2")]
347 #[error("front-coded dictionary leaves {0} suffix bytes after its last entry")]
348 FrontCodedTrailingSuffixBytes(usize),
349 #[cfg(feature = "unstable-v2")]
350 #[error("no Framed, Exception-Free ALP parameters return this float column bit-for-bit")]
351 NoAlpParameters,
352 #[error("invalid Framed, Exception-Free ALP parameters: e={0}, f={1}")]
353 InvalidAlpParams(u8, u8),
354 #[error("invalid Framed, Exception-Free ALP scale byte {0}")]
355 InvalidAlpScale(u8),
356 #[error("presence stream has {0} bits set but {1} values provided")]
357 PresenceValueCountMismatch(usize, usize),
358 #[error("need to encode before being able to write")]
359 NeedsEncodingBeforeWriting,
360 #[error("memory limit exceeded: limit={limit}, used={used}, requested={requested}")]
361 MemoryLimitExceeded {
362 limit: u32,
363 used: u32,
364 requested: u32,
365 },
366 #[error("not implemented: {0}")]
367 NotImplemented(&'static str),
368 #[error("unsupported property value and encoder combination: {0:?} + {1:?}")]
369 UnsupportedPropertyEncoderCombination(&'static str, &'static str),
370 #[error("mixed property types are not allowed in column {0} ({1})")]
371 MixedPropertyTypes(usize, String),
372 #[error("shared dictionary requires at least 2 streams, got {0}")]
373 SharedDictRequiresStreams(usize),
374 #[error("unsupported string stream count (expected between 2 and 5): {0}")]
375 UnsupportedStringStreamCount(usize),
376 #[error("Structs are not allowed to be optional")]
377 TriedToEncodeOptionalStruct,
378 #[error(
379 "encoding instruction count mismatch: expected {input_len} instructions for {input_len} properties, got {config_len}"
380 )]
381 EncodingInstructionCountMismatch { input_len: usize, config_len: usize },
382 #[error("struct child data streams expected exactly 1 value, got {0}")]
383 UnexpectedStructChildCount(u32),
384 #[error("SharedDict stream count is {actual}, expected {expected}")]
386 InvalidSharedDictStreamCount { actual: u32, expected: u32 },
387 #[error("unsupported physical encoding: {0}")]
388 UnsupportedPhysicalEncoding(&'static str),
389 #[error("unsupported physical encoding: {0:?} for {1}")]
390 UnsupportedPhysicalEncodingForType(PhysicalEncoding, &'static str),
391 #[error(
392 "Extent {extent} cannot be encoded to morton due to morton allowing max. 16 bits, but {required_bits} would be required"
393 )]
394 VertexMortonNotCompatibleWithExtent { extent: u32, required_bits: u32 },
395 #[error("Morton stream uses {0} bits, but at most 16 bits are supported")]
396 InvalidMortonBits(u32),
397
398 #[error("MVT error: {0}")]
400 BadMvtGeometry(&'static str),
401 #[error("geometry[{0}]: index out of bounds")]
402 GeometryIndexOutOfBounds(usize),
403 #[error("geometry[{index}]: {field}[{idx}] out of bounds (len={len})")]
404 GeometryOutOfBounds {
405 index: usize,
406 field: &'static str,
407 idx: usize,
408 len: usize,
409 },
410 #[error("geometry[{index}]: vertex {vertex} out of bounds (count={count})")]
411 GeometryVertexOutOfBounds {
412 index: usize,
413 vertex: usize,
414 count: usize,
415 },
416 #[error("geometry[{0}]: {1} requires geometry_offsets")]
417 NoGeometryOffsets(usize, GeometryType),
418 #[error("geometry[{0}]: {1} requires part_offsets")]
419 NoPartOffsets(usize, GeometryType),
420 #[error("geometry[{0}]: {1} requires ring_offsets")]
421 NoRingOffsets(usize, GeometryType),
422 #[error("geometry[{0}]: unexpected offset combination for {1}")]
423 UnexpectedOffsetCombination(usize, GeometryType),
424 #[error("geometry: ring lengths without part lengths")]
425 RingLengthsWithoutPartLengths,
426 #[error("geometry[{0}]: {1} requires outlines, which a triangles-only layer does not store")]
427 NonPolygonWithoutOutlines(usize, GeometryType),
428
429 #[error("FastPFor error: {0}")]
430 FastPfor(#[from] fastpfor::FastPForError),
431 #[error(transparent)]
432 Io(#[from] std::io::Error),
433 #[error("Serde JSON error: {0}")]
434 SerdeJsonError(#[from] serde_json::Error),
435 #[error("integer conversion error: {0}")]
436 TryFromIntError(#[from] TryFromIntError),
437 #[error("num_enum conversion error: {0}")]
438 TryFromPrimitive(#[from] TryFromPrimitiveError<GeometryType>),
439 #[error("UTF-8 decode error: {0}")]
440 Utf8(#[from] std::str::Utf8Error),
441 #[error("UTF-8 decode error: {0}")]
442 FromUtf8(#[from] std::string::FromUtf8Error),
443 #[error("MVT error: {0}")]
444 Mvt(#[from] fast_mvt::MvtError),
445 #[error("MVT JSON value error: {0}")]
446 MvtJsonValue(#[from] fast_mvt::MvtJsonValueError),
447}
448
449impl From<MltError> for std::io::Error {
450 fn from(value: MltError) -> Self {
451 if let MltError::Io(e) = value {
452 e
453 } else {
454 Self::other(value)
455 }
456 }
457}
458
459pub(crate) trait AsMltError<T> {
460 fn or_overflow(&self) -> MltResult<T>;
461}
462
463impl<T: Copy> AsMltError<T> for Option<T> {
464 #[inline]
465 fn or_overflow(&self) -> MltResult<T> {
466 self.ok_or(MltError::IntegerOverflow)
467 }
468}
469
470impl AsMltError<u32> for Result<u32, TryFromIntError> {
471 #[inline]
472 fn or_overflow(&self) -> MltResult<u32> {
473 self.map_err(|_| MltError::IntegerOverflow)
474 }
475}
476
477#[inline]
478pub(crate) fn fail_if_invalid_stream_size(actual: usize, expected: usize) -> MltResult<()> {
479 if actual == expected {
480 Ok(())
481 } else {
482 Err(MltError::InvalidDecodingStreamSize(actual, expected))
483 }
484}