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 property name: {0}")]
33 DuplicatePropertyName(String),
34 #[error("feature property count mismatch: expected {expected}, got {actual}")]
35 PropertyLengthMismatch { expected: usize, actual: usize },
36 #[error("property {index} kind mismatch: expected {expected:?}, got {actual:?}")]
37 PropertyKindMismatch {
38 index: usize,
39 expected: crate::tile::PropKind,
40 actual: crate::tile::PropKind,
41 },
42 #[error("staged column {column} feature count mismatch: expected {expected}, got {actual}")]
43 StagedFeatureCountMismatch {
44 column: String,
45 expected: usize,
46 actual: usize,
47 },
48 #[error("missing string stream: {0}")]
49 MissingStringStream(&'static str),
50 #[error("multiple geometry columns found (only one allowed)")]
51 MultipleGeometryColumns,
52 #[error("multiple ID columns found (only one allowed)")]
53 MultipleIdColumns,
54 #[error("varint uses more bytes than necessary (non-canonical encoding)")]
55 NonCanonicalVarInt,
56 #[error("{0} is not decoded")]
57 NotDecoded(&'static str),
58 #[error("decoded data is not in encoded form")]
59 NotEncoded,
60 #[error("error parsing column type: code={0}")]
61 ParsingColumnType(u8),
62 #[error("error parsing v2 stream encoding byte: 0x{0:02X}")]
63 ParsingEncodingByte(u8),
64 #[cfg(feature = "unstable-v2")]
65 #[error("error parsing v2 geometry layout: code={0}")]
66 ParsingGeoLayout(u8),
67 #[cfg(feature = "unstable-v2")]
68 #[error("error parsing v2 layer layout: byte=0x{0:02X}")]
69 ParsingLayerLayout(u8),
70 #[error("error parsing logical technique: code={0}")]
71 ParsingLogicalTechnique(u8),
72 #[error("error parsing physical encoding: code={0}")]
73 ParsingPhysicalEncoding(u8),
74 #[error("error parsing stream type: code={0}")]
75 ParsingStreamType(u8),
76 #[error("found {0} bytes after the expected end of layer")]
77 TrailingLayerData(usize),
78 #[error("unexpected end of input (unable to take {0} bytes)")]
79 UnableToTake(u32),
80 #[error("unexpected stream type {0:?}")]
81 UnexpectedStreamType(StreamType),
82 #[error("unexpected stream type {0:?}, expected {1} for {2}")]
83 UnexpectedStreamType2(StreamType, &'static str, &'static str),
84 #[error("unsupported logical encoding {0:?} for {1}")]
85 UnsupportedLogicalEncoding(LogicalEncoding, &'static str),
86 #[error("invalid combination of logical encodings: {0:?} + {1:?}")]
87 InvalidLogicalEncodings(LogicalTechnique, LogicalTechnique),
88 #[error("logical encoding {0:?} is not one a {1:?} stream has")]
89 LogicalEncodingNotInKind(LogicalCombination, ValueKind),
90 #[error("layer has zero size")]
91 ZeroLayerSize,
92 #[error("The encoder used to optimise data is incompatible")]
93 BadEncoderDataCombination,
94 #[error("StagedLayer::encode_explicit requires Encoder.explicit to be Some(_)")]
95 MissingExplicitEncoder,
96
97 #[error("buffer underflow: needed {0} bytes, but only {1} remain")]
99 BufferUnderflow(u32, usize),
100 #[error("FastPFor decode failed: expected={0} got={1}")]
101 FastPforDecode(u32, usize),
102 #[error("invalid RLE run length (cannot convert to usize): value={0}")]
103 RleRunLenInvalid(i128),
104
105 #[error("geometry requires at least 1 stream, got 0")]
107 GeometryWithoutStreams,
108 #[error("FastPFor data byte length expected multiple of 4, got {0}")]
109 InvalidFastPforByteLength(usize),
110 #[error("vec2 delta stream size expected to be non-empty and multiple of 2, got {0}")]
111 InvalidPairStreamSize(usize),
112 #[error("decodable stream size expected {1}, got {0}")]
113 InvalidDecodingStreamSize(usize, usize),
114 #[error("IDs missing for encoding (expected Some IDs, got None)")]
115 IdsMissingForEncoding,
116 #[error("missing struct encoder for struct")]
117 MissingStructEncoderForStruct,
118 #[error("previous decode/parsing attempt failed")]
119 PriorParseFailure,
120 #[error("FSST-compressed data is malformed: {0}")]
121 MalformedFsst(&'static str),
122 #[cfg(feature = "unstable-v2")]
123 #[error("dictionary code {0} is out of range for a dictionary of {1} values")]
124 DictionaryCodeOutOfRange(u32, usize),
125 #[cfg(feature = "unstable-v2")]
126 #[error(
127 "front-coded lengths stream holds a prefix and a suffix length per entry, so its {0} values cannot be split in two"
128 )]
129 FrontCodedOddLengthCount(usize),
130 #[cfg(feature = "unstable-v2")]
131 #[error(
132 "front-coded entry {index} shares {shared} bytes with a predecessor of only {available}"
133 )]
134 FrontCodedPrefixTooLong {
135 index: usize,
136 shared: usize,
137 available: usize,
138 },
139 #[cfg(feature = "unstable-v2")]
140 #[error(
141 "front-coded entry {index} needs {needed} suffix bytes, but {available} remain in the blob"
142 )]
143 FrontCodedSuffixOutOfBounds {
144 index: usize,
145 needed: usize,
146 available: usize,
147 },
148 #[cfg(feature = "unstable-v2")]
149 #[error("front-coded dictionary leaves {0} suffix bytes after its last entry")]
150 FrontCodedTrailingSuffixBytes(usize),
151 #[cfg(feature = "unstable-v2")]
152 #[error("no ALP parameters return this float column bit-for-bit")]
153 NoAlpParameters,
154 #[error("invalid ALP parameters: e={0}, f={1}")]
155 InvalidAlpParams(u8, u8),
156 #[error("presence stream has {0} bits set but {1} values provided")]
157 PresenceValueCountMismatch(usize, usize),
158 #[error("need to encode before being able to write")]
159 NeedsEncodingBeforeWriting,
160 #[error("memory limit exceeded: limit={limit}, used={used}, requested={requested}")]
161 MemoryLimitExceeded {
162 limit: u32,
163 used: u32,
164 requested: u32,
165 },
166 #[error("not implemented: {0}")]
167 NotImplemented(&'static str),
168 #[error("unsupported property value and encoder combination: {0:?} + {1:?}")]
169 UnsupportedPropertyEncoderCombination(&'static str, &'static str),
170 #[error("mixed property types are not allowed in column {0} ({1})")]
171 MixedPropertyTypes(usize, String),
172 #[error("shared dictionary requires at least 2 streams, got {0}")]
173 SharedDictRequiresStreams(usize),
174 #[error("unsupported string stream count (expected between 2 and 5): {0}")]
175 UnsupportedStringStreamCount(usize),
176 #[error("Structs are not allowed to be optional")]
177 TriedToEncodeOptionalStruct,
178 #[error(
179 "encoding instruction count mismatch: expected {input_len} instructions for {input_len} properties, got {config_len}"
180 )]
181 EncodingInstructionCountMismatch { input_len: usize, config_len: usize },
182 #[error("struct child data streams expected exactly 1 value, got {0}")]
183 UnexpectedStructChildCount(u32),
184 #[error("SharedDict stream count is {actual}, expected {expected}")]
186 InvalidSharedDictStreamCount { actual: u32, expected: u32 },
187 #[error("unsupported physical encoding: {0}")]
188 UnsupportedPhysicalEncoding(&'static str),
189 #[error("unsupported physical encoding: {0:?} for {1}")]
190 UnsupportedPhysicalEncodingForType(PhysicalEncoding, &'static str),
191 #[error(
192 "Extent {extent} cannot be encoded to morton due to morton allowing max. 16 bits, but {required_bits} would be required"
193 )]
194 VertexMortonNotCompatibleWithExtent { extent: u32, required_bits: u32 },
195 #[error("Morton stream uses {0} bits, but at most 16 bits are supported")]
196 InvalidMortonBits(u32),
197
198 #[error("MVT error: {0}")]
200 BadMvtGeometry(&'static str),
201 #[error("geometry[{0}]: index out of bounds")]
202 GeometryIndexOutOfBounds(usize),
203 #[error("geometry[{index}]: {field}[{idx}] out of bounds (len={len})")]
204 GeometryOutOfBounds {
205 index: usize,
206 field: &'static str,
207 idx: usize,
208 len: usize,
209 },
210 #[error("geometry[{index}]: vertex {vertex} out of bounds (count={count})")]
211 GeometryVertexOutOfBounds {
212 index: usize,
213 vertex: usize,
214 count: usize,
215 },
216 #[error("geometry[{0}]: {1} requires geometry_offsets")]
217 NoGeometryOffsets(usize, GeometryType),
218 #[error("geometry[{0}]: {1} requires part_offsets")]
219 NoPartOffsets(usize, GeometryType),
220 #[error("geometry[{0}]: {1} requires ring_offsets")]
221 NoRingOffsets(usize, GeometryType),
222 #[error("geometry[{0}]: unexpected offset combination for {1}")]
223 UnexpectedOffsetCombination(usize, GeometryType),
224 #[error("geometry: ring lengths without part lengths")]
225 RingLengthsWithoutPartLengths,
226
227 #[error("FastPFor error: {0}")]
228 FastPfor(#[from] fastpfor::FastPForError),
229 #[error(transparent)]
230 Io(#[from] std::io::Error),
231 #[error("Serde JSON error: {0}")]
232 SerdeJsonError(#[from] serde_json::Error),
233 #[error("integer conversion error: {0}")]
234 TryFromIntError(#[from] TryFromIntError),
235 #[error("num_enum conversion error: {0}")]
236 TryFromPrimitive(#[from] TryFromPrimitiveError<GeometryType>),
237 #[error("UTF-8 decode error: {0}")]
238 Utf8(#[from] std::str::Utf8Error),
239 #[error("UTF-8 decode error: {0}")]
240 FromUtf8(#[from] std::string::FromUtf8Error),
241 #[error("MVT error: {0}")]
242 Mvt(#[from] fast_mvt::MvtError),
243 #[error("MVT JSON value error: {0}")]
244 MvtJsonValue(#[from] fast_mvt::MvtJsonValueError),
245}
246
247impl From<MltError> for std::io::Error {
248 fn from(value: MltError) -> Self {
249 if let MltError::Io(e) = value {
250 e
251 } else {
252 Self::other(value)
253 }
254 }
255}
256
257pub(crate) trait AsMltError<T> {
258 fn or_overflow(&self) -> MltResult<T>;
259}
260
261impl<T: Copy> AsMltError<T> for Option<T> {
262 #[inline]
263 fn or_overflow(&self) -> MltResult<T> {
264 self.ok_or(MltError::IntegerOverflow)
265 }
266}
267
268impl AsMltError<u32> for Result<u32, TryFromIntError> {
269 #[inline]
270 fn or_overflow(&self) -> MltResult<u32> {
271 self.map_err(|_| MltError::IntegerOverflow)
272 }
273}
274
275#[inline]
276pub(crate) fn fail_if_invalid_stream_size(actual: usize, expected: usize) -> MltResult<()> {
277 if actual == expected {
278 Ok(())
279 } else {
280 Err(MltError::InvalidDecodingStreamSize(actual, expected))
281 }
282}