1use crate::geometry::GeometryType;
2use std::fmt;
3
4#[derive(Debug)]
9pub enum CjseqError {
10 Json(serde_json::Error),
13 GeometryDepth {
18 geometry_type: GeometryType,
19 expected: usize,
21 found: usize,
23 },
24 Io(std::io::Error),
26 Validation(String),
31}
32
33impl fmt::Display for CjseqError {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 match self {
36 CjseqError::Json(e) => write!(f, "invalid JSON: {e}"),
37 CjseqError::GeometryDepth {
38 geometry_type,
39 expected,
40 found,
41 } => write!(
42 f,
43 "a {geometry_type:?} nests its boundaries {expected} levels deep, but these boundaries are nested {found} levels deep"
44 ),
45 CjseqError::Io(e) => write!(f, "I/O error: {e}"),
46 CjseqError::Validation(msg) => write!(f, "invalid CityJSON: {msg}"),
47 }
48 }
49}
50
51impl std::error::Error for CjseqError {
52 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
53 match self {
54 CjseqError::Json(e) => Some(e),
55 CjseqError::GeometryDepth { .. } => None,
56 CjseqError::Io(e) => Some(e),
57 CjseqError::Validation(_) => None,
58 }
59 }
60}
61
62impl From<serde_json::Error> for CjseqError {
63 fn from(e: serde_json::Error) -> Self {
64 CjseqError::Json(e)
65 }
66}
67
68impl From<std::io::Error> for CjseqError {
69 fn from(e: std::io::Error) -> Self {
70 CjseqError::Io(e)
71 }
72}
73
74pub type Result<T> = std::result::Result<T, CjseqError>;
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn io_error_converts_via_from_and_keeps_its_message() {
83 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "nope");
84 let err: CjseqError = io_err.into();
85 assert!(matches!(err, CjseqError::Io(_)));
86 assert_eq!(err.to_string(), "I/O error: nope");
87 }
88
89 #[test]
90 fn validation_error_carries_its_message() {
91 let err = CjseqError::Validation("Input file not CityJSON.".to_string());
92 assert_eq!(
93 err.to_string(),
94 "invalid CityJSON: Input file not CityJSON."
95 );
96 }
97}