1use crate::_internal::log;
6use crate::buf::BufferFormat;
7use crate::prelude::*;
8use core::fmt;
9use displaydoc::Display;
10
11#[derive(Clone, Copy, Eq, PartialEq, Display, Debug)]
16#[non_exhaustive]
17pub enum DataErrorKind {
18 #[displaydoc("Missing data for key")]
20 MissingDataKey,
21
22 #[displaydoc("Missing data for locale")]
24 MissingLocale,
25
26 #[displaydoc("Request needs a locale")]
28 NeedsLocale,
29
30 #[displaydoc("Request has an extraneous locale")]
32 ExtraneousLocale,
33
34 #[displaydoc("Resource blocked by filter")]
36 FilteredResource,
37
38 #[displaydoc("Mismatched types: tried to downcast with {0}, but actual type is different")]
41 MismatchedType(&'static str),
42
43 #[displaydoc("Missing payload")]
45 MissingPayload,
46
47 #[displaydoc("Invalid state")]
49 InvalidState,
50
51 #[displaydoc("Parse error for data key or data locale")]
53 KeyLocaleSyntax,
54
55 #[displaydoc("Custom")]
59 Custom,
60
61 #[displaydoc("I/O error: {0:?}")]
63 #[cfg(feature = "std")]
64 Io(std::io::ErrorKind),
65
66 #[displaydoc("Missing source data")]
68 #[cfg(feature = "datagen")]
69 MissingSourceData,
70
71 #[displaydoc("Unavailable buffer format: {0:?} (does icu_provider need to be compiled with an additional Cargo feature?)")]
74 UnavailableBufferFormat(BufferFormat),
75}
76
77#[derive(Clone, Copy, Eq, PartialEq, Debug)]
99#[non_exhaustive]
100pub struct DataError {
101 pub kind: DataErrorKind,
103
104 pub key: Option<DataKey>,
106
107 pub str_context: Option<&'static str>,
109
110 pub silent: bool,
112}
113
114impl fmt::Display for DataError {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(f, "ICU4X data error")?;
117 if self.kind != DataErrorKind::Custom {
118 write!(f, ": {}", self.kind)?;
119 }
120 if let Some(key) = self.key {
121 write!(f, " (key: {key})")?;
122 }
123 if let Some(str_context) = self.str_context {
124 write!(f, ": {str_context}")?;
125 }
126 Ok(())
127 }
128}
129
130impl DataErrorKind {
131 #[inline]
135 pub const fn into_error(self) -> DataError {
136 DataError {
137 kind: self,
138 key: None,
139 str_context: None,
140 silent: false,
141 }
142 }
143
144 #[inline]
146 pub const fn with_key(self, key: DataKey) -> DataError {
147 self.into_error().with_key(key)
148 }
149
150 #[inline]
152 pub const fn with_str_context(self, context: &'static str) -> DataError {
153 self.into_error().with_str_context(context)
154 }
155
156 #[inline]
158 pub fn with_type_context<T>(self) -> DataError {
159 self.into_error().with_type_context::<T>()
160 }
161
162 #[inline]
164 pub fn with_req(self, key: DataKey, req: DataRequest) -> DataError {
165 self.into_error().with_req(key, req)
166 }
167}
168
169impl DataError {
170 #[inline]
172 pub const fn custom(str_context: &'static str) -> Self {
173 Self {
174 kind: DataErrorKind::Custom,
175 key: None,
176 str_context: Some(str_context),
177 silent: false,
178 }
179 }
180
181 #[inline]
183 pub const fn with_key(self, key: DataKey) -> Self {
184 Self {
185 kind: self.kind,
186 key: Some(key),
187 str_context: self.str_context,
188 silent: self.silent,
189 }
190 }
191
192 #[inline]
194 pub const fn with_str_context(self, context: &'static str) -> Self {
195 Self {
196 kind: self.kind,
197 key: self.key,
198 str_context: Some(context),
199 silent: self.silent,
200 }
201 }
202
203 #[inline]
205 pub fn with_type_context<T>(self) -> Self {
206 if !self.silent {
207 log::warn!("{self}: Type context: {}", core::any::type_name::<T>());
208 }
209 self.with_str_context(core::any::type_name::<T>())
210 }
211
212 pub fn with_req(mut self, key: DataKey, req: DataRequest) -> Self {
217 if req.metadata.silent {
218 self.silent = true;
219 }
220 if !self.silent && self.kind != DataErrorKind::MissingDataKey {
222 log::warn!("{} (key: {}, request: {})", self, key, req);
223 }
224 self.with_key(key)
225 }
226
227 #[cfg(feature = "std")]
232 pub fn with_path_context<P: AsRef<std::path::Path> + ?Sized>(self, _path: &P) -> Self {
233 if !self.silent {
234 log::warn!("{} (path: {:?})", self, _path.as_ref());
235 }
236 self
237 }
238
239 #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
244 #[inline]
245 pub fn with_display_context<D: fmt::Display + ?Sized>(self, context: &D) -> Self {
246 if !self.silent {
247 log::warn!("{}: {}", self, context);
248 }
249 self
250 }
251
252 #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
257 #[inline]
258 pub fn with_debug_context<D: fmt::Debug + ?Sized>(self, context: &D) -> Self {
259 if !self.silent {
260 log::warn!("{}: {:?}", self, context);
261 }
262 self
263 }
264
265 #[inline]
266 pub(crate) fn for_type<T>() -> DataError {
267 DataError {
268 kind: DataErrorKind::MismatchedType(core::any::type_name::<T>()),
269 key: None,
270 str_context: None,
271 silent: false,
272 }
273 }
274}
275
276#[cfg(feature = "std")]
277impl std::error::Error for DataError {}
278
279#[cfg(feature = "std")]
280impl From<std::io::Error> for DataError {
281 fn from(e: std::io::Error) -> Self {
282 log::warn!("I/O error: {}", e);
283 DataErrorKind::Io(e.kind()).into_error()
284 }
285}