jiff_icu/
error.rs

1/// Creates a new ad hoc error via `format_args!`.
2macro_rules! err {
3    ($($tt:tt)*) => {{
4        crate::error::Error::adhoc_from_args(format_args!($($tt)*))
5    }}
6}
7
8pub(crate) use err;
9
10/// An error that can occur when converting between types in this crate.
11#[derive(Clone, Debug)]
12pub struct Error {
13    kind: ErrorKind,
14}
15
16impl Error {
17    /// Creates an error from an arbitrary `core::fmt::Arguments`.
18    ///
19    /// When `alloc` isn't enabled, then `Arguments::as_str()` is used to
20    /// find an error message. Otherwise, a generic error message is emitted.
21    pub(crate) fn adhoc_from_args<'a>(
22        message: core::fmt::Arguments<'a>,
23    ) -> Error {
24        let kind = ErrorKind::Adhoc(AdhocError::from_args(message));
25        Error { kind }
26    }
27}
28
29#[derive(Clone, Debug)]
30enum ErrorKind {
31    Adhoc(AdhocError),
32    Jiff(jiff::Error),
33}
34
35impl core::fmt::Display for Error {
36    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
37        match self.kind {
38            ErrorKind::Adhoc(ref err) => {
39                core::fmt::Display::fmt(&err.message, f)
40            }
41            ErrorKind::Jiff(ref err) => err.fmt(f),
42        }
43    }
44}
45
46// Why do we use `core::error::Error` here despite the fact that
47// we have a `std` feature? Well, because Jiff's `Error` type only
48// implements `std::error::Error` and can't (non-annoyingly) implement
49// `core::error::Error` because of its MSRV.
50#[cfg(feature = "std")]
51impl core::error::Error for Error {
52    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
53        match self.kind {
54            ErrorKind::Adhoc(_) => None,
55            ErrorKind::Jiff(ref err) => Some(err),
56        }
57    }
58}
59
60impl From<jiff::Error> for Error {
61    fn from(e: jiff::Error) -> Error {
62        Error { kind: ErrorKind::Jiff(e) }
63    }
64}
65
66/// A generic error message.
67#[derive(Clone, Debug)]
68struct AdhocError {
69    #[cfg(feature = "alloc")]
70    message: alloc::boxed::Box<str>,
71    #[cfg(not(feature = "alloc"))]
72    message: &'static str,
73}
74
75impl AdhocError {
76    fn from_args<'a>(message: core::fmt::Arguments<'a>) -> AdhocError {
77        #[cfg(feature = "alloc")]
78        {
79            AdhocError::from_display(message)
80        }
81        #[cfg(not(feature = "alloc"))]
82        {
83            let message = message.as_str().unwrap_or(
84                "unknown `jiff-icu` error (better error messages require \
85                 enabling the `alloc` feature for the `jiff-icu` crate)",
86            );
87            AdhocError::from_static_str(message)
88        }
89    }
90
91    #[cfg(feature = "alloc")]
92    fn from_display<'a>(message: impl core::fmt::Display + 'a) -> AdhocError {
93        use alloc::string::ToString;
94
95        let message = message.to_string().into_boxed_str();
96        AdhocError { message }
97    }
98
99    #[cfg(not(feature = "alloc"))]
100    fn from_static_str(message: &'static str) -> AdhocError {
101        AdhocError { message }
102    }
103}