1use crate::log;
6use crate::{marker::DataMarkerId, prelude::*};
7use core::fmt;
8use displaydoc::Display;
9
10#[derive(Clone, Copy, Eq, PartialEq, Display, Debug)]
15#[non_exhaustive]
16pub enum DataErrorKind {
17 #[displaydoc("Missing data for marker")]
19 MarkerNotFound,
20
21 #[displaydoc("Missing data for identifier")]
23 IdentifierNotFound,
24
25 #[displaydoc("Invalid request")]
27 InvalidRequest,
28
29 #[displaydoc(
31 "The data for two markers is not consistent: {0:?} (were they generated in different datagen invocations?)"
32 )]
33 InconsistentData(DataMarkerInfo),
34
35 #[displaydoc("Downcast: expected {0}, found")]
37 Downcast(&'static str),
38
39 #[displaydoc("Deserialize")]
43 Deserialize,
44
45 #[displaydoc("Custom")]
49 Custom,
50
51 #[displaydoc("I/O: {0:?}")]
53 #[cfg(feature = "std")]
54 Io(std::io::ErrorKind),
55}
56
57#[derive(Clone, Copy, Eq, PartialEq, Debug)]
79#[non_exhaustive]
80pub struct DataError {
81 pub kind: DataErrorKind,
83
84 pub marker: Option<DataMarkerId>,
86
87 pub str_context: Option<&'static str>,
89
90 pub silent: bool,
92}
93
94impl fmt::Display for DataError {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 write!(f, "ICU4X data error")?;
97 if self.kind != DataErrorKind::Custom {
98 write!(f, ": {}", self.kind)?;
99 }
100 if let Some(marker) = self.marker {
101 write!(f, " (marker: {marker:?})")?;
102 }
103 if let Some(str_context) = self.str_context {
104 write!(f, ": {str_context}")?;
105 }
106 Ok(())
107 }
108}
109
110impl DataErrorKind {
111 #[inline]
115 pub const fn into_error(self) -> DataError {
116 DataError {
117 kind: self,
118 marker: None,
119 str_context: None,
120 silent: false,
121 }
122 }
123
124 #[inline]
126 pub const fn with_marker(self, marker: DataMarkerInfo) -> DataError {
127 self.into_error().with_marker(marker)
128 }
129
130 #[inline]
132 pub const fn with_str_context(self, context: &'static str) -> DataError {
133 self.into_error().with_str_context(context)
134 }
135
136 #[inline]
138 pub fn with_type_context<T>(self) -> DataError {
139 self.into_error().with_type_context::<T>()
140 }
141
142 #[inline]
144 pub fn with_req(self, marker: DataMarkerInfo, req: DataRequest) -> DataError {
145 self.into_error().with_req(marker, req)
146 }
147}
148
149impl DataError {
150 #[inline]
152 pub const fn custom(str_context: &'static str) -> Self {
153 Self {
154 kind: DataErrorKind::Custom,
155 marker: None,
156 str_context: Some(str_context),
157 silent: false,
158 }
159 }
160
161 #[inline]
163 pub const fn with_marker(self, marker: DataMarkerInfo) -> Self {
164 Self {
165 kind: self.kind,
166 marker: Some(marker.id),
167 str_context: self.str_context,
168 silent: self.silent,
169 }
170 }
171
172 #[inline]
174 pub const fn with_str_context(self, context: &'static str) -> Self {
175 Self {
176 kind: self.kind,
177 marker: self.marker,
178 str_context: Some(context),
179 silent: self.silent,
180 }
181 }
182
183 #[inline]
185 pub fn with_type_context<T>(self) -> Self {
186 if !self.silent {
187 log::warn!("{self}: Type context: {}", core::any::type_name::<T>());
188 }
189 self.with_str_context(core::any::type_name::<T>())
190 }
191
192 pub fn with_req(mut self, marker: DataMarkerInfo, req: DataRequest) -> Self {
197 if req.metadata.silent {
198 self.silent = true;
199 }
200 if !self.silent && self.kind != DataErrorKind::MarkerNotFound {
202 log::warn!("{self} (marker: {marker:?}, request: {})", req.id);
203 }
204 self.with_marker(marker)
205 }
206
207 #[cfg(feature = "std")]
212 pub fn with_path_context(self, _path: &std::path::Path) -> Self {
213 if !self.silent {
214 log::warn!("{self} (path: {_path:?})");
215 }
216 self
217 }
218
219 #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
224 #[inline]
225 pub fn with_display_context<D: fmt::Display + ?Sized>(self, context: &D) -> Self {
226 if !self.silent {
227 log::warn!("{self}: {context}");
228 }
229 self
230 }
231
232 #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
237 #[inline]
238 pub fn with_debug_context<D: fmt::Debug + ?Sized>(self, context: &D) -> Self {
239 if !self.silent {
240 log::warn!("{self}: {context:?}");
241 }
242 self
243 }
244
245 #[inline]
246 pub(crate) fn for_type<T>() -> DataError {
247 DataError {
248 kind: DataErrorKind::Downcast(core::any::type_name::<T>()),
249 marker: None,
250 str_context: None,
251 silent: false,
252 }
253 }
254}
255
256impl core::error::Error for DataError {}
257
258#[cfg(feature = "std")]
259impl From<std::io::Error> for DataError {
260 fn from(e: std::io::Error) -> Self {
261 log::warn!("I/O error: {e}");
262 DataErrorKind::Io(e.kind()).into_error()
263 }
264}
265
266pub trait ResultDataError<T>: Sized {
268 fn allow_identifier_not_found(self) -> Result<Option<T>, DataError>;
270}
271
272impl<T> ResultDataError<T> for Result<T, DataError> {
273 fn allow_identifier_not_found(self) -> Result<Option<T>, DataError> {
274 match self {
275 Ok(t) => Ok(Some(t)),
276 Err(DataError {
277 kind: DataErrorKind::IdentifierNotFound,
278 ..
279 }) => Ok(None),
280 Err(e) => Err(e),
281 }
282 }
283}