Skip to content

Commit 8359a07

Browse files
committed
Forward-compatible component range error type
1 parent 20b27cb commit 8359a07

File tree

4 files changed

+128
-102
lines changed

4 files changed

+128
-102
lines changed

src/date.rs

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use crate::no_std_prelude::*;
33
use crate::{
44
format::parse::{parse, ParseError, ParseResult, ParsedItems},
5-
DeferredFormat, Duration, PrimitiveDateTime, Time,
5+
ComponentRangeError, DeferredFormat, Duration, PrimitiveDateTime, Time,
66
Weekday::{self, Friday, Monday, Saturday, Sunday, Thursday, Tuesday, Wednesday},
77
};
88
use core::{
@@ -139,18 +139,18 @@ impl Date {
139139
///
140140
/// ```rust
141141
/// # use time::Date;
142-
/// assert!(Date::try_from_ymd(2019, 1, 1).is_some());
143-
/// assert!(Date::try_from_ymd(2019, 12, 31).is_some());
142+
/// assert!(Date::try_from_ymd(2019, 1, 1).is_ok());
143+
/// assert!(Date::try_from_ymd(2019, 12, 31).is_ok());
144144
/// ```
145145
///
146146
/// Returns `None` if the date is not valid.
147147
///
148148
/// ```rust
149149
/// # use time::Date;
150-
/// assert!(Date::try_from_ymd(2019, 2, 29).is_none()); // 2019 isn't a leap year.
150+
/// assert!(Date::try_from_ymd(2019, 2, 29).is_err()); // 2019 isn't a leap year.
151151
/// ```
152152
#[inline]
153-
pub fn try_from_ymd(year: i32, month: u8, day: u8) -> Option<Self> {
153+
pub fn try_from_ymd(year: i32, month: u8, day: u8) -> Result<Self, ComponentRangeError> {
154154
/// Cumulative days through the beginning of a month in both common and
155155
/// leap years.
156156
const DAYS_CUMULATIVE_COMMON_LEAP: [[u16; 12]; 2] = [
@@ -163,7 +163,7 @@ impl Date {
163163

164164
let ordinal = DAYS_CUMULATIVE_COMMON_LEAP[is_leap_year(year) as usize][month as usize - 1];
165165

166-
Some(Self {
166+
Ok(Self {
167167
year,
168168
ordinal: ordinal + day as u16,
169169
})
@@ -193,20 +193,20 @@ impl Date {
193193
///
194194
/// ```rust
195195
/// # use time::Date;
196-
/// assert!(Date::try_from_yo(2019, 1).is_some());
197-
/// assert!(Date::try_from_yo(2019, 365).is_some());
196+
/// assert!(Date::try_from_yo(2019, 1).is_ok());
197+
/// assert!(Date::try_from_yo(2019, 365).is_ok());
198198
/// ```
199199
///
200200
/// Returns `None` if the date is not valid.
201201
///
202202
/// ```rust
203203
/// # use time::Date;
204-
/// assert!(Date::try_from_yo(2019, 366).is_none()); // 2019 isn't a leap year.
204+
/// assert!(Date::try_from_yo(2019, 366).is_err()); // 2019 isn't a leap year.
205205
/// ```
206206
#[inline(always)]
207-
pub fn try_from_yo(year: i32, ordinal: u16) -> Option<Self> {
207+
pub fn try_from_yo(year: i32, ordinal: u16) -> Result<Self, ComponentRangeError> {
208208
ensure_value_in_range!(ordinal in 1 => days_in_year(year), given year);
209-
Some(Self { year, ordinal })
209+
Ok(Self { year, ordinal })
210210
}
211211

212212
/// Create a `Date` from the ISO year, week, and weekday.
@@ -256,33 +256,37 @@ impl Date {
256256
///
257257
/// ```rust
258258
/// # use time::{Date, Weekday::*};
259-
/// assert!(Date::try_from_iso_ywd(2019, 1, Monday).is_some());
260-
/// assert!(Date::try_from_iso_ywd(2019, 1, Tuesday).is_some());
261-
/// assert!(Date::try_from_iso_ywd(2020, 53, Friday).is_some());
259+
/// assert!(Date::try_from_iso_ywd(2019, 1, Monday).is_ok());
260+
/// assert!(Date::try_from_iso_ywd(2019, 1, Tuesday).is_ok());
261+
/// assert!(Date::try_from_iso_ywd(2020, 53, Friday).is_ok());
262262
/// ```
263263
///
264264
/// Returns `None` if the week is not valid.
265265
///
266266
/// ```rust
267267
/// # use time::{Date, Weekday::*};
268-
/// assert!(Date::try_from_iso_ywd(2019, 53, Monday).is_none()); // 2019 doesn't have 53 weeks.
268+
/// assert!(Date::try_from_iso_ywd(2019, 53, Monday).is_err()); // 2019 doesn't have 53 weeks.
269269
/// ```
270270
#[inline]
271-
pub fn try_from_iso_ywd(year: i32, week: u8, weekday: Weekday) -> Option<Self> {
271+
pub fn try_from_iso_ywd(
272+
year: i32,
273+
week: u8,
274+
weekday: Weekday,
275+
) -> Result<Self, ComponentRangeError> {
272276
ensure_value_in_range!(week in 1 => weeks_in_year(year), given year);
273277

274278
let ordinal = week as u16 * 7 + weekday.iso_weekday_number() as u16
275279
- (Self::from_yo(year, 4).weekday().iso_weekday_number() as u16 + 3);
276280

277281
if ordinal < 1 {
278-
return Some(Self::from_yo(year - 1, ordinal + days_in_year(year - 1)));
282+
return Ok(Self::from_yo(year - 1, ordinal + days_in_year(year - 1)));
279283
}
280284

281285
let days_in_cur_year = days_in_year(year);
282286
if ordinal > days_in_cur_year {
283-
Some(Self::from_yo(year + 1, ordinal - days_in_cur_year))
287+
Ok(Self::from_yo(year + 1, ordinal - days_in_cur_year))
284288
} else {
285-
Some(Self::from_yo(year, ordinal))
289+
Ok(Self::from_yo(year, ordinal))
286290
}
287291
}
288292

@@ -707,12 +711,17 @@ impl Date {
707711
///
708712
/// ```rust
709713
/// # use time::Date;
710-
/// assert!(Date::from_ymd(1970, 1, 1).try_with_hms(0, 0, 0).is_some());
711-
/// assert!(Date::from_ymd(1970, 1, 1).try_with_hms(24, 0, 0).is_none());
714+
/// assert!(Date::from_ymd(1970, 1, 1).try_with_hms(0, 0, 0).is_ok());
715+
/// assert!(Date::from_ymd(1970, 1, 1).try_with_hms(24, 0, 0).is_err());
712716
/// ```
713717
#[inline(always)]
714-
pub fn try_with_hms(self, hour: u8, minute: u8, second: u8) -> Option<PrimitiveDateTime> {
715-
Some(PrimitiveDateTime::new(
718+
pub fn try_with_hms(
719+
self,
720+
hour: u8,
721+
minute: u8,
722+
second: u8,
723+
) -> Result<PrimitiveDateTime, ComponentRangeError> {
724+
Ok(PrimitiveDateTime::new(
716725
self,
717726
Time::try_from_hms(hour, minute, second)?,
718727
))
@@ -747,10 +756,10 @@ impl Date {
747756
/// # use time::Date;
748757
/// assert!(Date::from_ymd(1970, 1, 1)
749758
/// .try_with_hms_milli(0, 0, 0, 0)
750-
/// .is_some());
759+
/// .is_ok());
751760
/// assert!(Date::from_ymd(1970, 1, 1)
752761
/// .try_with_hms_milli(24, 0, 0, 0)
753-
/// .is_none());
762+
/// .is_err());
754763
/// ```
755764
#[inline(always)]
756765
pub fn try_with_hms_milli(
@@ -759,8 +768,8 @@ impl Date {
759768
minute: u8,
760769
second: u8,
761770
millisecond: u16,
762-
) -> Option<PrimitiveDateTime> {
763-
Some(PrimitiveDateTime::new(
771+
) -> Result<PrimitiveDateTime, ComponentRangeError> {
772+
Ok(PrimitiveDateTime::new(
764773
self,
765774
Time::try_from_hms_milli(hour, minute, second, millisecond)?,
766775
))
@@ -795,10 +804,10 @@ impl Date {
795804
/// # use time::Date;
796805
/// assert!(Date::from_ymd(1970, 1, 1)
797806
/// .try_with_hms_micro(0, 0, 0, 0)
798-
/// .is_some());
807+
/// .is_ok());
799808
/// assert!(Date::from_ymd(1970, 1, 1)
800809
/// .try_with_hms_micro(24, 0, 0, 0)
801-
/// .is_none());
810+
/// .is_err());
802811
/// ```
803812
#[inline(always)]
804813
pub fn try_with_hms_micro(
@@ -807,8 +816,8 @@ impl Date {
807816
minute: u8,
808817
second: u8,
809818
microsecond: u32,
810-
) -> Option<PrimitiveDateTime> {
811-
Some(PrimitiveDateTime::new(
819+
) -> Result<PrimitiveDateTime, ComponentRangeError> {
820+
Ok(PrimitiveDateTime::new(
812821
self,
813822
Time::try_from_hms_micro(hour, minute, second, microsecond)?,
814823
))
@@ -840,10 +849,10 @@ impl Date {
840849
/// # use time::Date;
841850
/// assert!(Date::from_ymd(1970, 1, 1)
842851
/// .try_with_hms_nano(0, 0, 0, 0)
843-
/// .is_some());
852+
/// .is_ok());
844853
/// assert!(Date::from_ymd(1970, 1, 1)
845854
/// .try_with_hms_nano(24, 0, 0, 0)
846-
/// .is_none());
855+
/// .is_err());
847856
/// ```
848857
#[inline(always)]
849858
pub fn try_with_hms_nano(
@@ -852,8 +861,8 @@ impl Date {
852861
minute: u8,
853862
second: u8,
854863
nanosecond: u32,
855-
) -> Option<PrimitiveDateTime> {
856-
Some(PrimitiveDateTime::new(
864+
) -> Result<PrimitiveDateTime, ComponentRangeError> {
865+
Ok(PrimitiveDateTime::new(
857866
self,
858867
Time::try_from_hms_nano(hour, minute, second, nanosecond)?,
859868
))
@@ -2084,9 +2093,9 @@ mod test {
20842093
fn try_with_hms() {
20852094
assert_eq!(
20862095
ymd!(1970, 1, 1).try_with_hms(0, 0, 0),
2087-
Some(ymd!(1970, 1, 1).with_time(Time::from_hms(0, 0, 0))),
2096+
Ok(ymd!(1970, 1, 1).with_time(Time::from_hms(0, 0, 0))),
20882097
);
2089-
assert_eq!(ymd!(1970, 1, 1).try_with_hms(24, 0, 0), None);
2098+
assert!(ymd!(1970, 1, 1).try_with_hms(24, 0, 0).is_err());
20902099
}
20912100

20922101
#[test]
@@ -2101,9 +2110,9 @@ mod test {
21012110
fn try_with_hms_milli() {
21022111
assert_eq!(
21032112
ymd!(1970, 1, 1).try_with_hms_milli(0, 0, 0, 0),
2104-
Some(ymd!(1970, 1, 1).with_time(Time::from_hms_milli(0, 0, 0, 0))),
2113+
Ok(ymd!(1970, 1, 1).with_time(Time::from_hms_milli(0, 0, 0, 0))),
21052114
);
2106-
assert_eq!(ymd!(1970, 1, 1).try_with_hms_milli(24, 0, 0, 0), None);
2115+
assert!(ymd!(1970, 1, 1).try_with_hms_milli(24, 0, 0, 0).is_err());
21072116
}
21082117

21092118
#[test]
@@ -2118,9 +2127,9 @@ mod test {
21182127
fn try_with_hms_micro() {
21192128
assert_eq!(
21202129
ymd!(1970, 1, 1).try_with_hms_micro(0, 0, 0, 0),
2121-
Some(ymd!(1970, 1, 1).with_time(Time::from_hms_micro(0, 0, 0, 0))),
2130+
Ok(ymd!(1970, 1, 1).with_time(Time::from_hms_micro(0, 0, 0, 0))),
21222131
);
2123-
assert_eq!(ymd!(1970, 1, 1).try_with_hms_micro(24, 0, 0, 0), None);
2132+
assert!(ymd!(1970, 1, 1).try_with_hms_micro(24, 0, 0, 0).is_err());
21242133
}
21252134

21262135
#[test]
@@ -2135,9 +2144,9 @@ mod test {
21352144
fn try_with_hms_nano() {
21362145
assert_eq!(
21372146
ymd!(1970, 1, 1).try_with_hms_nano(0, 0, 0, 0),
2138-
Some(ymd!(1970, 1, 1).with_time(Time::from_hms_nano(0, 0, 0, 0))),
2147+
Ok(ymd!(1970, 1, 1).with_time(Time::from_hms_nano(0, 0, 0, 0))),
21392148
);
2140-
assert_eq!(ymd!(1970, 1, 1).try_with_hms_nano(24, 0, 0, 0), None);
2149+
assert!(ymd!(1970, 1, 1).try_with_hms_nano(24, 0, 0, 0).is_err());
21412150
}
21422151

21432152
#[test]

src/duration.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#[cfg(feature = "std")]
22
use crate::Instant;
33
use crate::{
4-
NumberExt, ConversionRangeError,
4+
ConversionRangeError, NumberExt,
55
Sign::{self, Negative, Positive, Zero},
66
};
77
use core::{

src/lib.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -210,19 +210,19 @@ macro_rules! assert_value_in_range {
210210
macro_rules! ensure_value_in_range {
211211
($value:ident in $start:expr => $end:expr) => {
212212
if !($start..=$end).contains(&$value) {
213-
return None;
213+
return Err(ComponentRangeError);
214214
}
215215
};
216216

217217
($value:ident in $start:expr => exclusive $end:expr) => {
218218
if !($start..$end).contains(&$value) {
219-
return None;
219+
return Err(ComponentRangeError);
220220
}
221221
};
222222

223223
($value:ident in $start:expr => $end:expr,given $($conditional:ident),+ $(,)?) => {
224224
if !($start..=$end).contains(&$value) {
225-
return None;
225+
return Err(ComponentRangeError);
226226
};
227227
};
228228
}
@@ -329,21 +329,23 @@ impl fmt::Display for ConversionRangeError {
329329
#[cfg(feature = "std")]
330330
impl std::error::Error for ConversionRangeError {}
331331

332-
#[cfg(test)]
333-
mod test {
334-
use super::*;
335-
#[cfg(not(feature = "std"))]
336-
use crate::no_std_prelude::*;
332+
/// An error type indicating that a component provided to a method was out of
333+
/// range, causing a failure.
334+
#[allow(missing_copy_implementations)] // Non-copy fields may be added.
335+
#[non_exhaustive]
336+
#[derive(Debug, Clone, PartialEq, Eq)]
337+
pub struct ComponentRangeError;
337338

338-
#[test]
339-
fn out_of_range_error_format() {
340-
assert_eq!(
341-
ComponentRangeError.to_string(),
342-
"Source value is out of range for the target type",
343-
);
339+
impl fmt::Display for ComponentRangeError {
340+
#[inline(always)]
341+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
342+
f.write_str("A component's value is out of range")
344343
}
345344
}
346345

346+
#[cfg(feature = "std")]
347+
impl std::error::Error for ComponentRangeError {}
348+
347349
// For some back-compatibility, we're also implementing some deprecated types
348350
// and methods. They will be removed completely in 0.3.
349351

0 commit comments

Comments
 (0)