From decdb5e6301c75f77239343e2ee5c3dfb3ff496f Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Sun, 21 Dec 2025 09:09:15 -0500 Subject: [PATCH] error: add `Error::is_range` predicate I'm somewhat concerned that this doesn't cover all cases, but I think this should be a good start. --- src/civil/date.rs | 2 +- src/error/civil.rs | 2 -- src/error/mod.rs | 24 ++++++++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/civil/date.rs b/src/civil/date.rs index 5d53c6c..e56f66f 100644 --- a/src/civil/date.rs +++ b/src/civil/date.rs @@ -1059,7 +1059,7 @@ impl Date { let nth = t::SpanWeeks::try_new("nth weekday", nth)?; if nth == C(0) { - Err(Error::from(E::NthWeekdayNonZero)) + Err(Error::slim_range("nth weekday")) } else if nth > C(0) { let nth = nth.max(C(1)); let weekday_diff = weekday.since_ranged(self.weekday().next()); diff --git a/src/error/civil.rs b/src/error/civil.rs index 4f548b8..40fce64 100644 --- a/src/error/civil.rs +++ b/src/error/civil.rs @@ -13,7 +13,6 @@ pub(crate) enum Error { InvalidISOWeekNumber, OverflowDaysDuration, OverflowTimeNanoseconds, - NthWeekdayNonZero, RoundMustUseDaysOrBigger { unit: Unit }, RoundMustUseHoursOrSmaller { unit: Unit }, } @@ -68,7 +67,6 @@ impl core::fmt::Display for Error { OverflowTimeNanoseconds => { f.write_str("adding duration to time overflowed") } - NthWeekdayNonZero => f.write_str("nth weekday cannot be `0`"), RoundMustUseDaysOrBigger { unit } => write!( f, "rounding the span between two dates must use days \ diff --git a/src/error/mod.rs b/src/error/mod.rs index 8cdc895..14ae0c1 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -93,6 +93,23 @@ impl Error { pub fn from_args<'a>(message: core::fmt::Arguments<'a>) -> Error { Error::from(ErrorKind::Adhoc(AdhocError::from_args(message))) } + + /// Returns true when this error originated as a result of a value being + /// out of Jiff's supported range. + /// + /// # Example + /// + /// ``` + /// use jiff::civil::Date; + /// + /// assert!(Date::new(2025, 2, 29).unwrap_err().is_range()); + /// assert!("2025-02-29".parse::().unwrap_err().is_range()); + /// assert!(Date::strptime("%Y-%m-%d", "2025-02-29").unwrap_err().is_range()); + /// ``` + pub fn is_range(&self) -> bool { + use self::ErrorKind::*; + matches!(*self.root().kind(), Range(_) | SlimRange(_) | ITimeRange(_)) + } } impl Error { @@ -218,6 +235,13 @@ impl Error { } } + /// Returns the root error in this chain. + fn root(&self) -> &Error { + // OK because `Error::chain` is guaranteed to return a non-empty + // iterator. + self.chain().last().unwrap() + } + /// Returns a chain of error values. /// /// This starts with the most recent error added to the chain. That is,