Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor internals module part 2 #1429

Merged
merged 4 commits into from Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
65 changes: 48 additions & 17 deletions src/naive/date.rs
Expand Up @@ -238,10 +238,14 @@
if year < MIN_YEAR || year > MAX_YEAR {
return None; // Out-of-range
}
if ordinal == 0 || ordinal > 366 {
return None; // Invalid
}
debug_assert!(YearFlags::from_year(year).0 == flags.0);
match Of::new(ordinal, flags) {
Some(of) => Some(NaiveDate { yof: (year << 13) | (of.inner() as i32) }),
None => None, // Invalid: Ordinal outside of the nr of days in a year with those flags.
let yof = (year << 13) | (ordinal << 4) as i32 | flags.0 as i32;
match yof & OL_MASK <= MAX_OL {
true => Some(NaiveDate { yof }),
false => None, // Does not exist: Ordinal 366 in a common year.
}
}

Expand Down Expand Up @@ -803,7 +807,7 @@
// do the full check
let year = self.year();
let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400);
let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal());
let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.ordinal());
let cycle = try_opt!((cycle as i32).checked_add(days));
let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097);
year_div_400 += cycle_div_400y;
Expand Down Expand Up @@ -1098,9 +1102,10 @@
#[inline]
#[must_use]
pub const fn succ_opt(&self) -> Option<NaiveDate> {
match self.of().succ() {
Some(of) => Some(self.with_of(of)),
None => NaiveDate::from_ymd_opt(self.year() + 1, 1, 1),
let new_ol = (self.yof & OL_MASK) + (1 << 4);
match new_ol <= MAX_OL {
true => Some(NaiveDate { yof: self.yof & !OL_MASK | new_ol }),
false => NaiveDate::from_yo_opt(self.year() + 1, 1),
}
}

Expand Down Expand Up @@ -1134,9 +1139,10 @@
#[inline]
#[must_use]
pub const fn pred_opt(&self) -> Option<NaiveDate> {
match self.of().pred() {
Some(of) => Some(self.with_of(of)),
None => NaiveDate::from_ymd_opt(self.year() - 1, 12, 31),
let new_shifted_ordinal = (self.yof & ORDINAL_MASK) - (1 << 4);
match new_shifted_ordinal > 0 {
true => Some(NaiveDate { yof: self.yof & !ORDINAL_MASK | new_shifted_ordinal }),
false => NaiveDate::from_ymd_opt(self.year() - 1, 12, 31),
}
}

Expand Down Expand Up @@ -1226,8 +1232,8 @@
let year2 = rhs.year();
let (year1_div_400, year1_mod_400) = div_mod_floor(year1, 400);
let (year2_div_400, year2_mod_400) = div_mod_floor(year2, 400);
let cycle1 = internals::yo_to_cycle(year1_mod_400 as u32, self.of().ordinal()) as i64;
let cycle2 = internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal()) as i64;
let cycle1 = internals::yo_to_cycle(year1_mod_400 as u32, self.ordinal()) as i64;
let cycle2 = internals::yo_to_cycle(year2_mod_400 as u32, rhs.ordinal()) as i64;
TimeDelta::days((year1_div_400 as i64 - year2_div_400 as i64) * 146_097 + (cycle1 - cycle2))
}

Expand Down Expand Up @@ -1453,7 +1459,7 @@
// This duplicates `Datelike::ordinal()`, because trait methods can't be const yet.
#[inline]
const fn ordinal(&self) -> u32 {
self.of().ordinal()
((self.yof & ORDINAL_MASK) >> 4) as u32
}

// This duplicates `Datelike::month()`, because trait methods can't be const yet.
Expand Down Expand Up @@ -1646,7 +1652,7 @@
/// ```
#[inline]
fn ordinal(&self) -> u32 {
self.of().ordinal()
((self.yof & ORDINAL_MASK) >> 4) as u32
}

/// Returns the day of year starting from 0.
Expand All @@ -1663,7 +1669,7 @@
/// ```
#[inline]
fn ordinal0(&self) -> u32 {
self.of().ordinal() - 1
self.ordinal() - 1
}

/// Returns the day of week.
Expand Down Expand Up @@ -1834,7 +1840,14 @@
/// ```
#[inline]
fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDate> {
self.of().with_ordinal(ordinal).map(|of| self.with_of(of))
if ordinal == 0 || ordinal > 366 {
return None;
}
let yof = (self.yof & !ORDINAL_MASK) | (ordinal << 4) as i32;
match yof & OL_MASK <= MAX_OL {
true => Some(NaiveDate { yof }),
false => None, // Does not exist: Ordinal 366 in a common year.
}
}

/// Makes a new `NaiveDate` with the day of year (starting from 0) changed.
Expand Down Expand Up @@ -2309,6 +2322,17 @@
/// `NaiveDate::MIN` pushes it beyond the valid, representable range.
pub(super) const MIN_YEAR: i32 = (i32::MIN >> 13) + 1;

const ORDINAL_MASK: i32 = 0b1_1111_1111_0000;

const LEAP_YEAR_MASK: i32 = 0b1000;

// OL: ordinal and leap year flag.
// With only these parts of the date an ordinal 366 in a common year would be encoded as
// `((366 << 1) | 1) << 3`, and in a leap year as `((366 << 1) | 0) << 3`, which is less.
// This allows for efficiently checking the ordinal exists depending on whether this is a leap year.
const OL_MASK: i32 = ORDINAL_MASK | LEAP_YEAR_MASK;
const MAX_OL: i32 = 366 << 4;

