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