Skip to main content

cityjson_types/
error.rs

1//! Error types.
2use std::fmt::{Debug, Display, Formatter};
3
4/// Errors returned by cityjson-rs operations.
5#[derive(Clone, Hash, PartialEq, Eq)]
6#[non_exhaustive]
7pub enum Error {
8    /// Boundary type mismatch — e.g. trying to convert a `Solid` boundary into a `MultiPoint`.
9    IncompatibleBoundary(String, String),
10    /// A vertex index could not be converted between integer types (e.g. `u64` → `u16` overflow).
11    IndexConversion {
12        source_type: String,
13        target_type: String,
14        value: String,
15    },
16    /// A vertex index value exceeds the range of the target index type.
17    IndexOverflow { index_type: String, value: String },
18    /// The vertex container is full for the chosen `VR` type (e.g. more than `u32::MAX` vertices).
19    VerticesContainerFull { attempted: usize, maximum: usize },
20    /// A resource pool (semantics, materials, textures, or geometries) has reached its limit.
21    ResourcePoolFull { attempted: usize, maximum: usize },
22    /// General geometry validation failure.
23    InvalidGeometry(String),
24    /// A shell failed validation (e.g. fewer than four surfaces for a closed solid).
25    InvalidShell {
26        reason: String,
27        surface_count: usize,
28    },
29    /// A ring failed validation (e.g. fewer than three vertices).
30    InvalidRing { reason: String, vertex_count: usize },
31    /// A linestring failed validation (e.g. fewer than two vertices).
32    InvalidLineString { reason: String, vertex_count: usize },
33    /// A boundary index references an element that does not exist.
34    InvalidReference {
35        element_type: String,
36        index: usize,
37        max_index: usize,
38    },
39    /// A configured default appearance theme name does not exist in the model.
40    InvalidThemeName { theme_type: String, theme: String },
41    /// A geometry operation expected one type but found another.
42    InvalidGeometryType { expected: String, found: String },
43    /// A geometry is structurally incomplete (e.g. missing required fields).
44    IncompleteGeometry(String),
45    /// The `CityJSON` `"version"` field holds an unsupported value.
46    UnsupportedVersion(String, String),
47    /// The city object type string is not a known `CityJSON` type and does not start with `"+"`.
48    InvalidCityObjectType(String),
49    /// JSON parsing failed.
50    InvalidJson(String),
51    /// The `CityJSON` document is missing the required `"version"` field.
52    MissingVersion,
53    /// The `CityJSON` version is not supported by this crate.
54    UnsupportedCityJSONVersion(String),
55    /// An I/O or import error.
56    Import(String),
57}
58
59pub type Result<T> = std::result::Result<T, Error>;
60
61impl Display for Error {
62    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
63        match self {
64            Error::IncompatibleBoundary(source_boundarytype, target_boundarytype) => {
65                write!(
66                    f,
67                    "cannot convert a {source_boundarytype} to a {target_boundarytype}"
68                )
69            }
70            Error::IndexConversion {
71                source_type,
72                target_type,
73                value,
74            } => write!(
75                f,
76                "failed to convert index from {source_type} to {target_type}: value {value}"
77            ),
78            Error::IndexOverflow { index_type, value } => {
79                write!(f, "index overflow for {index_type}: value {value}")
80            }
81            Error::VerticesContainerFull { attempted, maximum } => write!(
82                f,
83                "attempted to store {attempted} vertices in a container with capacity {maximum}"
84            ),
85            Error::ResourcePoolFull { attempted, maximum } => write!(
86                f,
87                "attempted to store {attempted} resources in a pool with maximum {maximum} slots"
88            ),
89            Error::InvalidGeometry(msg) => write!(f, "{msg}"),
90            Error::InvalidShell {
91                reason,
92                surface_count,
93            } => write!(
94                f,
95                "Invalid shell: {reason} (surface count: {surface_count})"
96            ),
97            Error::InvalidRing {
98                reason,
99                vertex_count,
100            } => write!(f, "Invalid ring: {reason} (vertex count: {vertex_count})"),
101            Error::InvalidLineString {
102                reason,
103                vertex_count,
104            } => write!(
105                f,
106                "Invalid linestring: {reason} (vertex count: {vertex_count})"
107            ),
108            Error::InvalidReference {
109                element_type,
110                index,
111                max_index,
112            } => write!(
113                f,
114                "Invalid {element_type} index: {index} (max: {max_index})"
115            ),
116            Error::InvalidThemeName { theme_type, theme } => {
117                write!(f, "Invalid {theme_type} theme name: {theme}")
118            }
119            Error::InvalidGeometryType { expected, found } => {
120                write!(
121                    f,
122                    "Invalid geometry type: expected {expected}, found {found}"
123                )
124            }
125            Error::IncompleteGeometry(msg) => write!(f, "Incomplete geometry: {msg}"),
126            Error::UnsupportedVersion(v, supported) => {
127                write!(
128                    f,
129                    "the CityJSON version should be one of {supported}, but got {v}"
130                )
131            }
132            Error::InvalidCityObjectType(v) => write!(f, "invalid CityObject type: {v}"),
133            Error::InvalidJson(msg) => write!(f, "Invalid JSON: {msg}"),
134            Error::MissingVersion => write!(f, "Missing 'version' field in CityJSON document"),
135            Error::UnsupportedCityJSONVersion(version) => {
136                write!(f, "Unsupported CityJSON version: {version}")
137            }
138            Error::Import(msg) => write!(f, "Import error: {msg}"),
139        }
140    }
141}
142
143impl Debug for Error {
144    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
145        write!(f, "{self}")
146    }
147}
148
149impl std::error::Error for Error {}
150
151impl From<std::io::Error> for Error {
152    fn from(value: std::io::Error) -> Self {
153        Error::Import(value.to_string())
154    }
155}