summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2017-11-24 16:05:34 +0100
committerGitHub <noreply@github.com>2017-11-24 16:05:34 +0100
commit0ce2af172f7249d25c2e9f75f9324eab1a029a80 (patch)
tree3be3d1f33b9f4a81432ec78e1d6368f5131da363
parent9b990ff630864c5245328c015cab94af98ae3f0a (diff)
parenta19b88d52c54229faaceb06a470e7c38f23805cf (diff)
Merge pull request #15 from matthiasbeyer/fix-panic
Fix panics
-rw-r--r--Cargo.toml2
-rw-r--r--fuzz/.gitignore4
-rw-r--r--fuzz/Cargo.toml22
-rw-r--r--fuzz/fuzz_targets/parse.rs9
-rw-r--r--src/error.rs5
-rw-r--r--src/lib.rs2
-rw-r--r--src/parser/iterator.rs9
-rw-r--r--src/parser/mod.rs12
-rw-r--r--src/parser/timetype.rs138
-rw-r--r--src/timetype.rs118
-rw-r--r--src/util.rs8
11 files changed, 215 insertions, 114 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 12a610c..b4c5d79 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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")
diff --git a/src/lib.rs b/src/lib.rs
index d39493a..d8e1d7c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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;
}
}