Skip to main content

cityjson_lib/
error.rs

1use std::error;
2use std::fmt::{Debug, Display, Formatter};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum ErrorKind {
6    Io,
7    Syntax,
8    Version,
9    Shape,
10    Unsupported,
11    Model,
12}
13
14pub enum Error {
15    Io(std::io::Error),
16    Syntax(String),
17    CityJSON(cityjson::error::Error),
18    MissingVersion,
19    ExpectedCityJSON(String),
20    ExpectedCityJSONFeature(String),
21    UnsupportedType(String),
22    UnsupportedVersion { found: String, supported: String },
23    Streaming(String),
24    Import(String),
25    UnsupportedFeature(String),
26}
27
28pub type Result<T> = std::result::Result<T, Error>;
29
30impl Error {
31    pub fn kind(&self) -> ErrorKind {
32        match self {
33            Self::Io(_) => ErrorKind::Io,
34            Self::Syntax(_) => ErrorKind::Syntax,
35            Self::CityJSON(_) => ErrorKind::Model,
36            Self::MissingVersion => ErrorKind::Version,
37            Self::ExpectedCityJSON(_) | Self::ExpectedCityJSONFeature(_) => ErrorKind::Shape,
38            Self::UnsupportedType(_)
39            | Self::UnsupportedVersion { .. }
40            | Self::UnsupportedFeature(_) => ErrorKind::Unsupported,
41            Self::Streaming(_) => ErrorKind::Shape,
42            Self::Import(_) => ErrorKind::Model,
43        }
44    }
45}
46
47impl Display for Error {
48    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
49        match self {
50            Self::Io(error) => write!(f, "I/O error: {error}"),
51            Self::Syntax(error) => write!(f, "JSON error: {error}"),
52            Self::CityJSON(error) => write!(f, "cityjson error: {error}"),
53            Self::MissingVersion => write!(f, "CityJSON object must contain a version member"),
54            Self::ExpectedCityJSON(found) => {
55                write!(f, "expected a CityJSON object, found {found}")
56            }
57            Self::ExpectedCityJSONFeature(found) => {
58                write!(f, "expected a CityJSONFeature object, found {found}")
59            }
60            Self::UnsupportedType(found) => {
61                write!(f, "unsupported CityJSON type: {found}")
62            }
63            Self::UnsupportedVersion { found, supported } => {
64                write!(
65                    f,
66                    "unsupported CityJSON version {found}; supported versions: {supported}"
67                )
68            }
69            Self::Streaming(message) => write!(f, "streaming error: {message}"),
70            Self::Import(message) => write!(f, "import error: {message}"),
71            Self::UnsupportedFeature(message) => write!(f, "unsupported feature: {message}"),
72        }
73    }
74}
75
76impl Debug for Error {
77    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
78        Display::fmt(self, f)
79    }
80}
81
82impl error::Error for Error {}
83
84impl From<std::io::Error> for Error {
85    fn from(value: std::io::Error) -> Self {
86        Self::Io(value)
87    }
88}
89
90impl From<cityjson::error::Error> for Error {
91    fn from(value: cityjson::error::Error) -> Self {
92        Self::CityJSON(value)
93    }
94}
95
96#[cfg(any(feature = "arrow", feature = "parquet"))]
97impl From<cityjson_arrow::error::Error> for Error {
98    fn from(value: cityjson_arrow::error::Error) -> Self {
99        match value {
100            cityjson_arrow::error::Error::Arrow(error) => Self::Import(error.to_string()),
101            cityjson_arrow::error::Error::Parquet(error) => Self::Import(error.to_string()),
102            cityjson_arrow::error::Error::CityJSON(error) => Self::CityJSON(error),
103            cityjson_arrow::error::Error::Json(error) => Self::Syntax(error.to_string()),
104            cityjson_arrow::error::Error::Conversion(message) => Self::Import(message),
105            cityjson_arrow::error::Error::Unsupported(message) => Self::UnsupportedFeature(message),
106            cityjson_arrow::error::Error::SchemaMismatch { expected, found } => Self::Import(
107                format!("expected Arrow schema: {expected}, found schema: {found}"),
108            ),
109            cityjson_arrow::error::Error::MissingField(field) => {
110                Self::Import(format!("missing Arrow field: {field}"))
111            }
112            cityjson_arrow::error::Error::Io(error) => Self::Io(error),
113        }
114    }
115}
116
117#[cfg(feature = "json")]
118impl From<cityjson_json::Error> for Error {
119    fn from(value: cityjson_json::Error) -> Self {
120        match value {
121            cityjson_json::Error::Json(error) => Self::Syntax(error.to_string()),
122            cityjson_json::Error::Utf8(error) => Self::Syntax(error.to_string()),
123            cityjson_json::Error::CityJson(error) => Self::CityJSON(error),
124            cityjson_json::Error::UnsupportedType(found) => Self::UnsupportedType(found),
125            cityjson_json::Error::UnsupportedVersion(found) => Self::UnsupportedVersion {
126                found,
127                supported: cityjson::CityJSONVersion::V2_0.to_string(),
128            },
129            cityjson_json::Error::MalformedRootObject(reason) => Self::Syntax(reason.to_owned()),
130            cityjson_json::Error::InvalidValue(reason) => Self::Import(reason),
131            cityjson_json::Error::UnsupportedFeature(feature) => {
132                Self::UnsupportedFeature(feature.to_owned())
133            }
134            cityjson_json::Error::UnresolvedCityObjectReference {
135                source_id,
136                target_id,
137                relation,
138            } => Self::Import(format!(
139                "unresolved CityObject {relation} reference from '{source_id}' to '{target_id}'"
140            )),
141        }
142    }
143}