1use std::io;
4use thiserror::Error;
5
6pub type Result<T> = std::result::Result<T, Error>;
8
9#[derive(Error, Debug)]
11pub enum Error {
12 #[error("I/O error: {0}")]
14 Io(#[from] io::Error),
15
16 #[error("LAS/LAZ error: {0}")]
18 Las(String),
19
20 #[error("LAZ compression error: {0}")]
22 LazCompression(String),
23
24 #[error("Unsupported point format: {0}")]
26 UnsupportedPointFormat(u8),
27
28 #[error("COPC error: {0}")]
30 Copc(String),
31
32 #[error("EPT error: {0}")]
34 Ept(String),
35
36 #[error("Mesh format error: {0}")]
38 MeshFormat(String),
39
40 #[error("OBJ export error: {0}")]
42 ObjExport(String),
43
44 #[error("glTF/GLB error: {0}")]
46 Gltf(String),
47
48 #[error("glTF JSON error: {0}")]
50 GltfJson(String),
51
52 #[error("TIN error: {0}")]
54 Tin(String),
55
56 #[error("Triangulation error: {0}")]
58 Triangulation(String),
59
60 #[error("DEM to mesh conversion error: {0}")]
62 DemToMesh(String),
63
64 #[error("3D Tiles error: {0}")]
66 Tiles3d(String),
67
68 #[error("Tileset JSON error: {0}")]
70 TilesetJson(String),
71
72 #[error("B3DM error: {0}")]
74 B3dm(String),
75
76 #[error("PNTS error: {0}")]
78 Pnts(String),
79
80 #[error("Classification error: {0}")]
82 Classification(String),
83
84 #[error("Ground classification error: {0}")]
86 GroundClassification(String),
87
88 #[error("Spatial index error: {0}")]
90 SpatialIndex(String),
91
92 #[error("Invalid bounds: {0}")]
94 InvalidBounds(String),
95
96 #[error("Invalid geometry: {0}")]
98 InvalidGeometry(String),
99
100 #[error("Empty dataset: {0}")]
102 EmptyDataset(String),
103
104 #[error("Invalid point count: expected {expected}, got {actual}")]
106 InvalidPointCount {
107 expected: usize,
109 actual: usize,
111 },
112
113 #[error("Invalid triangle count: {0}")]
115 InvalidTriangleCount(usize),
116
117 #[error("Invalid mesh: {0}")]
119 InvalidMesh(String),
120
121 #[error("Missing texture: {0}")]
123 MissingTexture(String),
124
125 #[error("Invalid texture coordinates: {0}")]
127 InvalidTextureCoords(String),
128
129 #[error("HTTP error: {0}")]
131 Http(String),
132
133 #[error("Range request error: {0}")]
135 RangeRequest(String),
136
137 #[error("JSON error: {0}")]
139 Json(String),
140
141 #[error("UTF-8 error: {0}")]
143 Utf8(#[from] std::string::FromUtf8Error),
144
145 #[error("Base64 decode error: {0}")]
147 Base64Decode(String),
148
149 #[error("Compression error: {0}")]
151 Compression(String),
152
153 #[error("Decompression error: {0}")]
155 Decompression(String),
156
157 #[error("Memory allocation error: {0}")]
159 MemoryAllocation(String),
160
161 #[error("Octree error: {0}")]
163 Octree(String),
164
165 #[error("Hierarchical LOD error: {0}")]
167 HierarchicalLod(String),
168
169 #[error("Tile loading error: {0}")]
171 TileLoading(String),
172
173 #[error("Metadata error: {0}")]
175 Metadata(String),
176
177 #[error("Invalid header: {0}")]
179 InvalidHeader(String),
180
181 #[error("Version mismatch: expected {expected}, got {actual}")]
183 VersionMismatch {
184 expected: String,
186 actual: String,
188 },
189
190 #[error("Feature not supported: {0}")]
192 Unsupported(String),
193
194 #[error("OxiGDAL core error: {0}")]
196 Core(String),
197}
198
199impl From<las::Error> for Error {
201 fn from(err: las::Error) -> Self {
202 Error::Las(err.to_string())
203 }
204}
205
206impl From<gltf::Error> for Error {
208 fn from(err: gltf::Error) -> Self {
209 Error::Gltf(err.to_string())
210 }
211}
212
213impl From<base64::DecodeError> for Error {
218 fn from(err: base64::DecodeError) -> Self {
219 Error::Base64Decode(err.to_string())
220 }
221}
222
223impl From<serde_json::Error> for Error {
225 fn from(err: serde_json::Error) -> Self {
226 Error::Json(err.to_string())
227 }
228}
229
230#[cfg(feature = "async")]
231impl From<reqwest::Error> for Error {
232 fn from(err: reqwest::Error) -> Self {
233 Error::Http(err.to_string())
234 }
235}
236
237impl From<oxigdal_core::error::OxiGdalError> for Error {
238 fn from(err: oxigdal_core::error::OxiGdalError) -> Self {
239 Error::Core(err.to_string())
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246
247 #[test]
248 fn test_error_display() {
249 let err = Error::Las("test error".to_string());
250 assert_eq!(err.to_string(), "LAS/LAZ error: test error");
251 }
252
253 #[test]
254 fn test_error_from_io() {
255 let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
256 let err: Error = io_err.into();
257 assert!(matches!(err, Error::Io(_)));
258 }
259
260 #[test]
261 fn test_error_from_json() {
262 let json_err = serde_json::from_str::<serde_json::Value>("{invalid}")
263 .expect_err("Should fail to parse invalid JSON");
264 let err: Error = json_err.into();
265 assert!(matches!(err, Error::Json(_)));
266 }
267
268 #[test]
269 fn test_invalid_point_count() {
270 let err = Error::InvalidPointCount {
271 expected: 100,
272 actual: 50,
273 };
274 assert_eq!(err.to_string(), "Invalid point count: expected 100, got 50");
275 }
276
277 #[test]
278 fn test_version_mismatch() {
279 let err = Error::VersionMismatch {
280 expected: "1.4".to_string(),
281 actual: "1.2".to_string(),
282 };
283 assert_eq!(err.to_string(), "Version mismatch: expected 1.4, got 1.2");
284 }
285}