Skip to content

Commit

Permalink
Convert Mdl to return Result
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Feb 14, 2024
1 parent 34b776e commit ee62e45
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 63 deletions.
20 changes: 10 additions & 10 deletions src/naive/date/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use crate::format::{
};
use crate::month::Months;
use crate::naive::{Days, IsoWeek, NaiveDateTime, NaiveTime, NaiveWeek};
use crate::{try_err, try_opt};
use crate::{ok, try_err, try_opt};
use crate::{Datelike, Error, TimeDelta, Weekday};

use super::internals::{Mdf, YearFlags};
Expand Down Expand Up @@ -145,7 +145,7 @@ impl NaiveDate {
if year < MIN_YEAR || year > MAX_YEAR {
return None; // Out-of-range
}
Some(NaiveDate::from_yof((year << 13) | try_opt!(mdf.ordinal_and_flags())))
Some(NaiveDate::from_yof((year << 13) | try_opt!(ok!(mdf.ordinal_and_flags()))))
}

/// Makes a new `NaiveDate` from the [calendar date](#calendar-date)
Expand Down Expand Up @@ -176,7 +176,7 @@ impl NaiveDate {
pub const fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> {
let flags = YearFlags::from_year(year);

if let Some(mdf) = Mdf::new(month, day, flags) {
if let Ok(mdf) = Mdf::new(month, day, flags) {
NaiveDate::from_mdf(year, mdf)
} else {
None
Expand Down Expand Up @@ -546,7 +546,7 @@ impl NaiveDate {
day = day_max;
};

NaiveDate::from_mdf(year, try_opt!(Mdf::new(month as u32, day, flags)))
NaiveDate::from_mdf(year, try_opt!(ok!(Mdf::new(month as u32, day, flags))))
}

/// Add a duration in [`Days`] to the date
Expand Down Expand Up @@ -800,10 +800,10 @@ impl NaiveDate {
const fn with_mdf(&self, mdf: Mdf) -> Option<NaiveDate> {
debug_assert!(self.year_flags().0 == mdf.year_flags().0);
match mdf.ordinal() {
Some(ordinal) => {
Ok(ordinal) => {
Some(NaiveDate::from_yof((self.yof() & !ORDINAL_MASK) | (ordinal << 4) as i32))
}
None => None, // Non-existing date
Err(_) => None, // Non-existing date
}
}

Expand Down Expand Up @@ -1488,7 +1488,7 @@ impl Datelike for NaiveDate {
/// ```
#[inline]
fn with_month(&self, month: u32) -> Option<NaiveDate> {
self.with_mdf(self.mdf().with_month(month)?)
self.with_mdf(self.mdf().with_month(month).ok()?)
}

/// Makes a new `NaiveDate` with the month number (starting from 0) changed.
Expand All @@ -1511,7 +1511,7 @@ impl Datelike for NaiveDate {
#[inline]
fn with_month0(&self, month0: u32) -> Option<NaiveDate> {
let month = month0.checked_add(1)?;
self.with_mdf(self.mdf().with_month(month)?)
self.with_mdf(self.mdf().with_month(month).ok()?)
}

/// Makes a new `NaiveDate` with the day of month (starting from 1) changed.
Expand All @@ -1532,7 +1532,7 @@ impl Datelike for NaiveDate {
/// ```
#[inline]
fn with_day(&self, day: u32) -> Option<NaiveDate> {
self.with_mdf(self.mdf().with_day(day)?)
self.with_mdf(self.mdf().with_day(day).ok()?)
}

/// Makes a new `NaiveDate` with the day of month (starting from 0) changed.
Expand All @@ -1554,7 +1554,7 @@ impl Datelike for NaiveDate {
#[inline]
fn with_day0(&self, day0: u32) -> Option<NaiveDate> {
let day = day0.checked_add(1)?;
self.with_mdf(self.mdf().with_day(day)?)
self.with_mdf(self.mdf().with_day(day).ok()?)
}

/// Makes a new `NaiveDate` with the day of year (starting from 1) changed.
Expand Down
124 changes: 71 additions & 53 deletions src/naive/internals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use core::fmt;

use crate::Error;

/// Year flags (aka the dominical letter).
///
/// `YearFlags` are used as the last four bits of `NaiveDate`, `Mdf` and `IsoWeek`.
Expand Down Expand Up @@ -134,46 +136,47 @@ const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;

// The next table are adjustment values to convert a date encoded as month-day-leapyear to
// ordinal-leapyear. OL = MDL - adjustment.
// Dates that do not exist are encoded as `XX`.
// Error cases are encoded as `-1` and `XX` (`0`). For a quick check all positive values are
// adjustments, `XX` indicates a date does not exist, and negative values are for invalid input.
const XX: i8 = 0;
const MDL_TO_OL: &[i8; MAX_MDL as usize + 1] = &[
XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, // 0
XX, XX, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
-1, -1, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 1
XX, XX, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
-1, -1, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, XX, XX, XX, XX, XX, // 2
XX, XX, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
-1, -1, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, // 3
XX, XX, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
-1, -1, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, XX, XX, // 4
XX, XX, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
-1, -1, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, // 5
XX, XX, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
-1, -1, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, XX, XX, // 6
XX, XX, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
-1, -1, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, // 7
XX, XX, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
-1, -1, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, // 8
XX, XX, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
-1, -1, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, XX, XX, // 9
XX, XX, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
-1, -1, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, // 10
XX, XX, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
-1, -1, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, XX, XX, // 11
XX, XX, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
-1, -1, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
100, // 12
Expand Down Expand Up @@ -244,12 +247,16 @@ impl Mdf {
///
/// # Errors
///
/// Returns `None` if `month > 12` or `day > 31`.
/// Returns [`Error::InvalidArgument`] if `month > 12` or `day > 31`.
#[inline]
pub(super) const fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Option<Mdf> {
pub(super) const fn new(
month: u32,
day: u32,
YearFlags(flags): YearFlags,
) -> Result<Mdf, Error> {
match month <= 12 && day <= 31 {
true => Some(Mdf((month << 9) | (day << 4) | flags as u32)),
false => None,
true => Ok(Mdf((month << 9) | (day << 4) | flags as u32)),
false => Err(Error::InvalidArgument),
}
}

Expand All @@ -275,15 +282,15 @@ impl Mdf {
///
/// # Errors
///
/// Returns `None` if `month > 12`.
/// Returns [`Error::InvalidArgument`] if `month > 12`.
#[inline]
pub(super) const fn with_month(&self, month: u32) -> Option<Mdf> {
pub(super) const fn with_month(&self, month: u32) -> Result<Mdf, Error> {
if month > 12 {
return None;
return Err(Error::InvalidArgument);
}

let Mdf(mdf) = *self;
Some(Mdf((mdf & 0b1_1111_1111) | (month << 9)))
Ok(Mdf((mdf & 0b1_1111_1111) | (month << 9)))
}

/// Returns the day of this `Mdf`.
Expand All @@ -297,15 +304,15 @@ impl Mdf {
///
/// # Errors
///
/// Returns `None` if `day > 31`.
/// Returns [`Error::InvalidArgument`] if `day > 31`.
#[inline]
pub(super) const fn with_day(&self, day: u32) -> Option<Mdf> {
pub(super) const fn with_day(&self, day: u32) -> Result<Mdf, Error> {
if day > 31 {
return None;
return Err(Error::InvalidArgument);
}

let Mdf(mdf) = *self;
Some(Mdf((mdf & !0b1_1111_0000) | (day << 4)))
Ok(Mdf((mdf & !0b1_1111_0000) | (day << 4)))
}

/// Replaces the flags of this `Mdf`, keeping the month and day.
Expand All @@ -322,14 +329,19 @@ impl Mdf {
///
/// # Errors
///
/// Returns `None` if `month == 0` or `day == 0`, or if a the given day does not exist in the
/// given month.
/// Returns [`Error::InvalidArgument`] if `month == 0` or `day == 0`.
///
/// Returns [`Error::DoesNotExist`] if the given day does not exist in the given month.
#[inline]
pub(super) const fn ordinal(&self) -> Option<u32> {
pub(super) const fn ordinal(&self) -> Result<u32, Error> {
let mdl = self.0 >> 3;
match MDL_TO_OL[mdl as usize] {
XX => None,
v => Some((mdl - v as u8 as u32) >> 1),
let adjustment = MDL_TO_OL[mdl as usize];
if adjustment > 0 {
Ok((mdl - adjustment as u8 as u32) >> 1)
} else if adjustment == 0 {
Err(Error::DoesNotExist)
} else {
Err(Error::InvalidArgument)
}
}

Expand All @@ -346,14 +358,19 @@ impl Mdf {
///
/// # Errors
///
/// Returns `None` if `month == 0` or `day == 0`, or if a the given day does not exist in the
/// given month.
/// Returns [`Error::InvalidArgument`] if `month == 0` or `day == 0`.
///
/// Returns [`Error::DoesNotExist`] if the given day does not exist in the given month.
#[inline]
pub(super) const fn ordinal_and_flags(&self) -> Option<i32> {
pub(super) const fn ordinal_and_flags(&self) -> Result<i32, Error> {
let mdl = self.0 >> 3;
match MDL_TO_OL[mdl as usize] {
XX => None,
v => Some(self.0 as i32 - ((v as i32) << 3)),
let adjustment = MDL_TO_OL[mdl as usize];
if adjustment > 0 {
Ok(self.0 as i32 - ((adjustment as i32) << 3))
} else if adjustment == 0 {
Err(Error::DoesNotExist)
} else {
Err(Error::InvalidArgument)
}
}

Expand Down Expand Up @@ -382,6 +399,7 @@ impl fmt::Debug for Mdf {
mod tests {
use super::Mdf;
use super::{YearFlags, A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF};
use crate::Error;

const NONLEAP_FLAGS: [YearFlags; 7] = [A, B, C, D, E, F, G];
const LEAP_FLAGS: [YearFlags; 7] = [AG, BA, CB, DC, ED, FE, GF];
Expand Down Expand Up @@ -428,9 +446,9 @@ mod tests {
for month in month1..=month2 {
for day in day1..=day2 {
let mdf = match Mdf::new(month, day, flags) {
Some(mdf) => mdf,
None if !expected => continue,
None => panic!("Mdf::new({}, {}, {:?}) returned None", month, day, flags),
Ok(mdf) => mdf,
Err(_) if !expected => continue,
Err(_) => panic!("Mdf::new({}, {}, {:?}) returned Err", month, day, flags),
};

assert!(
Expand Down Expand Up @@ -519,8 +537,8 @@ mod tests {
for month in 1u32..=12 {
for day in 1u32..31 {
let mdf = match Mdf::new(month, day, flags) {
Some(mdf) => mdf,
None => continue,
Ok(mdf) => mdf,
Err(_) => continue,
};

if mdf.valid() {
Expand All @@ -539,9 +557,9 @@ mod tests {

for month in 0u32..=16 {
let mdf = match mdf.with_month(month) {
Some(mdf) => mdf,
None if month > 12 => continue,
None => panic!("failed to create Mdf with month {}", month),
Ok(mdf) => mdf,
Err(_) if month > 12 => continue,
Err(_) => panic!("failed to create Mdf with month {}", month),
};

if mdf.valid() {
Expand All @@ -552,9 +570,9 @@ mod tests {

for day in 0u32..=1024 {
let mdf = match mdf.with_day(day) {
Some(mdf) => mdf,
None if day > 31 => continue,
None => panic!("failed to create Mdf with month {}", month),
Ok(mdf) => mdf,
Err(_) if day > 31 => continue,
Err(_) => panic!("failed to create Mdf with month {}", month),
};

if mdf.valid() {
Expand Down Expand Up @@ -585,7 +603,7 @@ mod tests {
#[test]
fn test_mdf_new_range() {
let flags = YearFlags::from_year(2023);
assert!(Mdf::new(13, 1, flags).is_none());
assert!(Mdf::new(1, 32, flags).is_none());
assert_eq!(Mdf::new(13, 1, flags), Err(Error::InvalidArgument));
assert_eq!(Mdf::new(1, 32, flags), Err(Error::InvalidArgument));
}
}

0 comments on commit ee62e45

Please sign in to comment.