datetime_string/
error.rs

1//! Datetime error.
2
3use core::fmt;
4
5use crate::datetime::DateError;
6
7/// Component kind.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9#[non_exhaustive]
10pub(crate) enum ComponentKind {
11    /// Year.
12    Year,
13    /// Month.
14    Month,
15    /// Day of month.
16    Mday,
17    /// Hour.
18    Hour,
19    /// Minute.
20    Minute,
21    /// Second.
22    Second,
23    /// Fraction part of a second.
24    Secfrac,
25    /// Time offset.
26    Offset,
27    /// Hour of time offset.
28    OffsetHour,
29    /// Minute of time offset.
30    OffsetMinute,
31}
32
33impl ComponentKind {
34    /// Returns a name of the component.
35    fn as_str(&self) -> &'static str {
36        match self {
37            Self::Year => "year",
38            Self::Month => "month",
39            Self::Mday => "day of month",
40            Self::Hour => "hour",
41            Self::Minute => "minute",
42            Self::Second => "second",
43            Self::Secfrac => "secfrac",
44            Self::Offset => "time offset",
45            Self::OffsetHour => "time offset hour",
46            Self::OffsetMinute => "time offset minute",
47        }
48    }
49}
50
51/// Validation error kind.
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53#[non_exhaustive]
54pub(crate) enum ErrorKind {
55    /// Invalid separator.
56    InvalidSeparator,
57    /// Invalid component type.
58    InvalidComponentType(ComponentKind),
59    /// Component value is out of range.
60    ComponentOutOfRange(ComponentKind),
61    /// String is too short or lacks expected following components.
62    TooShort,
63    /// String is too long or contains unexpected suffix.
64    TooLong,
65}
66
67/// Validation error.
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub struct Error {
70    /// Error kind.
71    kind: ErrorKind,
72}
73
74impl fmt::Display for Error {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        match self.kind {
77            ErrorKind::InvalidSeparator => write!(f, "Invalid separator"),
78            ErrorKind::InvalidComponentType(component) => {
79                write!(f, "Invalid component type for {}", component.as_str())
80            }
81            ErrorKind::ComponentOutOfRange(component) => {
82                write!(f, "Out of range value for {}", component.as_str())
83            }
84            ErrorKind::TooShort => write!(f, "Too short"),
85            ErrorKind::TooLong => write!(f, "Too long"),
86        }
87    }
88}
89
90#[cfg(feature = "std")]
91#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
92impl std::error::Error for Error {}
93
94impl From<ErrorKind> for Error {
95    #[inline]
96    fn from(kind: ErrorKind) -> Self {
97        Self { kind }
98    }
99}
100
101impl From<DateError> for Error {
102    #[inline]
103    fn from(e: DateError) -> Self {
104        match e {
105            DateError::MonthOutOfRange => {
106                ErrorKind::ComponentOutOfRange(ComponentKind::Month).into()
107            }
108            DateError::MdayOutOfRange => ErrorKind::ComponentOutOfRange(ComponentKind::Mday).into(),
109        }
110    }
111}
112
113/// Error with value before conversion.
114#[derive(Debug, Clone)]
115pub struct ConversionError<T> {
116    /// Conversion source value.
117    value: T,
118    /// Error.
119    error: Error,
120}
121
122impl<T> ConversionError<T> {
123    /// Creates a new error.
124    #[cfg(feature = "alloc")]
125    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
126    #[inline]
127    #[must_use]
128    pub(crate) fn new<E: Into<Error>>(value: T, error: E) -> Self {
129        Self {
130            value,
131            error: error.into(),
132        }
133    }
134
135    /// Returns the inner (validation) error.
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// # {
141    /// // `rfc3339::FullTimeString` is only available when `alloc` feature is enabled.
142    /// #![cfg(feature = "alloc")]
143    ///
144    /// # use datetime_string::ConversionError;
145    /// use std::convert::TryFrom;
146    /// use datetime_string::{Error, rfc3339::FullTimeString};
147    ///
148    /// let conv_err = FullTimeString::try_from("invalid time".to_owned()).unwrap_err();
149    /// let _: Error = conv_err.error();
150    /// # }
151    /// ```
152    #[inline]
153    #[must_use]
154    pub fn error(&self) -> Error {
155        self.error
156    }
157
158    /// Returns a reference to the value, which is failed to convert.
159    ///
160    /// # Examples
161    ///
162    /// ```
163    /// # {
164    /// // `rfc3339::FullTimeString` is only available when `alloc` feature is enabled.
165    /// #![cfg(feature = "alloc")]
166    ///
167    /// # use datetime_string::ConversionError;
168    /// use std::convert::TryFrom;
169    /// use datetime_string::{Error, rfc3339::FullTimeString};
170    ///
171    /// let conv_err = FullTimeString::try_from("invalid time".to_owned()).unwrap_err();
172    /// let source_val: &String = conv_err.value();
173    /// assert_eq!(source_val, "invalid time");
174    /// # }
175    /// ```
176    #[inline]
177    #[must_use]
178    pub fn value(&self) -> &T {
179        &self.value
180    }
181
182    /// Returns the value, which is failed to convert.
183    ///
184    /// # Examples
185    ///
186    /// ```
187    /// # {
188    /// // `rfc3339::FullTimeString` is only available when `alloc` feature is enabled.
189    /// #![cfg(feature = "alloc")]
190    ///
191    /// # use datetime_string::ConversionError;
192    /// use std::convert::TryFrom;
193    /// use datetime_string::{Error, rfc3339::FullTimeString};
194    ///
195    /// let conv_err = FullTimeString::try_from("invalid time".to_owned()).unwrap_err();
196    /// let source_val: String = conv_err.into_value();
197    /// assert_eq!(source_val, "invalid time");
198    /// # }
199    /// ```
200    #[inline]
201    #[must_use]
202    pub fn into_value(self) -> T {
203        self.value
204    }
205}
206
207impl<T: fmt::Debug> fmt::Display for ConversionError<T> {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        write!(f, "Failed to convert {:?}: {}", self.value, self.error)
210    }
211}
212
213#[cfg(feature = "std")]
214#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
215impl<T: fmt::Debug> std::error::Error for ConversionError<T> {}