1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
45use crate::log;
6use crate::{marker::DataMarkerId, prelude::*};
7use core::fmt;
8use displaydoc::Display;
910/// A list specifying general categories of data provider error.
11///
12/// Errors may be caused either by a malformed request or by the data provider
13/// not being able to fulfill a well-formed request.
14#[derive(#[automatically_derived]
impl ::core::clone::Clone for DataErrorKind {
#[inline]
fn clone(&self) -> DataErrorKind {
let _: ::core::clone::AssertParamIsClone<DataMarkerInfo>;
let _: ::core::clone::AssertParamIsClone<&'static str>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DataErrorKind { }Copy, #[automatically_derived]
impl ::core::cmp::Eq for DataErrorKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<DataMarkerInfo>;
let _: ::core::cmp::AssertParamIsEq<&'static str>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialEq for DataErrorKind {
#[inline]
fn eq(&self, other: &DataErrorKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(DataErrorKind::InconsistentData(__self_0),
DataErrorKind::InconsistentData(__arg1_0)) =>
__self_0 == __arg1_0,
(DataErrorKind::Downcast(__self_0),
DataErrorKind::Downcast(__arg1_0)) => __self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () =
{
impl ::core::fmt::Display for DataErrorKind {
fn fmt(&self, formatter: &mut ::core::fmt::Formatter)
-> ::core::fmt::Result {
#[allow(unused_variables, unused_assignments)]
match self {
Self::MarkerNotFound => {
formatter.write_fmt(format_args!("Missing data for marker"))
}
Self::IdentifierNotFound => {
formatter.write_fmt(format_args!("Missing data for identifier"))
}
Self::InvalidRequest => {
formatter.write_fmt(format_args!("Invalid request"))
}
Self::InconsistentData(_0) => {
formatter.write_fmt(format_args!("The data for two markers is not consistent: {0:?} (were they generated in different datagen invocations?)",
_0))
}
Self::Downcast(_0) => {
formatter.write_fmt(format_args!("Downcast: expected {0}, found",
_0))
}
Self::Deserialize => {
formatter.write_fmt(format_args!("Deserialize"))
}
Self::Custom => {
formatter.write_fmt(format_args!("Custom"))
}
}
}
}
};Display, #[automatically_derived]
impl ::core::fmt::Debug for DataErrorKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
DataErrorKind::MarkerNotFound =>
::core::fmt::Formatter::write_str(f, "MarkerNotFound"),
DataErrorKind::IdentifierNotFound =>
::core::fmt::Formatter::write_str(f, "IdentifierNotFound"),
DataErrorKind::InvalidRequest =>
::core::fmt::Formatter::write_str(f, "InvalidRequest"),
DataErrorKind::InconsistentData(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InconsistentData", &__self_0),
DataErrorKind::Downcast(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Downcast", &__self_0),
DataErrorKind::Deserialize =>
::core::fmt::Formatter::write_str(f, "Deserialize"),
DataErrorKind::Custom =>
::core::fmt::Formatter::write_str(f, "Custom"),
}
}
}Debug)]
15#[non_exhaustive]
16pub enum DataErrorKind {
17/// No data for the requested data marker. This is only returned by [`DynamicDataProvider`].
18#[displaydoc("Missing data for marker")]
19MarkerNotFound,
2021/// There is data for the data marker, but not for this particular data identifier.
22#[displaydoc("Missing data for identifier")]
23IdentifierNotFound,
2425/// The request is invalid, such as a request for a singleton marker containing a data identifier.
26#[displaydoc("Invalid request")]
27InvalidRequest,
2829/// The data for two [`DataMarker`]s is not consistent.
30#[displaydoc(
31"The data for two markers is not consistent: {0:?} (were they generated in different datagen invocations?)"
32)]
33InconsistentData(DataMarkerInfo),
3435/// An error occured during [`Any`](core::any::Any) downcasting.
36#[displaydoc("Downcast: expected {0}, found")]
37Downcast(&'static str),
3839/// An error occured during [`serde`] deserialization.
40 ///
41 /// Check debug logs for potentially more information.
42#[displaydoc("Deserialize")]
43Deserialize,
4445/// An unspecified error occurred.
46 ///
47 /// Check debug logs for potentially more information.
48#[displaydoc("Custom")]
49Custom,
5051/// An error occurred while accessing a system resource.
52#[displaydoc("I/O: {0:?}")]
53 #[cfg(feature = "std")]
54Io(std::io::ErrorKind),
55}
5657/// The error type for ICU4X data provider operations.
58///
59/// To create one of these, either start with a [`DataErrorKind`] or use [`DataError::custom()`].
60///
61/// # Example
62///
63/// Create a [`DataErrorKind::IdentifierNotFound`] error and attach a data request for context:
64///
65/// ```no_run
66/// # use icu_provider::prelude::*;
67/// let marker: DataMarkerInfo = unimplemented!();
68/// let req: DataRequest = unimplemented!();
69/// DataErrorKind::IdentifierNotFound.with_req(marker, req);
70/// ```
71///
72/// Create a named custom error:
73///
74/// ```
75/// # use icu_provider::prelude::*;
76/// DataError::custom("This is an example error");
77/// ```
78#[derive(#[automatically_derived]
impl ::core::clone::Clone for DataError {
#[inline]
fn clone(&self) -> DataError {
let _: ::core::clone::AssertParamIsClone<DataErrorKind>;
let _: ::core::clone::AssertParamIsClone<Option<DataMarkerId>>;
let _: ::core::clone::AssertParamIsClone<Option<&'static str>>;
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DataError { }Copy, #[automatically_derived]
impl ::core::cmp::Eq for DataError {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<DataErrorKind>;
let _: ::core::cmp::AssertParamIsEq<Option<DataMarkerId>>;
let _: ::core::cmp::AssertParamIsEq<Option<&'static str>>;
let _: ::core::cmp::AssertParamIsEq<bool>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialEq for DataError {
#[inline]
fn eq(&self, other: &DataError) -> bool {
self.silent == other.silent && self.kind == other.kind &&
self.marker == other.marker &&
self.str_context == other.str_context
}
}PartialEq, #[automatically_derived]
impl ::core::fmt::Debug for DataError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field4_finish(f, "DataError",
"kind", &self.kind, "marker", &self.marker, "str_context",
&self.str_context, "silent", &&self.silent)
}
}Debug)]
79#[non_exhaustive]
80pub struct DataError {
81/// Broad category of the error.
82pub kind: DataErrorKind,
8384/// The data marker of the request, if available.
85pub marker: Option<DataMarkerId>,
8687/// Additional context, if available.
88pub str_context: Option<&'static str>,
8990/// Whether this error was created in silent mode to not log.
91pub silent: bool,
92}
9394impl fmt::Displayfor DataError {
95fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96f.write_fmt(format_args!("ICU4X data error"))write!(f, "ICU4X data error")?;
97if self.kind != DataErrorKind::Custom {
98f.write_fmt(format_args!(": {0}", self.kind))write!(f, ": {}", self.kind)?;
99 }
100if let Some(marker) = self.marker {
101f.write_fmt(format_args!(" (marker: {0:?})", marker))write!(f, " (marker: {marker:?})")?;
102 }
103if let Some(str_context) = self.str_context {
104f.write_fmt(format_args!(": {0}", str_context))write!(f, ": {str_context}")?;
105 }
106Ok(())
107 }
108}
109110impl DataErrorKind {
111/// Converts this [`DataErrorKind`] into a [`DataError`].
112 ///
113 /// If possible, you should attach context using a `with_` function.
114#[inline]
115pub const fn into_error(self) -> DataError {
116DataError {
117 kind: self,
118 marker: None,
119 str_context: None,
120 silent: false,
121 }
122 }
123124/// Creates a [`DataError`] with a data marker context.
125#[inline]
126pub const fn with_marker(self, marker: DataMarkerInfo) -> DataError {
127self.into_error().with_marker(marker)
128 }
129130/// Creates a [`DataError`] with a string context.
131#[inline]
132pub const fn with_str_context(self, context: &'static str) -> DataError {
133self.into_error().with_str_context(context)
134 }
135136/// Creates a [`DataError`] with a type name context.
137#[inline]
138pub fn with_type_context<T>(self) -> DataError {
139self.into_error().with_type_context::<T>()
140 }
141142/// Creates a [`DataError`] with a request context.
143#[inline]
144pub fn with_req(self, marker: DataMarkerInfo, req: DataRequest) -> DataError {
145self.into_error().with_req(marker, req)
146 }
147}
148149impl DataError {
150/// Returns a new, empty [`DataError`] with kind Custom and a string error message.
151#[inline]
152pub const fn custom(str_context: &'static str) -> Self {
153Self {
154 kind: DataErrorKind::Custom,
155 marker: None,
156 str_context: Some(str_context),
157 silent: false,
158 }
159 }
160161/// Sets the data marker of a [`DataError`], returning a modified error.
162#[inline]
163pub const fn with_marker(self, marker: DataMarkerInfo) -> Self {
164Self {
165 kind: self.kind,
166 marker: Some(marker.id),
167 str_context: self.str_context,
168 silent: self.silent,
169 }
170 }
171172/// Sets the string context of a [`DataError`], returning a modified error.
173#[inline]
174pub const fn with_str_context(self, context: &'static str) -> Self {
175Self {
176 kind: self.kind,
177 marker: self.marker,
178 str_context: Some(context),
179 silent: self.silent,
180 }
181 }
182183/// Sets the string context of a [`DataError`] to the given type name, returning a modified error.
184#[inline]
185pub fn with_type_context<T>(self) -> Self {
186if !self.silent {
187log::warn!("{self}: Type context: {}", core::any::type_name::<T>());
188 }
189self.with_str_context(core::any::type_name::<T>())
190 }
191192/// Logs the data error with the given request, returning an error containing the data marker.
193 ///
194 /// If the "logging" Cargo feature is enabled, this logs the whole request. Either way,
195 /// it returns an error with the data marker portion of the request as context.
196pub fn with_req(mut self, marker: DataMarkerInfo, req: DataRequest) -> Self {
197if req.metadata.silent {
198self.silent = true;
199 }
200// Don't write out a log for MissingDataMarker since there is no context to add
201if !self.silent && self.kind != DataErrorKind::MarkerNotFound {
202log::warn!("{self} (marker: {marker:?}, request: {})", req.id);
203 }
204self.with_marker(marker)
205 }
206207/// Logs the data error with the given context, then return self.
208 ///
209 /// This does not modify the error, but if the "logging" Cargo feature is enabled,
210 /// it will print out the context.
211#[cfg(feature = "std")]
212pub fn with_path_context(self, _path: &std::path::Path) -> Self {
213if !self.silent {
214log::warn!("{self} (path: {_path:?})");
215 }
216self
217}
218219/// Logs the data error with the given context, then return self.
220 ///
221 /// This does not modify the error, but if the "logging" Cargo feature is enabled,
222 /// it will print out the context.
223#[cfg_attr(not(feature = "logging"), allow(unused_variables))]
224 #[inline]
225pub fn with_display_context<D: fmt::Display + ?Sized>(self, context: &D) -> Self {
226if !self.silent {
227log::warn!("{self}: {context}");
228 }
229self230 }
231232/// Logs the data error with the given context, then return self.
233 ///
234 /// This does not modify the error, but if the "logging" Cargo feature is enabled,
235 /// it will print out the context.
236#[cfg_attr(not(feature = "logging"), allow(unused_variables))]
237 #[inline]
238pub fn with_debug_context<D: fmt::Debug + ?Sized>(self, context: &D) -> Self {
239if !self.silent {
240log::warn!("{self}: {context:?}");
241 }
242self243 }
244245#[inline]
246pub(crate) fn for_type<T>() -> DataError {
247DataError {
248 kind: DataErrorKind::Downcast(core::any::type_name::<T>()),
249 marker: None,
250 str_context: None,
251 silent: false,
252 }
253 }
254}
255256impl core::error::Errorfor DataError {}
257258#[cfg(feature = "std")]
259impl From<std::io::Error> for DataError {
260fn from(e: std::io::Error) -> Self {
261log::warn!("I/O error: {e}");
262 DataErrorKind::Io(e.kind()).into_error()
263 }
264}
265266/// Extension trait for `Result<T, DataError>`.
267pub trait ResultDataError<T>: Sized {
268/// Propagates all errors other than [`DataErrorKind::IdentifierNotFound`], and returns `None` in that case.
269fn allow_identifier_not_found(self) -> Result<Option<T>, DataError>;
270}
271272impl<T> ResultDataError<T> for Result<T, DataError> {
273fn allow_identifier_not_found(self) -> Result<Option<T>, DataError> {
274match self {
275Ok(t) => Ok(Some(t)),
276Err(DataError {
277 kind: DataErrorKind::IdentifierNotFound,
278 ..
279 }) => Ok(None),
280Err(e) => Err(e),
281 }
282 }
283}