diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2017-11-24 16:05:34 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-24 16:05:34 +0100 |
commit | 0ce2af172f7249d25c2e9f75f9324eab1a029a80 (patch) | |
tree | 3be3d1f33b9f4a81432ec78e1d6368f5131da363 | |
parent | 9b990ff630864c5245328c015cab94af98ae3f0a (diff) | |
parent | a19b88d52c54229faaceb06a470e7c38f23805cf (diff) |
Merge pull request #15 from matthiasbeyer/fix-panic
Fix panics
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | fuzz/.gitignore | 4 | ||||
-rw-r--r-- | fuzz/Cargo.toml | 22 | ||||
-rw-r--r-- | fuzz/fuzz_targets/parse.rs | 9 | ||||
-rw-r--r-- | src/error.rs | 5 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/parser/iterator.rs | 9 | ||||
-rw-r--r-- | src/parser/mod.rs | 12 | ||||
-rw-r--r-- | src/parser/timetype.rs | 138 | ||||
-rw-r--r-- | src/timetype.rs | 118 | ||||
-rw-r--r-- | src/util.rs | 8 |
11 files changed, 215 insertions, 114 deletions
@@ -1,6 +1,6 @@ [package] name = "kairos" -version = "0.1.0-beta-1" +version = "0.1.0-beta-2" authors = ["Matthias Beyer <mail@beyermatthias.de>"] description = "A library on top of chrono to calculate times and dates ergonomically" diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..572e03b --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,4 @@ + +target +corpus +artifacts diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..8aa3986 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,22 @@ + +[package] +name = "kairos-fuzz" +version = "0.0.1" +authors = ["Automatically generated"] +publish = false + +[package.metadata] +cargo-fuzz = true + +[dependencies.kairos] +path = ".." +[dependencies.libfuzzer-sys] +git = "https://github.com/rust-fuzz/libfuzzer-sys.git" + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "parse" +path = "fuzz_targets/parse.rs" diff --git a/fuzz/fuzz_targets/parse.rs b/fuzz/fuzz_targets/parse.rs new file mode 100644 index 0000000..5d6aa8b --- /dev/null +++ b/fuzz/fuzz_targets/parse.rs @@ -0,0 +1,9 @@ +#![no_main] +#[macro_use] extern crate libfuzzer_sys; +extern crate kairos; + +fuzz_target!(|data: &[u8]| { + if let Ok(data) = std::str::from_utf8(data) { + let _ = kairos::parser::parse(data); + } +}); diff --git a/src/error.rs b/src/error.rs index b9e7949..43413d7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -59,6 +59,11 @@ error_chain! { display("Cannot compare Month to non-Moment TimeType: {:?}", tt_rep) } + OutOfBounds(y: i32, mo: u32, d: u32, hr: u32, mi: u32, s: u32) { + description("Out of bounds error") + display("Out of bounds: {}-{}-{}T{}:{}:{}", y, mo, d, hr, mi, s) + } + NotADateInsideIterator { description("Cannot calculate date for iterator") display("Cannot calculate date for iterator") @@ -1,3 +1,5 @@ +#![recursion_limit="256"] + #[macro_use] extern crate error_chain; extern crate chrono; diff --git a/src/parser/iterator.rs b/src/parser/iterator.rs index a1db5ae..f06edd0 100644 --- a/src/parser/iterator.rs +++ b/src/parser/iterator.rs @@ -1,6 +1,7 @@ use nom::whitespace::sp; use parser::timetype::*; +use timetype::IntoTimeType; use timetype; use iter; use error; @@ -95,22 +96,22 @@ impl Iterator { match self.2 { Some(UntilSpec::Exact(e)) => { - let base = try!(into_ndt(self.0.into())); - let e = try!(into_ndt(e.into())); + let base = try!(into_ndt(self.0.into_timetype()?)); + let e = try!(into_ndt(e.into_timetype()?)); iter::Iter::build(base, recur) .map(|it| UserIterator::UntilIterator(it.until(e))) }, Some(UntilSpec::Times(i)) => { - let base = try!(into_ndt(self.0.into())); + let base = try!(into_ndt(self.0.into_timetype()?)); iter::Iter::build(base, recur) .map(|it| it.times(i)) .map(UserIterator::TimesIter) }, None => { - let base = try!(into_ndt(self.0.into())); + let base = try!(into_ndt(self.0.into_timetype()?)); iter::Iter::build(base, recur) .map(UserIterator::Iterator) }, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 884ba95..f67a3cb 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -52,6 +52,7 @@ mod iterator; use error::Result; use error::KairosErrorKind as KEK; use iter::Iter; +use timetype::IntoTimeType; use parser::timetype::timetype; use parser::iterator::iterator; @@ -60,15 +61,16 @@ pub enum Parsed { TimeType(::timetype::TimeType) } -named!(do_parse<Parsed>, alt_complete!( - do_parse!(it: iterator >> (Parsed::Iterator(it.into_user_iterator()))) | - do_parse!(tt: timetype >> (Parsed::TimeType(tt.into()))) +named!(do_parse<Result<Parsed>>, alt_complete!( + do_parse!(it: iterator >> (Ok(Parsed::Iterator(it.into_user_iterator())))) | + do_parse!(tt: timetype >> (tt.into_timetype().map(Parsed::TimeType))) )); pub fn parse(s: &str) -> Result<Parsed> { match do_parse(s.as_bytes()) { - IResult::Done(_, o) => Ok(o), - IResult::Error(e) => Err(e).map_err(From::from), + IResult::Done(_, Ok(o)) => Ok(o), + IResult::Done(_, Err(e)) => Err(e), + IResult::Error(e) => Err(e).map_err(From::from), IResult::Incomplete(Needed::Unknown) => Err(KEK::UnknownParserError.into()), IResult::Incomplete(Needed::Size(_)) => Err(KEK::UnknownParserError.into()), diff --git a/src/parser/timetype.rs b/src/parser/timetype.rs index 62e321b..bdd7eba 100644 --- a/src/parser/timetype.rs +++ b/src/parser/timetype.rs @@ -5,7 +5,10 @@ use nom::digit; use nom::whitespace::sp; use chrono::NaiveDate; +use timetype::IntoTimeType; use timetype; +use error::Result; +use error::KairosErrorKind as KEK; named!(pub integer<i64>, alt!( map_res!( @@ -76,9 +79,9 @@ named!(pub amount_parser<Amount>, do_parse!( #[derive(Debug, PartialEq, Eq)] pub struct Amount(i64, Unit); -impl Into<timetype::TimeType> for Amount { - fn into(self) -> timetype::TimeType { - match self.1 { +impl IntoTimeType for Amount { + fn into_timetype(self) -> Result<timetype::TimeType> { + Ok(match self.1 { Unit::Second => timetype::TimeType::seconds(self.0), Unit::Minute => timetype::TimeType::minutes(self.0), Unit::Hour => timetype::TimeType::hours(self.0), @@ -86,7 +89,7 @@ impl Into<timetype::TimeType> for Amount { Unit::Week => timetype::TimeType::weeks(self.0), Unit::Month => timetype::TimeType::months(self.0), Unit::Year => timetype::TimeType::years(self.0), - } + }) } } @@ -110,22 +113,18 @@ pub struct AmountExpr { next: Option<(Operator, Box<AmountExpr>)>, } -impl Into<timetype::TimeType> for AmountExpr { - fn into(self) -> timetype::TimeType { - let mut amount = self.amount.into(); +impl IntoTimeType for AmountExpr { + fn into_timetype(self) -> Result<timetype::TimeType> { + let mut amount = self.amount.into_timetype()?; if let Some((op, other_amonut_expr)) = self.next { match op { - Operator::Plus => { - amount = amount + (*other_amonut_expr).into(); - }, - Operator::Minus => { - amount = amount - (*other_amonut_expr).into(); - }, + Operator::Plus => amount = amount + (*other_amonut_expr).into_timetype()?, + Operator::Minus => amount = amount - (*other_amonut_expr).into_timetype()?, } } - amount + Ok(amount) } } @@ -150,56 +149,69 @@ pub enum ExactDate { Iso8601DateTime(::iso8601::DateTime) } -impl Into<timetype::TimeType> for ExactDate { - fn into(self) -> timetype::TimeType { +impl IntoTimeType for ExactDate { + fn into_timetype(self) -> Result<timetype::TimeType> { match self { - ExactDate::Today => timetype::TimeType::today(), - ExactDate::Yesterday => timetype::TimeType::today() - timetype::TimeType::days(1), - ExactDate::Tomorrow => timetype::TimeType::today() + timetype::TimeType::days(1), + ExactDate::Today => Ok(timetype::TimeType::today()), + ExactDate::Yesterday => Ok(timetype::TimeType::today() - timetype::TimeType::days(1)), + ExactDate::Tomorrow => Ok(timetype::TimeType::today() + timetype::TimeType::days(1)), ExactDate::Iso8601Date(date) => { match date { - ::iso8601::Date::YMD { year, month, day } => { - let ndt = NaiveDate::from_ymd(year, month, day).and_hms(0, 0, 0); - timetype::TimeType::moment(ndt) - }, - ::iso8601::Date::Week { year, ww, d } => { - let ndt = NaiveDate::from_ymd(year, 1, 1).and_hms(0, 0, 0); - timetype::TimeType::moment(ndt) + ::iso8601::Date::YMD { year, month, day } => NaiveDate::from_ymd_opt(year, month, day) + .ok_or(KEK::OutOfBounds(year, month, day, 0, 0, 0).into()) + .map(|ndt| ndt.and_hms(0, 0, 0)) + .map(timetype::TimeType::moment), + + ::iso8601::Date::Week { year, ww, d } => NaiveDate::from_ymd_opt(year, 1, 1) + .ok_or(KEK::OutOfBounds(year, 1, 1, 0, 0, 0).into()) + .map(|ndt| ndt.and_hms(0, 0, 0)) + .map(timetype::TimeType::moment) + .map(|m| { + m + timetype::TimeType::weeks(ww as i64) + timetype::TimeType::days(d as i64) - }, - ::iso8601::Date::Ordinal { year, ddd } => { - let ndt = NaiveDate::from_ymd(year, 1, 1).and_hms(0, 0, 0); - timetype::TimeType::moment(ndt) - + timetype::TimeType::days(ddd as i64) - }, + }), + + ::iso8601::Date::Ordinal { year, ddd } => NaiveDate::from_ymd_opt(year, 1, 1) + .ok_or(KEK::OutOfBounds(year, 1, 1, 0, 0, 0).into()) + .map(|ndt| ndt.and_hms(0, 0, 0)) + .map(timetype::TimeType::moment) + .map(|m| m + timetype::TimeType::days(ddd as i64)), } }, ExactDate::Iso8601DateTime(::iso8601::DateTime { date, time }) => { let (hour, minute, second) = (time.hour, time.minute, time.second); match date { - ::iso8601::Date::YMD { year, month, day } => { - let ndt = NaiveDate::from_ymd(year, month, day).and_hms(hour, minute, second); - timetype::TimeType::moment(ndt) - }, - ::iso8601::Date::Week { year, ww, d } => { - let ndt = NaiveDate::from_ymd(year, 1, 1).and_hms(0, 0, 0); - timetype::TimeType::moment(ndt) + ::iso8601::Date::YMD { year, month, day } => NaiveDate::from_ymd_opt(year, month, day) + .and_then(|ndt| ndt.and_hms_opt(hour, minute, second)) + .ok_or(KEK::OutOfBounds(year, month, day, hour, minute, second).into()) + .map(timetype::TimeType::moment), + + ::iso8601::Date::Week { year, ww, d } => NaiveDate::from_ymd_opt(year, 1, 1) + .ok_or(KEK::OutOfBounds(year, 1, 1, 0, 0, 0).into()) + .map(|ndt| ndt.and_hms(0, 0, 0)) + .map(timetype::TimeType::moment) + .map(|m| { + m + timetype::TimeType::weeks(ww as i64) + timetype::TimeType::days(d as i64) + timetype::TimeType::hours(hour as i64) + timetype::TimeType::minutes(minute as i64) + timetype::TimeType::seconds(second as i64) - }, - ::iso8601::Date::Ordinal { year, ddd } => { - let ndt = NaiveDate::from_ymd(year, 1, 1).and_hms(0, 0, 0); - timetype::TimeType::moment(ndt) + }), + + ::iso8601::Date::Ordinal { year, ddd } => NaiveDate::from_ymd_opt(year, 1, 1) + .ok_or(KEK::OutOfBounds(year, 1, 1, 0, 0, 0).into()) + .map(|ndt| ndt.and_hms(0, 0, 0)) + .map(timetype::TimeType::moment) + .map(|m| { + m + timetype::TimeType::days(ddd as i64) + timetype::TimeType::hours(hour as i64) + timetype::TimeType::minutes(minute as i64) + timetype::TimeType::seconds(second as i64) - }, + }), } }, } @@ -217,13 +229,13 @@ named!(pub date<Date>, do_parse!( #[derive(Debug, PartialEq, Eq)] pub struct Date(ExactDate, Option<(Operator, AmountExpr)>); -impl Into<timetype::TimeType> for Date { - fn into(self) -> timetype::TimeType { - let base : timetype::TimeType = self.0.into(); +impl IntoTimeType for Date { + fn into_timetype(self) -> Result<timetype::TimeType> { + let base : timetype::TimeType = self.0.into_timetype()?; match self.1 { - Some((Operator::Plus, amount)) => base + amount.into(), - Some((Operator::Minus, amount)) => base - amount.into(), - None => base, + Some((Operator::Plus, amount)) => Ok(base + amount.into_timetype()?), + Some((Operator::Minus, amount)) => Ok(base - amount.into_timetype()?), + None => Ok(base), } } } @@ -234,11 +246,11 @@ pub enum TimeType { AmountExpr(AmountExpr), } -impl Into<timetype::TimeType> for TimeType { - fn into(self) -> timetype::TimeType { +impl IntoTimeType for TimeType { + fn into_timetype(self) -> Result<timetype::TimeType> { match self { - TimeType::Date(d) => d.into(), - TimeType::AmountExpr(a) => a.into(), + TimeType::Date(d) => d.into_timetype(), + TimeType::AmountExpr(a) => a.into_timetype(), } } } @@ -414,7 +426,7 @@ mod tests { println!("{:#?}", o); - let calc_res : timetype::TimeType = o.into(); + let calc_res : timetype::TimeType = o.into_timetype().unwrap(); let calc_res = calc_res.calculate(); assert!(calc_res.is_ok()); @@ -437,7 +449,7 @@ mod tests { println!("{:#?}", o); - let calc_res : timetype::TimeType = o.into(); + let calc_res : timetype::TimeType = o.into_timetype().unwrap(); let calc_res = calc_res.calculate(); assert!(calc_res.is_ok()); @@ -458,7 +470,7 @@ mod tests { assert!(res.is_done()); let (_, o) = res.unwrap(); - let calc_res : timetype::TimeType = o.into(); + let calc_res : timetype::TimeType = o.into_timetype().unwrap(); let calc_res = calc_res.calculate(); assert!(calc_res.is_ok()); @@ -476,7 +488,7 @@ mod tests { assert!(res.is_done()); let (_, o) = res.unwrap(); - let calc_res : timetype::TimeType = o.into(); + let calc_res : timetype::TimeType = o.into_timetype().unwrap(); let calc_res = calc_res.calculate(); assert!(calc_res.is_ok()); @@ -494,7 +506,7 @@ mod tests { assert!(res.is_done(), "Not done: {:?}", res.unwrap_err().description()); let (_, o) = res.unwrap(); - let calc_res : timetype::TimeType = o.into(); + let calc_res : timetype::TimeType = o.into_timetype().unwrap(); let calc_res = calc_res.calculate(); assert!(calc_res.is_ok()); @@ -511,7 +523,7 @@ mod tests { println!("{:#?}", o); - let calc_res : timetype::TimeType = o.into(); + let calc_res : timetype::TimeType = o.into_timetype().unwrap(); let calc_res = calc_res.calculate(); assert!(calc_res.is_ok()); @@ -532,7 +544,7 @@ mod tests { assert!(res.is_done()); let (_, o) = res.unwrap(); - let calc_res : ::timetype::TimeType = o.into(); + let calc_res : ::timetype::TimeType = o.into_timetype().unwrap(); let calc_res = calc_res.calculate(); assert!(calc_res.is_ok()); @@ -550,7 +562,7 @@ mod tests { assert!(res.is_done(), "Not done: {:?}", res.unwrap_err().description()); let (_, o) = res.unwrap(); - let calc_res : ::timetype::TimeType = o.into(); + let calc_res : ::timetype::TimeType = o.into_timetype().unwrap(); let calc_res = calc_res.calculate(); assert!(calc_res.is_ok()); @@ -567,7 +579,7 @@ mod tests { println!("{:#?}", o); - let calc_res : ::timetype::TimeType = o.into(); + let calc_res : ::timetype::TimeType = o.into_timetype().unwrap(); println!("{:#?}", calc_res); let calc_res = calc_res.calculate(); diff --git a/src/timetype.rs b/src/timetype.rs index 6725edd..7534b8d 100644 --- a/src/timetype.rs +++ b/src/timetype.rs @@ -438,6 +438,19 @@ impl TimeType { } +/// Helper trait for converting things into a TimeType object +/// +/// Until `TryInto` is stabilized in Rust, we need a helper trait for this. +pub trait IntoTimeType { + fn into_timetype(self) -> Result<TimeType>; +} + +impl IntoTimeType for TimeType { + fn into_timetype(self) -> Result<TimeType> { + Ok(self) + } +} + fn do_calculate(tt: TimeType) -> Result<TimeType> { use timetype::TimeType as TT; @@ -469,7 +482,10 @@ fn end_of_year(tt: TimeType) -> Result<TimeType> { els @ TT::Years(_) | els @ TT::Addition(_, _) | els @ TT::Subtraction(_, _) => Err(KE::from_kind(KEK::CannotCalculateEndOfYearOn(els))), - TT::Moment(m) => Ok(TT::moment(NaiveDate::from_ymd(m.year(), 12, 31).and_hms(0, 0, 0))), + TT::Moment(m) => NaiveDate::from_ymd_opt(m.year(), 12, 31) + .map(|nd| nd.and_hms(0, 0, 0)) + .map(TT::moment) + .ok_or(KEK::OutOfBounds(m.year() as i32, 12, 31, 0, 0, 0).into()), TT::EndOfYear(e) => do_calculate(*e), TT::EndOfMonth(e) => do_calculate(*e), @@ -497,7 +513,10 @@ fn end_of_month(tt: TimeType) -> Result<TimeType> { els @ TT::Subtraction(_, _) => Err(KE::from_kind(KEK::CannotCalculateEndOfMonthOn(els))), TT::Moment(m) => { let last_day = get_num_of_days_in_month(m.year() as i64, m.month() as i64) as u32; - Ok(TT::moment(NaiveDate::from_ymd(m.year(), m.month(), last_day).and_hms(0, 0, 0))) + NaiveDate::from_ymd_opt(m.year(), m.month(), last_day) + .map(|nd| nd.and_hms(0, 0, 0)) + .map(TT::moment) + .ok_or(KEK::OutOfBounds(m.year() as i32, m.month() as u32, last_day, 0, 0, 0).into()) }, TT::EndOfYear(e) => do_calculate(*e), TT::EndOfMonth(e) => do_calculate(*e), @@ -523,9 +542,10 @@ fn end_of_day(tt: TimeType) -> Result<TimeType> { els @ TT::Years(_) | els @ TT::Addition(_, _) | els @ TT::Subtraction(_, _) => Err(KE::from_kind(KEK::CannotCalculateEndOfMonthOn(els))), - TT::Moment(m) => { - Ok(TT::moment(NaiveDate::from_ymd(m.year(), m.month(), m.day()).and_hms(23, 59, 59))) - }, + TT::Moment(m) => NaiveDate::from_ymd_opt(m.year(), m.month(), m.day()) + .map(|nd| nd.and_hms(23, 59, 59)) + .map(TT::moment) + .ok_or(KEK::OutOfBounds(m.year() as i32, m.month() as u32, m.day() as u32, 23, 59, 59).into()), TT::EndOfYear(e) => do_calculate(*e), TT::EndOfMonth(e) => do_calculate(*e), TT::EndOfDay(e) => do_calculate(*e), @@ -550,10 +570,10 @@ fn end_of_hour(tt: TimeType) -> Result<TimeType> { els @ TT::Years(_) | els @ TT::Addition(_, _) | els @ TT::Subtraction(_, _) => Err(KE::from_kind(KEK::CannotCalculateEndOfMonthOn(els))), - TT::Moment(m) => { - Ok(TT::moment(NaiveDate::from_ymd(m.year(), m.month(), m.day()) - .and_hms(m.hour(), 59, 59))) - }, + TT::Moment(m) => NaiveDate::from_ymd_opt(m.year(), m.month(), m.day()) + .and_then(|nd| nd.and_hms_opt(m.hour(), 59, 59)) + .map(TT::moment) + .ok_or(KEK::OutOfBounds(m.year() as i32, m.month() as u32, m.day() as u32, m.hour() as u32, 59, 59).into()), TT::EndOfYear(e) => do_calculate(*e), TT::EndOfMonth(e) => do_calculate(*e), TT::EndOfDay(e) => do_calculate(*e), @@ -578,10 +598,10 @@ fn end_of_minute(tt: TimeType) -> Result<TimeType> { els @ TT::Years(_) | els @ TT::Addition(_, _) | els @ TT::Subtraction(_, _) => Err(KE::from_kind(KEK::CannotCalculateEndOfMonthOn(els))), - TT::Moment(m) => { - Ok(TT::moment(NaiveDate::from_ymd(m.year(), m.month(), m.day()) - .and_hms(m.hour(), m.minute(), 59))) - }, + TT::Moment(m) => NaiveDate::from_ymd_opt(m.year(), m.month(), m.day()) + .and_then(|nd| nd.and_hms_opt(m.hour(), m.minute(), 59)) + .map(TT::moment) + .ok_or(KEK::OutOfBounds(m.year() as i32, m.month() as u32, m.day() as u32, m.hour() as u32, m.minute() as u32, 59 as u32).into()), TT::EndOfYear(e) => do_calculate(*e), TT::EndOfMonth(e) => do_calculate(*e), TT::EndOfDay(e) => do_calculate(*e), @@ -776,8 +796,10 @@ fn add_to_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_add(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Minutes(a) => { @@ -790,8 +812,10 @@ fn add_to_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_add(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Hours(a) => { @@ -804,8 +828,10 @@ fn add_to_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_add(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Days(a) => { @@ -818,8 +844,10 @@ fn add_to_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_add(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Months(a) => { @@ -832,8 +860,10 @@ fn add_to_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_add(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Years(a) => { @@ -846,8 +876,10 @@ fn add_to_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_add(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Moment(m) => Err(KE::from_kind(KEK::CannotAdd(TT::Moment(mom), TT::Moment(m)))), @@ -1045,8 +1077,10 @@ fn sub_from_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_sub(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Minutes(a) => { @@ -1059,8 +1093,10 @@ fn sub_from_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_sub(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Hours(a) => { @@ -1073,8 +1109,10 @@ fn sub_from_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_sub(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Days(a) => { @@ -1087,8 +1125,10 @@ fn sub_from_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_sub(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Months(a) => { @@ -1101,8 +1141,10 @@ fn sub_from_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_sub(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Years(a) => { @@ -1115,8 +1157,10 @@ fn sub_from_moment(mom: NaiveDateTime, tt: TimeType) -> Result<TimeType> { let (y, mo, d, h, mi, s) = adjust_times_sub(y, mo, d, h, mi, s); - let tt = NaiveDate::from_ymd(y as i32, mo as u32, d as u32) - .and_hms(h as u32, mi as u32, s as u32); + let tt = NaiveDate::from_ymd_opt(y as i32, mo as u32, d as u32) + .and_then(|nd| nd.and_hms_opt(h as u32, mi as u32, s as u32)) + .ok_or(KEK::OutOfBounds(y as i32, mo as u32, h as u32, h as u32, mi as u32, s as u32).into()) + .map_err(KE::from_kind)?; Ok(TimeType::moment(tt)) }, TT::Moment(m) => Err(KE::from_kind(KEK::CannotSub(TT::Moment(mom), TT::Moment(m)))), diff --git a/src/util.rs b/src/util.rs index 7730b2b..1ed9a7a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,16 +2,16 @@ pub fn adjust_times_add(mut y: i64, mut mo: i64, mut d: i64, mut h: i64, mut mi: i64, mut s: i64) -> (i64, i64, i64, i64, i64, i64) { + // Subtract $border from the $base as long as the $base is bigger or equal to the $border. + // The number of subtractions are added to $next. macro_rules! fix { { $base:ident, $border:expr, $next:ident } => { - while $base >= $border { - $next += 1; - $base -= $border; - } + $next += ($base - ($base % $border)) / $border; + $base = $base % $border; } } |