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> {}