Skip to content

Commit

Permalink
Eliminate use of ensure_value_in_range!
Browse files Browse the repository at this point in the history
  • Loading branch information
jhpratt committed Sep 9, 2023
1 parent b60a2b2 commit 5aa84bd
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 58 deletions.
77 changes: 62 additions & 15 deletions time/src/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use core::time::Duration as StdDuration;
#[cfg(feature = "formatting")]
use std::io;

use deranged::RangedI32;

use crate::convert::*;
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
Expand All @@ -14,6 +16,8 @@ use crate::parsing::Parsable;
use crate::util::{days_in_year, days_in_year_month, is_leap_year, weeks_in_year};
use crate::{error, Duration, Month, PrimitiveDateTime, Time, Weekday};

type Year = RangedI32<MIN_YEAR, MAX_YEAR>;

/// The minimum valid year.
pub(crate) const MIN_YEAR: i32 = if cfg!(feature = "large-dates") {
-999_999
Expand Down Expand Up @@ -91,8 +95,20 @@ impl Date {
[0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335],
];

ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
ensure_value_in_range!(day conditionally in 1 => days_in_year_month(year, month));
ensure_ranged!(Year: year);
match day {
1..=28 => {}
29..=31 if day <= days_in_year_month(year, month) => {}
_ => {
return Err(crate::error::ComponentRange {
name: "day",
minimum: 1,
maximum: days_in_year_month(year, month) as _,
value: day as _,
conditional_range: true,
});
}
}

Ok(Self::__from_ordinal_date_unchecked(
year,
Expand All @@ -114,8 +130,21 @@ impl Date {
/// assert!(Date::from_ordinal_date(2019, 366).is_err()); // 2019 isn't a leap year.
/// ```
pub const fn from_ordinal_date(year: i32, ordinal: u16) -> Result<Self, error::ComponentRange> {
ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
ensure_value_in_range!(ordinal conditionally in 1 => days_in_year(year));
ensure_ranged!(Year: year);
match ordinal {
1..=365 => {}
366 if is_leap_year(year) => {}
_ => {
return Err(crate::error::ComponentRange {
name: "ordinal",
minimum: 1,
maximum: days_in_year(year) as _,
value: ordinal as _,
conditional_range: true,
});
}
}

Ok(Self::__from_ordinal_date_unchecked(year, ordinal))
}

Expand All @@ -137,8 +166,20 @@ impl Date {
week: u8,
weekday: Weekday,
) -> Result<Self, error::ComponentRange> {
ensure_value_in_range!(year in MIN_YEAR => MAX_YEAR);
ensure_value_in_range!(week conditionally in 1 => weeks_in_year(year));
ensure_ranged!(Year: year);
match week {
1..=52 => {}
53 if week <= weeks_in_year(year) => {}
_ => {
return Err(crate::error::ComponentRange {
name: "week",
minimum: 1,
maximum: weeks_in_year(year) as _,
value: week as _,
conditional_range: true,
});
}
}

let adj_year = year - 1;
let raw = 365 * adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100)
Expand Down Expand Up @@ -181,9 +222,8 @@ impl Date {
/// ```
#[doc(alias = "from_julian_date")]
pub const fn from_julian_day(julian_day: i32) -> Result<Self, error::ComponentRange> {
ensure_value_in_range!(
julian_day in Self::MIN.to_julian_day() => Self::MAX.to_julian_day()
);
type JulianDay = RangedI32<{ Date::MIN.to_julian_day() }, { Date::MAX.to_julian_day() }>;
ensure_ranged!(JulianDay: julian_day);
Ok(Self::from_julian_day_unchecked(julian_day))
}

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

let ordinal = self.ordinal();

Expand Down Expand Up @@ -961,11 +1001,18 @@ impl Date {
/// ```
#[must_use = "This method does not mutate the original `Date`."]
pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
// Days 1-28 are present in every month, so we can skip checking.
if day == 0 || day >= 29 {
ensure_value_in_range!(
day conditionally in 1 => days_in_year_month(self.year(), self.month())
);
match day {
1..=28 => {}
29..=31 if day <= days_in_year_month(self.year(), self.month()) => {}
_ => {
return Err(crate::error::ComponentRange {
name: "day",
minimum: 1,
maximum: days_in_year_month(self.year(), self.month()) as _,
value: day as _,
conditional_range: true,
});
}
}

Ok(Self::__from_ordinal_date_unchecked(
Expand Down
13 changes: 7 additions & 6 deletions time/src/date_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use std::io;
#[cfg(feature = "std")]
use std::time::SystemTime;

use deranged::RangedI64;

use crate::convert::*;
use crate::date::{MAX_YEAR, MIN_YEAR};
#[cfg(feature = "formatting")]
Expand Down Expand Up @@ -248,12 +250,11 @@ impl<O: MaybeOffset> DateTime<O> {
where
O: HasLogicalOffset,
{
#[allow(clippy::missing_docs_in_private_items)]
const MIN_TIMESTAMP: i64 = Date::MIN.midnight().assume_utc().unix_timestamp();
#[allow(clippy::missing_docs_in_private_items)]
const MAX_TIMESTAMP: i64 = Date::MAX.with_time(Time::MAX).assume_utc().unix_timestamp();

ensure_value_in_range!(timestamp in MIN_TIMESTAMP => MAX_TIMESTAMP);
type Timestamp = RangedI64<
{ Date::MIN.midnight().assume_utc().unix_timestamp() },
{ Date::MAX.with_time(Time::MAX).assume_utc().unix_timestamp() },
>;
ensure_ranged!(Timestamp: timestamp);

// Use the unchecked method here, as the input validity has already been verified.
let date = Date::from_julian_day_unchecked(
Expand Down
35 changes: 2 additions & 33 deletions time/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,45 +179,13 @@ macro_rules! cascade {
};
}

/// Returns `Err(error::ComponentRange)` if the value is not in range.
macro_rules! ensure_value_in_range {
($value:ident in $start:expr => $end:expr) => {{
let _start = $start;
let _end = $end;
#[allow(trivial_numeric_casts, unused_comparisons)]
if $value < _start || $value > _end {
return Err(crate::error::ComponentRange {
name: stringify!($value),
minimum: _start as _,
maximum: _end as _,
value: $value as _,
conditional_range: false,
});
}
}};

($value:ident conditionally in $start:expr => $end:expr) => {{
let _start = $start;
let _end = $end;
#[allow(trivial_numeric_casts, unused_comparisons)]
if $value < _start || $value > _end {
return Err(crate::error::ComponentRange {
name: stringify!($value),
minimum: _start as _,
maximum: _end as _,
value: $value as _,
conditional_range: true,
});
}
}};
}

/// Constructs a ranged integer, returning a `ComponentRange` error if the value is out of range.
macro_rules! ensure_ranged {
($type:ident : $value:ident) => {
match $type::new($value) {
Some(val) => val,
None => {
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: stringify!($value),
minimum: $type::MIN.get() as _,
Expand All @@ -234,6 +202,7 @@ macro_rules! ensure_ranged {
Some(val) => match $type::new(val) {
Some(val) => val,
None => {
#[allow(trivial_numeric_casts)]
return Err(crate::error::ComponentRange {
name: stringify!($value),
minimum: $type::MIN.get() as i64 / $factor as i64,
Expand Down
18 changes: 14 additions & 4 deletions time/src/utc_offset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::ops::Neg;
#[cfg(feature = "formatting")]
use std::io;

use deranged::RangedI8;
use deranged::{RangedI32, RangedI8};

use crate::convert::*;
use crate::error;
Expand Down Expand Up @@ -166,9 +166,19 @@ impl UtcOffset {
/// # Ok::<_, time::Error>(())
/// ```
pub const fn from_whole_seconds(seconds: i32) -> Result<Self, error::ComponentRange> {
ensure_value_in_range!(
seconds in -24 * Second.per(Hour) as i32 - 1 => 24 * Second.per(Hour) as i32 - 1
);
type WholeSeconds = RangedI32<
{
Hours::MIN.get() as i32 * Second.per(Hour) as i32
+ Minutes::MIN.get() as i32 * Second.per(Minute) as i32
+ Seconds::MIN.get() as i32
},
{
Hours::MAX.get() as i32 * Second.per(Hour) as i32
+ Minutes::MAX.get() as i32 * Second.per(Minute) as i32
+ Seconds::MAX.get() as i32
},
>;
ensure_ranged!(WholeSeconds: seconds);

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

0 comments on commit 5aa84bd

Please sign in to comment.