Skip to content
This repository was archived by the owner on Aug 19, 2025. It is now read-only.

Commit 75a4110

Browse files
committed
dxr: simplify datetime parser logic
1 parent 29097ce commit 75a4110

File tree

4 files changed

+40
-59
lines changed

4 files changed

+40
-59
lines changed

dxr/src/error.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use thiserror::Error;
55
use crate::fault::Fault;
66

77
#[derive(Debug, Error, PartialEq)]
8+
#[non_exhaustive]
89
/// Error type representing conversion errors between XML-RPC values and Rust values.
910
pub enum DxrError {
1011
/// Error variant for XML parser errors.
@@ -13,6 +14,12 @@ pub enum DxrError {
1314
/// description of the parsing error
1415
error: String,
1516
},
17+
/// Error variant for invalid dateTime.iso8601 values.
18+
#[error("Invalid format for dateTime.iso8601 value: \n{}", .error)]
19+
InvalidDateTime {
20+
/// description of the parsing error
21+
error: String,
22+
},
1623
/// Error variant for a missing struct field.
1724
#[error("Struct '{}' missing field: {}", .name, .field)]
1825
MissingField {
@@ -61,6 +68,27 @@ impl DxrError {
6168
}
6269
}
6370

71+
/// Construct an [`DxrError`] for invalid datetime values.
72+
pub fn invalid_datetime(error: String) -> DxrError {
73+
DxrError::InvalidDateTime { error }
74+
}
75+
76+
/// Check if a given [`DxrError`] was raised for an invalid datetime value.
77+
pub fn is_invalid_datetime(&self) -> bool {
78+
matches!(self, DxrError::InvalidDateTime { .. })
79+
}
80+
81+
/// Check for [`DxrError::InvalidDateTime`] and return the inner error in case of a match.
82+
///
83+
/// The returned string describes the parsing failure.
84+
pub fn as_invalid_datetime(&self) -> Option<&str> {
85+
if let DxrError::InvalidDateTime { error } = self {
86+
Some(error)
87+
} else {
88+
None
89+
}
90+
}
91+
6492
/// Construct a [`DxrError`] for a missing struct field.
6593
pub fn missing_field(name: &'static str, field: &'static str) -> DxrError {
6694
DxrError::MissingField {
@@ -133,11 +161,6 @@ impl DxrError {
133161

134162
impl From<DxrError> for Fault {
135163
fn from(error: DxrError) -> Self {
136-
match error {
137-
DxrError::InvalidData { .. } => Fault::new(400, error.to_string()),
138-
DxrError::MissingField { .. } => Fault::new(400, error.to_string()),
139-
DxrError::ParameterMismatch { .. } => Fault::new(400, error.to_string()),
140-
DxrError::WrongType { .. } => Fault::new(400, error.to_string()),
141-
}
164+
Fault::new(400, error.to_string())
142165
}
143166
}

dxr/src/tests/xml/values.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,10 @@ fn from_datetime() {
182182
#[test]
183183
fn from_datetime_fail() {
184184
let value = "<value><dateTime.iso8601>202520252025</dateTime.iso8601></value>";
185-
assert!(from_str::<Value>(value)
185+
assert!(dbg!(from_str::<Value>(value))
186186
.unwrap_err()
187187
.to_string()
188-
.contains("Invalid dateTime.iso8601 value"));
188+
.contains("Invalid format for dateTime.iso8601 value"));
189189
}
190190

191191
#[test]

dxr/src/values.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
mod datetime;
22
pub use datetime::DateTime;
3-
pub use datetime::DateTimeParseError;
43

54
mod ser_de;
65

dxr/src/values/datetime.rs

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use winnow::error::{ContextError, StrContext, StrContextValue};
77
use winnow::token::take;
88
use winnow::Parser;
99

10+
use crate::error::DxrError;
11+
1012
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1113
pub struct DateTime {
1214
year: u16,
@@ -55,31 +57,15 @@ impl Display for DateTime {
5557
}
5658

5759
impl FromStr for DateTime {
58-
type Err = DateTimeParseError;
60+
type Err = DxrError;
5961

6062
fn from_str(s: &str) -> Result<Self, Self::Err> {
6163
DateTimeParser
6264
.parse(s)
63-
.map_err(|e| DateTimeParseError::InvalidFormat(e.to_string()))
65+
.map_err(|e| DxrError::invalid_datetime(e.to_string()))
6466
}
6567
}
6668

67-
#[derive(Clone, Debug, thiserror::Error)]
68-
pub enum DateTimeParseError {
69-
#[error("Invalid format for dateTime.iso8601 value: {}", .0)]
70-
InvalidFormat(String),
71-
#[error("Invalid dateTime.iso8601 value: Month out of range ({})", .0)]
72-
InvalidMonth(u8),
73-
#[error("Invalid dateTime.iso8601 value: Day out of range ({})", .0)]
74-
InvalidDay(u8),
75-
#[error("Invalid dateTime.iso8601 value: Hour out of range ({})", .0)]
76-
InvalidHour(u8),
77-
#[error("Invalid dateTime.iso8601 value: Minutes out of range ({})", .0)]
78-
InvalidMinutes(u8),
79-
#[error("Invalid dateTime.iso8601 value: Seconds out of range ({})", .0)]
80-
InvalidSeconds(u8),
81-
}
82-
8369
struct DateTimeParser;
8470

8571
impl Parser<&str, DateTime, ContextError> for DateTimeParser {
@@ -127,10 +113,7 @@ impl Parser<&str, u8, ContextError> for MonthParser {
127113
fn parse_next(&mut self, input: &mut &str) -> winnow::Result<u8> {
128114
take(2usize)
129115
.parse_to()
130-
.try_map(|month| match month {
131-
1..=12 => Ok(month),
132-
_ => Err(DateTimeParseError::InvalidMonth(month)),
133-
})
116+
.verify(|m| *m > 0 && *m <= 12)
134117
.context(StrContext::Label("month"))
135118
.parse_next(input)
136119
}
@@ -144,13 +127,7 @@ impl Parser<&str, u8, ContextError> for DayParser {
144127
fn parse_next(&mut self, input: &mut &str) -> winnow::Result<u8> {
145128
take(2usize)
146129
.parse_to()
147-
.try_map(|day| {
148-
if day == 0 || day > self.max {
149-
Err(DateTimeParseError::InvalidDay(day))
150-
} else {
151-
Ok(day)
152-
}
153-
})
130+
.verify(|d| *d > 0 && *d <= self.max)
154131
.context(StrContext::Label("day"))
155132
.parse_next(input)
156133
}
@@ -162,13 +139,7 @@ impl Parser<&str, u8, ContextError> for HourParser {
162139
fn parse_next(&mut self, input: &mut &str) -> winnow::Result<u8> {
163140
take(2usize)
164141
.parse_to()
165-
.try_map(|hour| {
166-
if hour > 24 {
167-
Err(DateTimeParseError::InvalidHour(hour))
168-
} else {
169-
Ok(hour)
170-
}
171-
})
142+
.verify(|h| *h < 24)
172143
.context(StrContext::Label("hour"))
173144
.parse_next(input)
174145
}
@@ -180,13 +151,7 @@ impl Parser<&str, u8, ContextError> for MinuteParser {
180151
fn parse_next(&mut self, input: &mut &str) -> winnow::Result<u8> {
181152
take(2usize)
182153
.parse_to()
183-
.try_map(|minute| {
184-
if minute > 59 {
185-
Err(DateTimeParseError::InvalidMinutes(minute))
186-
} else {
187-
Ok(minute)
188-
}
189-
})
154+
.verify(|m| *m < 60)
190155
.context(StrContext::Label("minute"))
191156
.parse_next(input)
192157
}
@@ -198,13 +163,7 @@ impl Parser<&str, u8, ContextError> for SecondParser {
198163
fn parse_next(&mut self, input: &mut &str) -> winnow::Result<u8> {
199164
take(2usize)
200165
.parse_to()
201-
.try_map(|second| {
202-
if second > 59 {
203-
Err(DateTimeParseError::InvalidSeconds(second))
204-
} else {
205-
Ok(second)
206-
}
207-
})
166+
.verify(|s| *s < 60)
208167
.context(StrContext::Label("second"))
209168
.parse_next(input)
210169
}

0 commit comments

Comments
 (0)