Skip to content

Commit 5e4c3ae

Browse files
committed
Make Mdf methods fallible in the face of invalid input
1 parent bd65046 commit 5e4c3ae

File tree

2 files changed

+46
-40
lines changed

2 files changed

+46
-40
lines changed

src/naive/date.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ impl NaiveDate {
267267
/// ```
268268
pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> {
269269
let flags = YearFlags::from_year(year);
270-
NaiveDate::from_mdf(year, Mdf::new(month, day, flags))
270+
NaiveDate::from_mdf(year, Mdf::new(month, day, flags)?)
271271
}
272272

273273
/// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date)
@@ -615,7 +615,7 @@ impl NaiveDate {
615615
let days = [31, feb_days, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
616616
let day = Ord::min(self.day(), days[(month - 1) as usize]);
617617

618-
NaiveDate::from_mdf(year, Mdf::new(month as u32, day, flags))
618+
NaiveDate::from_mdf(year, Mdf::new(month as u32, day, flags)?)
619619
}
620620

621621
/// Add a duration in [`Days`] to the date
@@ -1429,7 +1429,7 @@ impl Datelike for NaiveDate {
14291429
/// ```
14301430
#[inline]
14311431
fn with_month(&self, month: u32) -> Option<NaiveDate> {
1432-
self.with_mdf(self.mdf().with_month(month))
1432+
self.with_mdf(self.mdf().with_month(month)?)
14331433
}
14341434

14351435
/// Makes a new `NaiveDate` with the month number (starting from 0) changed.
@@ -1448,7 +1448,7 @@ impl Datelike for NaiveDate {
14481448
/// ```
14491449
#[inline]
14501450
fn with_month0(&self, month0: u32) -> Option<NaiveDate> {
1451-
self.with_mdf(self.mdf().with_month(month0 + 1))
1451+
self.with_mdf(self.mdf().with_month(month0 + 1)?)
14521452
}
14531453

14541454
/// Makes a new `NaiveDate` with the day of month (starting from 1) changed.
@@ -1467,7 +1467,7 @@ impl Datelike for NaiveDate {
14671467
/// ```
14681468
#[inline]
14691469
fn with_day(&self, day: u32) -> Option<NaiveDate> {
1470-
self.with_mdf(self.mdf().with_day(day))
1470+
self.with_mdf(self.mdf().with_day(day)?)
14711471
}
14721472

14731473
/// Makes a new `NaiveDate` with the day of month (starting from 0) changed.
@@ -1486,7 +1486,7 @@ impl Datelike for NaiveDate {
14861486
/// ```
14871487
#[inline]
14881488
fn with_day0(&self, day0: u32) -> Option<NaiveDate> {
1489-
self.with_mdf(self.mdf().with_day(day0 + 1))
1489+
self.with_mdf(self.mdf().with_day(day0 + 1)?)
14901490
}
14911491

14921492
/// Makes a new `NaiveDate` with the day of year (starting from 1) changed.

src/naive/internals.rs

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -371,30 +371,13 @@ pub(super) struct Mdf(pub(super) u32);
371371

372372
impl Mdf {
373373
#[inline]
374-
fn clamp_month(month: u32) -> u32 {
375-
if month > 12 {
376-
0
377-
} else {
378-
month
379-
}
380-
}
381-
382-
#[inline]
383-
fn clamp_day(day: u32) -> u32 {
384-
if day > 31 {
385-
0
386-
} else {
387-
day
374+
pub(super) fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Option<Mdf> {
375+
match month <= 12 && day <= 31 {
376+
true => Some(Mdf((month << 9) | (day << 4) | u32::from(flags))),
377+
false => None,
388378
}
389379
}
390380

391-
#[inline]
392-
pub(super) fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Mdf {
393-
let month = Mdf::clamp_month(month);
394-
let day = Mdf::clamp_day(day);
395-
Mdf((month << 9) | (day << 4) | u32::from(flags))
396-
}
397-
398381
#[inline]
399382
pub(super) fn from_of(Of(of): Of) -> Mdf {
400383
let ol = of >> 3;
@@ -421,10 +404,13 @@ impl Mdf {
421404
}
422405

423406
#[inline]
424-
pub(super) fn with_month(&self, month: u32) -> Mdf {
425-
let month = Mdf::clamp_month(month);
407+
pub(super) fn with_month(&self, month: u32) -> Option<Mdf> {
408+
if month > 12 {
409+
return None;
410+
}
411+
426412
let Mdf(mdf) = *self;
427-
Mdf((mdf & 0b1_1111_1111) | (month << 9))
413+
Some(Mdf((mdf & 0b1_1111_1111) | (month << 9)))
428414
}
429415

430416
#[inline]
@@ -434,10 +420,13 @@ impl Mdf {
434420
}
435421

436422
#[inline]
437-
pub(super) fn with_day(&self, day: u32) -> Mdf {
438-
let day = Mdf::clamp_day(day);
423+
pub(super) fn with_day(&self, day: u32) -> Option<Mdf> {
424+
if day > 31 {
425+
return None;
426+
}
427+
439428
let Mdf(mdf) = *self;
440-
Mdf((mdf & !0b1_1111_0000) | (day << 4))
429+
Some(Mdf((mdf & !0b1_1111_0000) | (day << 4)))
441430
}
442431

443432
#[inline]
@@ -556,7 +545,12 @@ mod tests {
556545
fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32, month2: u32, day2: u32) {
557546
for month in range_inclusive(month1, month2) {
558547
for day in range_inclusive(day1, day2) {
559-
let mdf = Mdf::new(month, day, flags);
548+
let mdf = match Mdf::new(month, day, flags) {
549+
Some(mdf) => mdf,
550+
None if !expected => continue,
551+
None => panic!("Mdf::new({}, {}, {:?}) returned None", month, day, flags),
552+
};
553+
560554
assert!(
561555
mdf.valid() == expected,
562556
"month {} day {} = {:?} should be {} for dominical year {:?}",
@@ -711,7 +705,11 @@ mod tests {
711705
for &flags in FLAGS.iter() {
712706
for month in range_inclusive(1u32, 12) {
713707
for day in range_inclusive(1u32, 31) {
714-
let mdf = Mdf::new(month, day, flags);
708+
let mdf = match Mdf::new(month, day, flags) {
709+
Some(mdf) => mdf,
710+
None => continue,
711+
};
712+
715713
if mdf.valid() {
716714
assert_eq!(mdf.month(), month);
717715
assert_eq!(mdf.day(), day);
@@ -724,20 +722,28 @@ mod tests {
724722
#[test]
725723
fn test_mdf_with_fields() {
726724
fn check(flags: YearFlags, month: u32, day: u32) {
727-
let mdf = Mdf::new(month, day, flags);
725+
let mdf = Mdf::new(month, day, flags).unwrap();
728726

729727
for month in range_inclusive(0u32, 16) {
730-
let mdf = mdf.with_month(month);
731-
assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
728+
let mdf = match mdf.with_month(month) {
729+
Some(mdf) => mdf,
730+
None if month > 12 => continue,
731+
None => panic!("failed to create Mdf with month {}", month),
732+
};
733+
732734
if mdf.valid() {
733735
assert_eq!(mdf.month(), month);
734736
assert_eq!(mdf.day(), day);
735737
}
736738
}
737739

738740
for day in range_inclusive(0u32, 1024) {
739-
let mdf = mdf.with_day(day);
740-
assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
741+
let mdf = match mdf.with_day(day) {
742+
Some(mdf) => mdf,
743+
None if day > 31 => continue,
744+
None => panic!("failed to create Mdf with month {}", month),
745+
};
746+
741747
if mdf.valid() {
742748
assert_eq!(mdf.month(), month);
743749
assert_eq!(mdf.day(), day);

0 commit comments

Comments
 (0)