]> git.proxmox.com Git - rustc.git/blame - vendor/icu_provider/src/error.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / vendor / icu_provider / src / error.rs
CommitLineData
487cf647
FG
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 ).
4
5use crate::buf::BufferFormat;
6use crate::prelude::*;
7use core::fmt;
8use displaydoc::Display;
9
10/// 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(Clone, Copy, Eq, PartialEq, Display, Debug)]
15#[non_exhaustive]
16pub enum DataErrorKind {
17 /// No data for the provided resource key.
18 #[displaydoc("Missing data for key")]
19 MissingDataKey,
20
21 /// There is data for the key, but not for this particular locale.
22 #[displaydoc("Missing data for locale")]
23 MissingLocale,
24
25 /// The request should include a locale.
26 #[displaydoc("Request needs a locale")]
27 NeedsLocale,
28
29 /// The request should not contain a locale.
30 #[displaydoc("Request has an extraneous locale")]
31 ExtraneousLocale,
32
33 /// The resource was blocked by a filter. The resource may or may not be available.
34 #[displaydoc("Resource blocked by filter")]
35 FilteredResource,
36
37 /// The generic type parameter does not match the TypeId. The expected type name is stored
38 /// as context when this error is returned.
39 #[displaydoc("Mismatched types: tried to downcast with {0}, but actual type is different")]
40 MismatchedType(&'static str),
41
42 /// The payload is missing. This is usually caused by a previous error.
43 #[displaydoc("Missing payload")]
44 MissingPayload,
45
46 /// A data provider object was given to an operation in an invalid state.
47 #[displaydoc("Invalid state")]
48 InvalidState,
49
50 /// An unspecified error occurred, such as a Serde error.
51 ///
52 /// Check debug logs for potentially more information.
53 #[displaydoc("Custom")]
54 Custom,
55
56 /// An error occurred while accessing a system resource.
57 #[displaydoc("I/O error: {0:?}")]
58 #[cfg(feature = "std")]
59 Io(std::io::ErrorKind),
60
61 /// An unspecified data source containing the required data is unavailable.
62 #[displaydoc("Missing source data")]
63 #[cfg(feature = "datagen")]
64 MissingSourceData,
65
66 /// An error indicating that the desired buffer format is not available. This usually
9ffffee4
FG
67 /// means that a required Cargo feature was not enabled
68 #[displaydoc("Unavailable buffer format: {0:?} (does icu_provider need to be compiled with an additional Cargo feature?)")]
487cf647
FG
69 UnavailableBufferFormat(BufferFormat),
70}
71
72/// The error type for ICU4X data provider operations.
73///
74/// To create one of these, either start with a [`DataErrorKind`] or use [`DataError::custom()`].
75///
76/// # Example
77///
78/// Create a NeedsLocale error and attach a data request for context:
79///
80/// ```no_run
81/// # use icu_provider::prelude::*;
82/// let key: DataKey = unimplemented!();
83/// let req: DataRequest = unimplemented!();
84/// DataErrorKind::NeedsLocale.with_req(key, req);
85/// ```
86///
87/// Create a named custom error:
88///
89/// ```
90/// # use icu_provider::prelude::*;
91/// DataError::custom("This is an example error");
92/// ```
93#[derive(Clone, Copy, Eq, PartialEq, Debug)]
94#[non_exhaustive]
95pub struct DataError {
96 /// Broad category of the error.
97 pub kind: DataErrorKind,
98
99 /// The data key of the request, if available.
100 pub key: Option<DataKey>,
101
102 /// Additional context, if available.
103 pub str_context: Option<&'static str>,
104}
105
106impl fmt::Display for DataError {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 write!(f, "ICU4X data error")?;
109 if self.kind != DataErrorKind::Custom {
110 write!(f, ": {}", self.kind)?;
111 }
112 if let Some(key) = self.key {
113 write!(f, " (key: {})", key)?;
114 }
115 if let Some(str_context) = self.str_context {
116 write!(f, ": {}", str_context)?;
117 }
118 Ok(())
119 }
120}
121
122impl DataErrorKind {
123 /// Converts this DataErrorKind into a DataError.
124 ///
125 /// If possible, you should attach context using a `with_` function.
126 #[inline]
127 pub const fn into_error(self) -> DataError {
128 DataError {
129 kind: self,
130 key: None,
131 str_context: None,
132 }
133 }
134
135 /// Creates a DataError with a resource key context.
136 #[inline]
137 pub const fn with_key(self, key: DataKey) -> DataError {
138 self.into_error().with_key(key)
139 }
140
141 /// Creates a DataError with a string context.
142 #[inline]
143 pub const fn with_str_context(self, context: &'static str) -> DataError {
144 self.into_error().with_str_context(context)
145 }
146
147 /// Creates a DataError with a type name context.
148 #[inline]
149 pub fn with_type_context<T>(self) -> DataError {
150 self.into_error().with_type_context::<T>()
151 }
152
153 /// Creates a DataError with a request context.
154 #[inline]
155 pub fn with_req(self, key: DataKey, req: DataRequest) -> DataError {
156 self.into_error().with_req(key, req)
157 }
158}
159
160impl DataError {
161 /// Returns a new, empty DataError with kind Custom and a string error message.
162 #[inline]
163 pub const fn custom(str_context: &'static str) -> Self {
164 Self {
165 kind: DataErrorKind::Custom,
166 key: None,
167 str_context: Some(str_context),
168 }
169 }
170
171 /// Sets the resource key of a DataError, returning a modified error.
172 #[inline]
173 pub const fn with_key(self, key: DataKey) -> Self {
174 Self {
175 kind: self.kind,
176 key: Some(key),
177 str_context: self.str_context,
178 }
179 }
180
181 /// Sets the string context of a DataError, returning a modified error.
182 #[inline]
183 pub const fn with_str_context(self, context: &'static str) -> Self {
184 Self {
185 kind: self.kind,
186 key: self.key,
187 str_context: Some(context),
188 }
189 }
190
191 /// Sets the string context of a DataError to the given type name, returning a modified error.
192 #[inline]
193 pub fn with_type_context<T>(self) -> Self {
194 self.with_str_context(core::any::type_name::<T>())
195 }
196
197 /// Logs the data error with the given request, returning an error containing the resource key.
198 ///
9ffffee4 199 /// If the "log_error_context" Cargo feature is enabled, this logs the whole request. Either way,
487cf647
FG
200 /// it returns an error with the resource key portion of the request as context.
201 #[cfg_attr(not(feature = "log_error_context"), allow(unused_variables))]
202 pub fn with_req(self, key: DataKey, req: DataRequest) -> Self {
203 // Don't write out a log for MissingDataKey since there is no context to add
204 #[cfg(feature = "log_error_context")]
205 if self.kind != DataErrorKind::MissingDataKey {
206 log::warn!("{} (key: {}, request: {})", self, key, req);
207 }
208 self.with_key(key)
209 }
210
211 /// Logs the data error with the given context, then return self.
212 ///
9ffffee4 213 /// This does not modify the error, but if the "log_error_context" Cargo feature is enabled,
487cf647
FG
214 /// it will print out the context.
215 #[cfg(feature = "std")]
216 #[cfg_attr(not(feature = "log_error_context"), allow(unused_variables))]
217 pub fn with_path_context<P: AsRef<std::path::Path> + ?Sized>(self, path: &P) -> Self {
218 #[cfg(feature = "log_error_context")]
219 log::warn!("{} (path: {:?})", self, path.as_ref());
220 self
221 }
222
223 /// Logs the data error with the given context, then return self.
224 ///
9ffffee4 225 /// This does not modify the error, but if the "log_error_context" Cargo feature is enabled,
487cf647
FG
226 /// it will print out the context.
227 #[cfg_attr(not(feature = "log_error_context"), allow(unused_variables))]
228 #[inline]
229 pub fn with_display_context<D: fmt::Display + ?Sized>(self, context: &D) -> Self {
230 #[cfg(feature = "log_error_context")]
231 log::warn!("{}: {}", self, context);
232 self
233 }
234
235 /// Logs the data error with the given context, then return self.
236 ///
9ffffee4 237 /// This does not modify the error, but if the "log_error_context" Cargo feature is enabled,
487cf647
FG
238 /// it will print out the context.
239 #[cfg_attr(not(feature = "log_error_context"), allow(unused_variables))]
240 #[inline]
241 pub fn with_debug_context<D: fmt::Debug + ?Sized>(self, context: &D) -> Self {
242 #[cfg(feature = "log_error_context")]
243 log::warn!("{}: {:?}", self, context);
244 self
245 }
246
247 #[inline]
248 pub(crate) fn for_type<T>() -> DataError {
249 DataError {
250 kind: DataErrorKind::MismatchedType(core::any::type_name::<T>()),
251 key: None,
252 str_context: None,
253 }
254 }
255}
256
257#[cfg(feature = "std")]
258impl std::error::Error for DataError {}
259
260#[cfg(feature = "std")]
261impl From<std::io::Error> for DataError {
262 fn from(e: std::io::Error) -> Self {
263 #[cfg(feature = "log_error_context")]
264 log::warn!("I/O error: {}", e);
265 DataErrorKind::Io(e.kind()).into_error()
266 }
267}