Skip to content

Commit efe4616

Browse files
committed
rangeint: switch / and % operators to match std
When I first devised the rangeint abstraction, I somewhat unwisely made its `/` and `%` operators use eucilidean division instead of matching what `std` does (which always rounds the result toward zero). I did this because I thought it was going to be overwhelmingly common in a datetime library. But it ended up not being that common, and it's probably better to require explicitness. Anyway, I'm considering ripping out the ranged integer abstraction inside of Jiff, and this is probably the first step toward making that not-totally-insane.
1 parent 6508ba1 commit efe4616

File tree

5 files changed

+41
-18
lines changed

5 files changed

+41
-18
lines changed

src/civil/date.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3654,8 +3654,8 @@ fn month_add_overflowing(
36543654
) -> (t::Month, t::SpanYears) {
36553655
let month = t::SpanMonths::rfrom(month);
36563656
let total = month - C(1) + span;
3657-
let years = total / C(12);
3658-
let month = (total % C(12)) + C(1);
3657+
let years = total.div_floor(C(12));
3658+
let month = total.rem_floor(C(12)) + C(1);
36593659
(month.rinto(), years.rinto())
36603660
}
36613661

@@ -3774,6 +3774,23 @@ mod tests {
37743774
}
37753775
}
37763776
}
3777+
3778+
let year_range = -9999..=-9500;
3779+
for year in year_range {
3780+
let year = Year::new(year).unwrap();
3781+
for month in [1, 2, 4] {
3782+
let month = Month::new(month).unwrap();
3783+
for day in 20..=days_in_month(year, month).get() {
3784+
let date = date(year.get(), month.get(), day);
3785+
let wd = date.iso_week_date();
3786+
let got = wd.date();
3787+
assert_eq!(
3788+
date, got,
3789+
"for date {date:?}, and ISO week date {wd:?}"
3790+
);
3791+
}
3792+
}
3793+
}
37773794
}
37783795

37793796
#[test]

src/civil/time.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -749,15 +749,16 @@ impl Time {
749749
.wrapping_mul(t::NANOS_PER_MICRO),
750750
);
751751
sum = sum.wrapping_add(span.get_nanoseconds_ranged().without_bounds());
752-
let civil_day_nanosecond = sum % t::NANOS_PER_CIVIL_DAY;
752+
let civil_day_nanosecond = sum.rem_floor(t::NANOS_PER_CIVIL_DAY);
753753
Time::from_nanosecond(civil_day_nanosecond.rinto())
754754
}
755755

756756
#[inline]
757757
fn wrapping_add_signed_duration(self, duration: SignedDuration) -> Time {
758758
let start = t::NoUnits128::rfrom(self.to_nanosecond());
759759
let duration = t::NoUnits128::new_unchecked(duration.as_nanos());
760-
let end = start.wrapping_add(duration) % t::NANOS_PER_CIVIL_DAY;
760+
let end =
761+
start.wrapping_add(duration).rem_floor(t::NANOS_PER_CIVIL_DAY);
761762
Time::from_nanosecond(end.rinto())
762763
}
763764

@@ -825,7 +826,8 @@ impl Time {
825826
// OK because 96-bit unsigned integer can't overflow i128.
826827
let duration = i128::try_from(duration.as_nanos()).unwrap();
827828
let duration = t::NoUnits128::new_unchecked(duration);
828-
let end = start.wrapping_sub(duration) % t::NANOS_PER_CIVIL_DAY;
829+
let end =
830+
start.wrapping_sub(duration).rem_floor(t::NANOS_PER_CIVIL_DAY);
829831
Time::from_nanosecond(end.rinto())
830832
}
831833

