1use std::error::Error;
9use std::fmt::Display;
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14#[derive(Debug, PartialEq, Eq, Clone, Hash)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[non_exhaustive]
18pub enum ParseError {
19 Empty,
21 Syntax(usize, String),
24 Overflow,
28 TimeUnit(usize, String),
31 NegativeExponentOverflow,
33 PositiveExponentOverflow,
35 NegativeNumber,
38 InvalidInput(String),
40}
41
42impl Error for ParseError {}
43
44impl Display for ParseError {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 let msg = match self {
47 Self::Syntax(column, reason) => {
48 format!("Syntax error: {reason} at column {column}")
49 }
50 Self::Overflow => "Number overflow".to_owned(),
51 Self::TimeUnit(pos, reason) => {
52 format!("Time unit error: {reason} at column {pos}")
53 }
54 Self::NegativeExponentOverflow => {
55 "Negative exponent overflow: Minimum is -32768".to_owned()
56 }
57 Self::PositiveExponentOverflow => {
58 "Positive exponent overflow: Maximum is +32767".to_owned()
59 }
60 Self::NegativeNumber => "Number was negative".to_owned(),
61 Self::InvalidInput(reason) => format!("Invalid input: {reason}"),
62 Self::Empty => "Empty input".to_owned(),
63 };
64 f.write_str(&msg)
65 }
66}
67
68#[derive(Debug, PartialEq, Eq, Clone, Hash)]
71#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
72pub enum TryFromDurationError {
73 NegativeDuration,
75 PositiveOverflow,
77 NegativeOverflow,
79}
80
81impl From<TryFromDurationError> for ParseError {
82 fn from(error: TryFromDurationError) -> Self {
83 match error {
84 TryFromDurationError::NegativeDuration => Self::NegativeNumber,
85 TryFromDurationError::PositiveOverflow | TryFromDurationError::NegativeOverflow => {
86 Self::Overflow
87 }
88 }
89 }
90}
91
92impl Error for TryFromDurationError {}
93
94impl Display for TryFromDurationError {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 let description = match self {
97 Self::NegativeDuration => "Error converting duration: value is negative",
98 Self::PositiveOverflow => {
99 "Error converting duration: value overflows the positive value range"
100 }
101 Self::NegativeOverflow => {
102 "Error converting duration: value overflows the negative value range"
103 }
104 };
105 description.fmt(f)
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use rstest::rstest;
112 #[cfg(feature = "serde")]
113 use serde_test::{assert_tokens, Token};
114
115 use super::*;
116
117 #[rstest]
118 #[case::syntax_error(
119 ParseError::Syntax(10, "Invalid character".to_owned()),
120 "Syntax error: Invalid character at column 10"
121 )]
122 #[case::overflow(ParseError::Overflow, "Number overflow")]
123 #[case::time_unit_error(
124 ParseError::TimeUnit(10, "Found invalid 'y'".to_owned()),
125 "Time unit error: Found invalid 'y' at column 10"
126 )]
127 #[case::negative_exponent_overflow_error(
128 ParseError::NegativeExponentOverflow,
129 "Negative exponent overflow: Minimum is -32768"
130 )]
131 #[case::positive_exponent_overflow_error(
132 ParseError::PositiveExponentOverflow,
133 "Positive exponent overflow: Maximum is +32767"
134 )]
135 #[case::negative_number_error(ParseError::NegativeNumber, "Number was negative")]
136 #[case::invalid_input(
137 ParseError::InvalidInput("Unexpected".to_owned()),
138 "Invalid input: Unexpected"
139 )]
140 #[case::empty(ParseError::Empty, "Empty input")]
141 fn test_error_messages_parse_error(#[case] error: ParseError, #[case] expected: &str) {
142 assert_eq!(error.to_string(), expected);
143 }
144
145 #[rstest]
146 #[case::negative_overflow(TryFromDurationError::NegativeOverflow, ParseError::Overflow)]
147 #[case::positive_overflow(TryFromDurationError::PositiveOverflow, ParseError::Overflow)]
148 #[case::negative_number(TryFromDurationError::NegativeDuration, ParseError::NegativeNumber)]
149 fn test_from_for_parse_error(#[case] from: TryFromDurationError, #[case] expected: ParseError) {
150 assert_eq!(ParseError::from(from), expected);
151 }
152
153 #[rstest]
154 #[case::negative_number(
155 TryFromDurationError::NegativeDuration,
156 "Error converting duration: value is negative"
157 )]
158 #[case::positive_overflow(
159 TryFromDurationError::PositiveOverflow,
160 "Error converting duration: value overflows the positive value range"
161 )]
162 #[case::positive_overflow(
163 TryFromDurationError::NegativeOverflow,
164 "Error converting duration: value overflows the negative value range"
165 )]
166 fn test_error_messages_try_from_duration_error(
167 #[case] error: TryFromDurationError,
168 #[case] expected: &str,
169 ) {
170 assert_eq!(error.to_string(), expected);
171 }
172
173 #[cfg(feature = "serde")]
174 #[test]
175 fn test_serde_try_from_duration_error() {
176 let error = TryFromDurationError::NegativeDuration;
177
178 assert_tokens(
179 &error,
180 &[
181 Token::Enum {
182 name: "TryFromDurationError",
183 },
184 Token::Str("NegativeDuration"),
185 Token::Unit,
186 ],
187 );
188 }
189
190 #[cfg(feature = "serde")]
191 #[test]
192 fn test_serde_parse_error() {
193 let error = ParseError::Empty;
194
195 assert_tokens(
196 &error,
197 &[
198 Token::Enum { name: "ParseError" },
199 Token::Str("Empty"),
200 Token::Unit,
201 ],
202 );
203 }
204}