Skip to content

Commit 5aa84bd

Browse files
committed
Eliminate use of ensure_value_in_range!
1 parent b60a2b2 commit 5aa84bd

File tree

4 files changed

+85
-58
lines changed

4 files changed

+85
-58
lines changed

time/src/date.rs

+62-15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use core::time::Duration as StdDuration;
66
#[cfg(feature = "formatting")]
77
use std::io;
88

9+
use deranged::RangedI32;
10+
911
use crate::convert::*;
1012
#[cfg(feature = "formatting")]
1113
use crate::formatting::Formattable;
@@ -14,6 +16,8 @@ use crate::parsing::Parsable;
1416
use crate::util::{days_in_year, days_in_year_month, is_leap_year, weeks_in_year};
1517
use crate::{error, Duration, Month, PrimitiveDateTime, Time, Weekday};
1618

19+
type Year = RangedI32<MIN_YEAR, MAX_YEAR>;
20+
1721
/// The minimum valid year.
1822
pub(crate) const MIN_YEAR: i32 = if cfg!(feature = "large-dates") {
1923
-999_999
@@ -91,8 +95,20 @@ impl Date {
9195
[0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
9296
];
9397

94-
ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
95-
ensure_value_in_range!(day conditionally in 1 => days_in_year_month(year, month));
98+
ensure_ranged!(Year: year);
99+
match day {
100+
1..=28 => {}
101+
29..=31 if day <= days_in_year_month(year, month) => {}
102+
_ => {
103+
return Err(crate::error::ComponentRange {
104+
name: "day",
105+
minimum: 1,
106+
maximum: days_in_year_month(year, month) as _,
107+
value: day as _,
108+
conditional_range: true,
109+
});
110+
}
111+
}
96112

97113
Ok(Self::__from_ordinal_date_unchecked(
98114
year,
@@ -114,8 +130,21 @@ impl Date {
114130
/// assert!(Date::from_ordinal_date(2019, 366).is_err()); // 2019 isn't a leap year.
115131
/// ```
116132
pub const fn from_ordinal_date(year: i32, ordinal: u16) -> Result<Self, error::ComponentRange> {
117-
ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
118-
ensure_value_in_range!(ordinal conditionally in 1 => days_in_year(year));
133+
ensure_ranged!(Year: year);
134+
match ordinal {
135+
1..=365 => {}
136+
366 if is_leap_year(year) => {}
137+
_ => {
138+
return Err(crate::error::ComponentRange {
139+
name: "ordinal",
140+
minimum: 1,
141+
maximum: days_in_year(year) as _,
142+
value: ordinal as _,
143+
conditional_range: true,
144+
});
145+
}
146+
}
147+
119148
Ok(Self::__from_ordinal_date_unchecked(year, ordinal))
120149
}
121150

@@ -137,8 +166,20 @@ impl Date {
137166
week: u8,
138167
weekday: Weekday,
139168
) -> Result<Self, error::ComponentRange> {
140-
ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
141-
ensure_value_in_range!(week conditionally in 1 => weeks_in_year(year));
169+
ensure_ranged!(Year: year);
170+
match week {
171+
1..=52 => {}
172+
53 if week <= weeks_in_year(year) => {}
173+
_ => {
174+
return Err(crate::error::ComponentRange {
175+
name: "week",
176+
minimum: 1,
177+
maximum: weeks_in_year(year) as _,
178+
value: week as _,
179+
conditional_range: true,
180+
});
181+
}
182+
}
142183

143184
let adj_year = year - 1;
144185
let raw = 365 * adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100)
@@ -181,9 +222,8 @@ impl Date {
181222
/// ```
182223
#[doc(alias = "from_julian_date")]
183224
pub const fn from_julian_day(julian_day: i32) -> Result<Self, error::ComponentRange> {
184-
ensure_value_in_range!(
185-
julian_day in Self::MIN.to_julian_day() => Self::MAX.to_julian_day()
186-
);
225+
type JulianDay = RangedI32<{ Date::MIN.to_julian_day() }, { Date::MAX.to_julian_day() }>;
226+
ensure_ranged!(JulianDay: julian_day);
187227
Ok(Self::from_julian_day_unchecked(julian_day))
188228
}
189229

@@ -899,7 +939,7 @@ impl Date {
899939
/// ```
900940
#[must_use = "This method does not mutate the original `Date`."]
901941
pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
902-
ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
942+
ensure_ranged!(Year: year);
903943

904944
let ordinal = self.ordinal();
905945

@@ -961,11 +1001,18 @@ impl Date {
9611001
/// ```
9621002
#[must_use = "This method does not mutate the original `Date`."]
9631003
pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
964-
// Days 1-28 are present in every month, so we can skip checking.
965-
if day == 0 || day >= 29 {
966-
ensure_value_in_range!(
967-
day conditionally in 1 => days_in_year_month(self.year(), self.month())
968-
);
1004+
match day {
1005+
1..=28 => {}
1006+
29..=31 if day <= days_in_year_month(self.year(), self.month()) => {}
1007+
_ => {
1008+
return Err(crate::error::ComponentRange {
1009+
name: "day",
1010+
minimum: 1,
1011+
maximum: days_in_year_month(self.year(), self.month()) as _,
1012+
value: day as _,
1013+
conditional_range: true,
1014+
});
1015+
}
9691016
}
9701017

9711018
Ok(Self::__from_ordinal_date_unchecked(

time/src/date_time.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use std::io;
1616
#[cfg(feature = "std")]
1717
use std::time::SystemTime;
1818

19+
use deranged::RangedI64;
20+
1921
use crate::convert::*;
2022
use crate::date::{MAX_YEAR, MIN_YEAR};
2123
#[cfg(feature = "formatting")]
@@ -248,12 +250,11 @@ impl<O: MaybeOffset> DateTime<O> {
248250
where
249251
O: HasLogicalOffset,
250252
{
251-
#[allow(clippy::missing_docs_in_private_items)]
252-
const MIN_TIMESTAMP: i64 = Date::MIN.midnight().assume_utc().unix_timestamp();
253-
#[allow(clippy::missing_docs_in_private_items)]
254-
const MAX_TIMESTAMP: i64 = Date::MAX.with_time(Time::MAX).assume_utc().unix_timestamp();
255-
256-
ensure_value_in_range!(timestamp in MIN_TIMESTAMP => MAX_TIMESTAMP);
253+
type Timestamp = RangedI64<
254+
{ Date::MIN.midnight().assume_utc().unix_timestamp() },
255+
{ Date::MAX.with_time(Time::MAX).assume_utc().unix_timestamp() },
256+
>;
257+
ensure_ranged!(Timestamp: timestamp);
257258

258259
// Use the unchecked method here, as the input validity has already been verified.
259260
let date = Date::from_julian_day_unchecked(

time/src/lib.rs

+2-33
Original file line numberDiff line numberDiff line change
@@ -179,45 +179,13 @@ macro_rules! cascade {
179179
};
180180
}
181181

182-
/// Returns `Err(error::ComponentRange)` if the value is not in range.
183-
macro_rules! ensure_value_in_range {
184-
($value:ident in $start:expr => $end:expr) => {{
185-
let _start = $start;
186-
let _end = $end;
187-
#[allow(trivial_numeric_casts, unused_comparisons)]
188-
if $value < _start || $value > _end {
189-
return Err(crate::error::ComponentRange {
190-
name: stringify!($value),
191-
minimum: _start as _,
192-
maximum: _end as _,
193-
value: $value as _,
194-
conditional_range: false,
195-
});
196-
}
197-
}};
198-
199-
($value:ident conditionally in $start:expr => $end:expr) => {{
200-
let _start = $start;
201-
let _end = $end;
202-
#[allow(trivial_numeric_casts, unused_comparisons)]
203-
if $value < _start || $value > _end {
204-
return Err(crate::error::ComponentRange {
205-
name: stringify!($value),
206-
minimum: _start as _,
207-
maximum: _end as _,
208-
value: $value as _,
209-
conditional_range: true,
210-
});
211-
}
212-
}};
213-
}
214-
215182
/// Constructs a ranged integer, returning a `ComponentRange` error if the value is out of range.
216183
macro_rules! ensure_ranged {
217184
($type:ident : $value:ident) => {
218185
match $type::new($value) {
219186
Some(val) => val,
220187
None => {
188+
#[allow(trivial_numeric_casts)]
221189
return Err(crate::error::ComponentRange {
222190
name: stringify!($value),
223191
minimum: $type::MIN.get() as _,
@@ -234,6 +202,7 @@ macro_rules! ensure_ranged {
234202
Some(val) => match $type::new(val) {
235203
Some(val) => val,
236204
None => {
205+
#[allow(trivial_numeric_casts)]
237206
return Err(crate::error::ComponentRange {
238207
name: stringify!($value),
239208
minimum: $type::MIN.get() as i64 / $factor as i64,

time/src/utc_offset.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use core::ops::Neg;
55
#[cfg(feature = "formatting")]
66
use std::io;
77

8-
use deranged::RangedI8;
8+
use deranged::{RangedI32, RangedI8};
99

1010
use crate::convert::*;
1111
use crate::error;
@@ -166,9 +166,19 @@ impl UtcOffset {
166166
/// # Ok::<_, time::Error>(())
167167
/// ```
168168
pub const fn from_whole_seconds(seconds: i32) -> Result<Self, error::ComponentRange> {
169-
ensure_value_in_range!(
170-
seconds in -24 * Second.per(Hour) as i32 - 1 => 24 * Second.per(Hour) as i32 - 1
171-
);
169+
type WholeSeconds = RangedI32<
170+
{
171+
Hours::MIN.get() as i32 * Second.per(Hour) as i32
172+
+ Minutes::MIN.get() as i32 * Second.per(Minute) as i32
173+
+ Seconds::MIN.get() as i32
174+
},
175+
{
176+
Hours::MAX.get() as i32 * Second.per(Hour) as i32
177+
+ Minutes::MAX.get() as i32 * Second.per(Minute) as i32
178+
+ Seconds::MAX.get() as i32
179+
},
180+
>;
181+
ensure_ranged!(WholeSeconds: seconds);
172182

173183
// Safety: The value was checked to be in range.
174184
Ok(unsafe {

0 commit comments

Comments
 (0)