src/civil/weekday.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ impl Weekday {
174174
/// ```
175175
/// use jiff::civil::Weekday;
176176
///
177+
/// let weekday = Weekday::from_sunday_zero_offset(0)?;
178+
/// assert_eq!(weekday, Weekday::Sunday);
177179
/// let weekday = Weekday::from_sunday_zero_offset(4)?;
178180
/// assert_eq!(weekday, Weekday::Thursday);
179181
///
@@ -413,7 +415,7 @@ impl Weekday {
413415
let start = t::NoUnits::rfrom(self.to_monday_zero_offset_ranged());
414416
// OK because all i64 values fit in a NoUnits.
415417
let rhs = t::NoUnits::new(days.into()).unwrap();
416-
let end = start.wrapping_add(rhs) % C(7);
418+
let end = start.wrapping_add(rhs).rem_floor(C(7));
417419
Weekday::from_monday_zero_offset_ranged(end)
418420
}
419421

@@ -551,7 +553,7 @@ impl Weekday {
551553
pub(crate) fn from_sunday_zero_offset_ranged(
552554
offset: impl RInto<t::WeekdayZero>,
553555
) -> Weekday {
554-
let offset_sunday = (offset.rinto() - C(1)) % C(7);
556+
let offset_sunday = (offset.rinto() - C(1)).rem_floor(C(7));
555557
Weekday::from_monday_zero_offset_ranged(offset_sunday)
556558
}
557559

@@ -589,7 +591,7 @@ impl Weekday {
589591

590592
#[inline]
591593
pub(crate) fn to_sunday_zero_offset_ranged(self) -> t::WeekdayZero {
592-
(self.to_monday_zero_offset_ranged() + C(1)) % C(7)
594+
(self.to_monday_zero_offset_ranged() + C(1)).rem_floor(C(7))
593595
}
594596

595597
#[inline]
@@ -606,7 +608,7 @@ impl Weekday {
606608
pub(crate) fn since_ranged(self, other: Weekday) -> t::WeekdayZero {
607609
(self.to_monday_zero_offset_ranged()
608610
- other.to_monday_zero_offset_ranged())
609-
% C(7)
611+
.rem_floor(C(7))
610612
}
611613

612614
#[inline]

src/util/rangeint.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,25 +1797,25 @@ macro_rules! define_ranged {
17971797
fn div(self, rhs: $name<MIN2, MAX2>) -> Self::Output {
17981798
#[cfg(not(debug_assertions))]
17991799
{
1800-
let val = self.val.wrapping_div_euclid(rhs.val);
1800+
let val = self.val.wrapping_div(rhs.val);
18011801
Self { val }
18021802
}
18031803
#[cfg(debug_assertions)]
18041804
{
18051805
let val =
1806-
self.val.checked_div_euclid(rhs.val).expect(concat!(
1806+
self.val.checked_div(rhs.val).expect(concat!(
18071807
"dividing ",
18081808
stringify!($name),
18091809
" values overflowed"
18101810
));
18111811
let min =
1812-
self.min.checked_div_euclid(rhs.min).expect(concat!(
1812+
self.min.checked_div(rhs.min).expect(concat!(
18131813
"dividing ",
18141814
stringify!($name),
18151815
" minimums overflowed"
18161816
));
18171817
let max =
1818-
self.max.checked_div_euclid(rhs.max).expect(concat!(
1818+
self.max.checked_div(rhs.max).expect(concat!(
18191819
"dividing ",
18201820
stringify!($name),
18211821
" maximums overflowed"
@@ -1849,25 +1849,25 @@ macro_rules! define_ranged {
18491849
fn rem(self, rhs: $name<MIN2, MAX2>) -> Self::Output {
18501850
#[cfg(not(debug_assertions))]
18511851
{
1852-
let val = self.val.wrapping_rem_euclid(rhs.val);
1852+
let val = self.val.wrapping_rem(rhs.val);
18531853
Self { val }
18541854
}
18551855
#[cfg(debug_assertions)]
18561856
{
18571857
let val =
1858-
self.val.checked_rem_euclid(rhs.val).expect(concat!(
1858+
self.val.checked_rem(rhs.val).expect(concat!(
18591859
"modulo ",
18601860
stringify!($name),
18611861
" values overflowed"
18621862
));
18631863
let min =
1864-
self.min.checked_rem_euclid(rhs.min).expect(concat!(
1864+
self.min.checked_rem(rhs.min).expect(concat!(
18651865
"modulo ",
18661866
stringify!($name),
18671867
" minimums overflowed"
18681868
));
18691869
let max =
1870-
self.max.checked_rem_euclid(rhs.max).expect(concat!(
1870+
self.max.checked_rem(rhs.max).expect(concat!(
18711871
"modulo ",
18721872
stringify!($name),
18731873
" maximums overflowed"

src/util/round/mode.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ impl RoundMode {
164164
}
165165
}
166166
RoundMode::HalfEven => {
167-
if expand_is_nearer || (tie && quotient % C(2) == C(1)) {
167+
if expand_is_nearer
168+
|| (tie && quotient.rem_floor(C(2)) == C(1))
169+
{
168170
quotient += sign;
169171
}
170172
}

0 commit comments

Comments
 (0)