#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
fn test_encodable_json<F, E>(to_string: F)
where
Expand Down Expand Up @@ -2511,7 +2535,7 @@
NaiveDate::MAX == calculated_max,
"`NaiveDate::MAX` should have year flag {:?} and ordinal {}",
calculated_max.of().flags(),
calculated_max.of().ordinal()
calculated_max.ordinal()

Check warning on line 2538 in src/naive/date.rs

View check run for this annotation

Codecov / codecov/patch

src/naive/date.rs#L2538

Added line #L2538 was not covered by tests
);

// let's also check that the entire range do not exceed 2^44 seconds
Expand Down Expand Up @@ -2675,6 +2699,7 @@
assert_eq!(yo_opt(2012, 300), Some(ymd(2012, 10, 26)));
assert_eq!(yo_opt(2012, 366), Some(ymd(2012, 12, 31)));
assert_eq!(yo_opt(2012, 367), None);
assert_eq!(yo_opt(2012, 1 << 28 | 60), None);

assert_eq!(yo_opt(2014, 0), None);
assert_eq!(yo_opt(2014, 1), Some(ymd(2014, 1, 1)));
Expand Down Expand Up @@ -2933,14 +2958,20 @@
assert_eq!(d.with_day(29), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap()));
assert_eq!(d.with_day(30), None);
assert_eq!(d.with_day(u32::MAX), None);
}

#[test]
fn test_date_with_ordinal() {
let d = NaiveDate::from_ymd_opt(2000, 5, 5).unwrap();
assert_eq!(d.with_ordinal(0), None);
assert_eq!(d.with_ordinal(1), Some(NaiveDate::from_ymd_opt(2000, 1, 1).unwrap()));
assert_eq!(d.with_ordinal(60), Some(NaiveDate::from_ymd_opt(2000, 2, 29).unwrap()));
assert_eq!(d.with_ordinal(61), Some(NaiveDate::from_ymd_opt(2000, 3, 1).unwrap()));
assert_eq!(d.with_ordinal(366), Some(NaiveDate::from_ymd_opt(2000, 12, 31).unwrap()));
assert_eq!(d.with_ordinal(367), None);
assert_eq!(d.with_ordinal(1 << 28 | 60), None);
let d = NaiveDate::from_ymd_opt(1999, 5, 5).unwrap();
assert_eq!(d.with_ordinal(366), None);
assert_eq!(d.with_ordinal(u32::MAX), None);
}

Expand Down
70 changes: 1 addition & 69 deletions src/naive/internals.rs
Expand Up @@ -267,6 +267,7 @@ pub(super) struct Of(u32);

impl Of {
#[inline]
#[cfg(test)]
pub(super) const fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Option<Of> {
let of = Of((ordinal << 4) | flags as u32);
of.validate()
Expand Down Expand Up @@ -310,17 +311,6 @@ impl Of {
}
}

#[inline]
pub(super) const fn ordinal(&self) -> u32 {
self.0 >> 4
}

#[inline]
pub(super) const fn with_ordinal(&self, ordinal: u32) -> Option<Of> {
let of = Of((ordinal << 4) | (self.0 & 0b1111));
of.validate()
}

#[inline]
pub(super) const fn flags(&self) -> YearFlags {
YearFlags((self.0 & 0b1111) as u8)
Expand All @@ -345,22 +335,6 @@ impl Of {
pub(super) const fn to_mdf(&self) -> Mdf {
Mdf::from_of(*self)
}

/// Returns an `Of` with the next day, or `None` if this is the last day of the year.
#[inline]
pub(super) const fn succ(&self) -> Option<Of> {
let of = Of(self.0 + (1 << 4));
of.validate()
}

/// Returns an `Of` with the previous day, or `None` if this is the first day of the year.
#[inline]
pub(super) const fn pred(&self) -> Option<Of> {
match self.ordinal() {
1 => None,
_ => Some(Of(self.0 - (1 << 4))),
}
}
}

impl fmt::Debug for Of {
Expand Down Expand Up @@ -669,41 +643,6 @@ mod tests {
}
}

#[test]
fn test_of_fields() {
for &flags in FLAGS.iter() {
for ordinal in 1u32..=366 {
if let Some(of) = Of::new(ordinal, flags) {
assert_eq!(of.ordinal(), ordinal);
}
}
}
}

#[test]
fn test_of_with_fields() {
fn check(flags: YearFlags, ordinal: u32) {
let of = Of::new(ordinal, flags).unwrap();

for ordinal in 0u32..=1024 {
let of = of.with_ordinal(ordinal);
assert_eq!(of, Of::new(ordinal, flags));
if let Some(of) = of {
assert_eq!(of.ordinal(), ordinal);
}
}
}

for &flags in NONLEAP_FLAGS.iter() {
check(flags, 1);
check(flags, 365);
}
for &flags in LEAP_FLAGS.iter() {
check(flags, 1);
check(flags, 366);
}
}

#[test]
fn test_of_weekday() {
assert_eq!(Of::new(1, A).unwrap().weekday(), Weekday::Sun);
Expand Down Expand Up @@ -866,13 +805,6 @@ mod tests {
assert!(Of::from_mdf(Mdf::new(2, 29, regular_year).unwrap()).is_none());
assert!(Of::from_mdf(Mdf::new(2, 29, leap_year).unwrap()).is_some());
assert!(Of::from_mdf(Mdf::new(2, 28, regular_year).unwrap()).is_some());

assert!(Of::new(365, regular_year).unwrap().succ().is_none());
assert!(Of::new(365, leap_year).unwrap().succ().is_some());
assert!(Of::new(366, leap_year).unwrap().succ().is_none());

assert!(Of::new(1, regular_year).unwrap().pred().is_none());
assert!(Of::new(1, leap_year).unwrap().pred().is_none());
}

#[test]
Expand Down