diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/error.rs | 5 | ||||
-rw-r--r-- | src/iter.rs | 88 | ||||
-rw-r--r-- | src/parser.rs | 312 |
3 files changed, 399 insertions, 6 deletions
diff --git a/src/error.rs b/src/error.rs index 653b368..b9e7949 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) } + NotADateInsideIterator { + description("Cannot calculate date for iterator") + display("Cannot calculate date for iterator") + } + UnknownParserError { description("Unknown parser error") display("Unknown parser error") diff --git a/src/iter.rs b/src/iter.rs index 64c6ba1..b253f9f 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -9,6 +9,7 @@ use error::Result; use timetype::TimeType; use matcher::Matcher; +#[derive(Debug)] pub struct Iter { base: TimeType, increment: TimeType, @@ -80,6 +81,7 @@ impl Iterator for Iter { } +#[derive(Debug)] pub struct FilterIter<I, M>(I, M) where I: Iterator<Item = Result<TimeType>>, M: Matcher; @@ -127,6 +129,7 @@ impl<I, M> EveryFilter<M> for I } } +#[derive(Debug)] pub struct WithoutIter<I, M>(I, M) where I: Iterator<Item = Result<TimeType>>, M: Matcher; @@ -174,6 +177,7 @@ impl<I, M> WithoutFilter<M> for I } } +#[derive(Debug)] pub struct UntilIter<I>(I, NaiveDateTime) where I: Iterator<Item = Result<TimeType>>; @@ -222,6 +226,54 @@ impl<I> Until for I } } +#[derive(Debug)] +pub struct TimesIter<I> + where I: Iterator<Item = Result<TimeType>> +{ + inner: I, + times: i64, + count: i64, +} + +impl<I> TimesIter<I> + where I: Iterator<Item = Result<TimeType>> +{ + fn new(i: I, times: i64) -> TimesIter<I> { + TimesIter { + inner: i, + times: times, + count: 0, + } + } +} + +impl<I> Iterator for TimesIter<I> + where I: Iterator<Item = Result<TimeType>> +{ + type Item = Result<TimeType>; + + fn next(&mut self) -> Option<Self::Item> { + if self.times == self.count { + None + } else { + self.count += 1; + self.inner.next() + } + } +} + +pub trait Times : Iterator<Item = Result<TimeType>> + Sized { + fn times(self, i64) -> TimesIter<Self>; +} + +impl<I> Times for I + where I: Iterator<Item = Result<TimeType>> +{ + fn times(self, times: i64) -> TimesIter<Self> { + TimesIter::new(self, times) + } +} + pub mod extensions { use timetype::TimeType as TT; use super::Iter; @@ -528,5 +580,41 @@ mod test_until { assert!(v.is_empty()); } + #[test] + fn test_until_1() { + let end = (TimeType::today() + TimeType::days(2)) + .calculate() + .unwrap() + .get_moment() + .unwrap() + .clone(); + + let v = TimeType::today() + .daily(1) + .unwrap() + .until(end) + .collect::<Vec<_>>(); + + assert_eq!(v.len(), 1); + } + + #[test] + fn test_until_2() { + let end = (TimeType::today() + TimeType::days(2)) + .calculate() + .unwrap() + .get_moment() + .unwrap() + .clone(); + + let v = TimeType::today() + .hourly(1) + .unwrap() + .until(end) + .collect::<Vec<_>>(); + + assert_eq!(v.len(), 48 - 1); // -1 because we do not start to iterate with 0, but 1 + } + } diff --git a/src/parser.rs b/src/parser.rs index 7a2e7a1..723f4f3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -50,6 +50,8 @@ use std::str::FromStr; use chrono::NaiveDate; use timetype; +use iter; +use error; named!(integer<i64>, alt!( map_res!( @@ -345,18 +347,92 @@ pub enum UntilSpec { } named!(iterator<Iterator>, do_parse!( - d: date >> - spec: iter_spec >> - until: opt!(until_spec) >> + opt!(sp) >> d: date >> + opt!(sp) >> spec: iter_spec >> + opt!(sp) >> until: opt!(complete!(until_spec)) >> (Iterator(d, spec, until)) )); #[derive(Debug, PartialEq, Eq)] pub struct Iterator(Date, Iterspec, Option<UntilSpec>); -impl Into<timetype::TimeType> for Iterator { - fn into(self) -> timetype::TimeType { - unimplemented!() +impl Iterator { + pub fn into_user_iterator(self) -> error::Result<UserIterator<iter::Iter>> { + use iter::Times; + use iter::Until; + + let unit_to_amount = |i, unit| match unit { + Unit::Second => timetype::TimeType::seconds(i), + Unit::Minute => timetype::TimeType::minutes(i), + Unit::Hour => timetype::TimeType::hours(i), + Unit::Day => timetype::TimeType::days(i), + Unit::Week => timetype::TimeType::weeks(i), + Unit::Month => timetype::TimeType::months(i), + Unit::Year => timetype::TimeType::years(i), + }; + + let recur = match self.1 { + Iterspec::Every(i, unit) => unit_to_amount(i, unit), + Iterspec::Secondly => unit_to_amount(1, Unit::Second), + Iterspec::Minutely => unit_to_amount(1, Unit::Minute), + Iterspec::Hourly => unit_to_amount(1, Unit::Hour), + Iterspec::Daily => unit_to_amount(1, Unit::Day), + Iterspec::Weekly => unit_to_amount(1, Unit::Week), + Iterspec::Monthly => unit_to_amount(1, Unit::Month), + Iterspec::Yearly => unit_to_amount(1, Unit::Year), + }; + + let into_ndt = |e: timetype::TimeType| try!(e.calculate()) + .get_moment() + .ok_or(error::KairosErrorKind::NotADateInsideIterator) + .map(Clone::clone); + + match self.2 { + Some(UntilSpec::Exact(e)) => { + let base = try!(into_ndt(self.0.into())); + let e = try!(into_ndt(e.into())); + + iter::Iter::build(base, recur) + .map(|it| UserIterator::UntilIterator(it.until(e))) + }, + + Some(UntilSpec::Times(i)) => { + let base = try!(into_ndt(self.0.into())); + iter::Iter::build(base, recur) + .map(|it| it.times(i)) + .map(UserIterator::TimesIter) + }, + + None => { + let base = try!(into_ndt(self.0.into())); + iter::Iter::build(base, recur) + .map(UserIterator::Iterator) + }, + } + } +} + +// names are hard +#[derive(Debug)] +pub enum UserIterator<I> + where I: ::std::iter::Iterator<Item = error::Result<timetype::TimeType>> +{ + Iterator(iter::Iter), + TimesIter(iter::TimesIter<I>), + UntilIterator(iter::UntilIter<I>) +} + +impl<I> ::std::iter::Iterator for UserIterator<I> + where I: ::std::iter::Iterator<Item = error::Result<timetype::TimeType>> +{ + type Item = error::Result<timetype::TimeType>; + + fn next(&mut self) -> Option<Self::Item> { + match *self { + UserIterator::Iterator(ref mut i) => i.next(), + UserIterator::TimesIter(ref mut i) => i.next(), + UserIterator::UntilIterator(ref mut i) => i.next(), + } } } @@ -698,5 +774,229 @@ mod tests { assert_eq!(calc_res.get_years(), 0); } + #[test] + fn test_iterator_1() { + let res = iterator(&b"2017-01-01 hourly"[..]); + assert!(res.is_done(), format!("Not done: {:?}", res)); + let (_, i) = res.unwrap(); + println!("{:#?}", i); + + let ui : Result<UserIterator<iter::Iter>, _> = i.into_user_iterator(); + assert!(ui.is_ok(), "Not okay: {:#?}", ui); + let mut ui = ui.unwrap(); + + for hour in 1..10 { // 10 is randomly chosen (fair dice roll... ) + let n = ui.next().unwrap(); + assert!(n.is_ok(), "Not ok: {:#?}", n); + let tt = n.unwrap(); + assert_eq!(tt.get_moment().unwrap().year() , 2017); + assert_eq!(tt.get_moment().unwrap().month() , 01); + assert_eq!(tt.get_moment().unwrap().day() , 01); + assert_eq!(tt.get_moment().unwrap().hour() , hour); + assert_eq!(tt.get_moment().unwrap().minute(), 00); + assert_eq!(tt.get_moment().unwrap().second(), 00); + } + } + + #[test] + fn test_iterator_2() { + let res = iterator(&b"2017-01-01 every 2mins"[..]); + assert!(res.is_done(), format!("Not done: {:?}", res)); + let (_, i) = res.unwrap(); + println!("{:#?}", i); + + let ui : Result<UserIterator<iter::Iter>, _> = i.into_user_iterator(); + assert!(ui.is_ok(), "Not okay: {:#?}", ui); + let mut ui = ui.unwrap(); + + for min in (1..60).into_iter().filter(|n| n % 2 == 0) { + let n = ui.next().unwrap(); + assert!(n.is_ok(), "Not ok: {:#?}", n); + let tt = n.unwrap(); + assert_eq!(tt.get_moment().unwrap().year() , 2017); + assert_eq!(tt.get_moment().unwrap().month() , 01); + assert_eq!(tt.get_moment().unwrap().day() , 01); + assert_eq!(tt.get_moment().unwrap().hour() , 00); + assert_eq!(tt.get_moment().unwrap().minute(), min); + assert_eq!(tt.get_moment().unwrap().second(), 00); + } + } + + #[test] + fn test_iterator_3() { + let res = iterator(&b"2017-01-01 daily"[..]); + assert!(res.is_done(), format!("Not done: {:?}", res)); + let (_, i) = res.unwrap(); + println!("{:#?}", i); + + let ui : Result<UserIterator<iter::Iter>, _> = i.into_user_iterator(); + assert!(ui.is_ok(), "Not okay: {:#?}", ui); + let mut ui = ui.unwrap(); + + for day in 2..30 { + let n = ui.next().unwrap(); + assert!(n.is_ok(), "Not ok: {:#?}", n); + let tt = n.unwrap(); + assert_eq!(tt.get_moment().unwrap().year() , 2017); + assert_eq!(tt.get_moment().unwrap().month() , 01); + assert_eq!(tt.get_moment().unwrap().day() , day); + assert_eq!(tt.get_moment().unwrap().hour() , 00); + assert_eq!(tt.get_moment().unwrap().minute(), 00); + assert_eq!(tt.get_moment().unwrap().second(), 00); + } + } + + #[test] + fn test_iterator_4() { + let res = iterator(&b"2017-01-01 weekly"[..]); + assert!(res.is_done(), format!("Not done: {:?}", res)); + let (_, i) = res.unwrap(); + println!("{:#?}", i); + + let ui : Result<UserIterator<iter::Iter>, _> = i.into_user_iterator(); + assert!(ui.is_ok(), "Not okay: {:#?}", ui); + let mut ui = ui.unwrap(); + + for week in 1..3 { + let n = ui.next().unwrap(); + assert!(n.is_ok(), "Not ok: {:#?}", n); + let tt = n.unwrap(); + assert_eq!(tt.get_moment().unwrap().year() , 2017); + assert_eq!(tt.get_moment().unwrap().month() , 01); + assert_eq!(tt.get_moment().unwrap().day() , 01 + (week * 7)); + assert_eq!(tt.get_moment().unwrap().hour() , 00); + assert_eq!(tt.get_moment().unwrap().minute(), 00); + assert_eq!(tt.get_moment().unwrap().second(), 00); + } + } + + #[test] + fn test_until_spec_1() { + let res = until_spec(&b"until 2017-01-01T05:00:00"[..]); + assert!(res.is_done(), format!("Not done: {:?}", res)); + let (_, i) = res.unwrap(); + println!("{:#?}", i); + } + + #[test] + fn test_until_iterator_1() { + let res = iterator(&b"2017-01-01 hourly until 2017-01-01T05:00:00"[..]); + assert!(res.is_done(), format!("Not done: {:?}", res)); + let (_, i) = res.unwrap(); + println!("{:#?}", i); + + let ui : Result<UserIterator<iter::Iter>, _> = i.into_user_iterator(); + assert!(ui.is_ok(), "Not okay: {:#?}", ui); + let mut ui = ui.unwrap(); + println!("Okay: {:#?}", ui); + + for hour in 1..10 { // 10 is randomly chosen (fair dice roll... ) + if hour > 5 - 1 { + let n = ui.next(); + assert!(n.is_none(), "Is Some, should be None: {:?}", n); + return; + } else { + let n = ui.next().unwrap(); + assert!(n.is_ok(), "Not ok: {:#?}", n); + let tt = n.unwrap(); + assert_eq!(tt.get_moment().unwrap().year() , 2017); + assert_eq!(tt.get_moment().unwrap().month() , 01); + assert_eq!(tt.get_moment().unwrap().day() , 01); + assert_eq!(tt.get_moment().unwrap().hour() , hour); + assert_eq!(tt.get_moment().unwrap().minute(), 00); + assert_eq!(tt.get_moment().unwrap().second(), 00); + } + } + } + + #[test] + fn test_until_iterator_2() { + let res = iterator(&b"2017-01-01 every 2mins until 2017-01-01T00:10:00"[..]); + assert!(res.is_done(), format!("Not done: {:?}", res)); + let (_, i) = res.unwrap(); + println!("{:#?}", i); + + let ui : Result<UserIterator<iter::Iter>, _> = i.into_user_iterator(); + assert!(ui.is_ok(), "Not okay: {:#?}", ui); + let mut ui = ui.unwrap(); + + for min in (1..60).into_iter().filter(|n| n % 2 == 0) { + if min > 10 - 1 { + let n = ui.next(); + assert!(n.is_none(), "Is Some, should be None: {:?}", n); + return; + } else { + let n = ui.next().unwrap(); + assert!(n.is_ok(), "Not ok: {:#?}", n); + let tt = n.unwrap(); + assert_eq!(tt.get_moment().unwrap().year() , 2017); + assert_eq!(tt.get_moment().unwrap().month() , 01); + assert_eq!(tt.get_moment().unwrap().day() , 01); + assert_eq!(tt.get_moment().unwrap().hour() , 00); + assert_eq!(tt.get_moment().unwrap().minute(), min); + assert_eq!(tt.get_moment().unwrap().second(), 00); + } + } + } + + #[test] + fn test_until_iterator_3() { + let res = iterator(&b"2017-01-01 daily until 2017-01-05"[..]); + assert!(res.is_done(), format!("Not done: {:?}", res)); + let (_, i) = res.unwrap(); + println!("{:#?}", i); + + let ui : Result<UserIterator<iter::Iter>, _> = i.into_user_iterator(); + assert!(ui.is_ok(), "Not okay: {:#?}", ui); + let mut ui = ui.unwrap(); + + for day in 2..30 { + if day > 5 - 1 { + let n = ui.next(); + assert!(n.is_none(), "Is Some, should be None: {:?}", n); + return; + } else { + let n = ui.next().unwrap(); + assert!(n.is_ok(), "Not ok: {:#?}", n); + let tt = n.unwrap(); + assert_eq!(tt.get_moment().unwrap().year() , 2017); + assert_eq!(tt.get_moment().unwrap().month() , 01); + assert_eq!(tt.get_moment().unwrap().day() , day); + assert_eq!(tt.get_moment().unwrap().hour() , 00); + assert_eq!(tt.get_moment().unwrap().minute(), 00); + assert_eq!(tt.get_moment().unwrap().second(), 00); + } + } + } + + #[test] + fn test_until_iterator_4() { + let res = iterator(&b"2017-01-01 weekly until 2017-01-14"[..]); + assert!(res.is_done(), format!("Not done: {:?}", res)); + let (_, i) = res.unwrap(); + println!("{:#?}", i); + + let ui : Result<UserIterator<iter::Iter>, _> = i.into_user_iterator(); + assert!(ui.is_ok(), "Not okay: {:#?}", ui); + let mut ui = ui.unwrap(); + + for week in 1..3 { + if (week * 7 + 1) > 14 { + let n = ui.next(); + assert!(n.is_none(), "Is Some, should be None: {:?}", n); + return; + } else { + let n = ui.next().unwrap(); + assert!(n.is_ok(), "Not ok: {:#?}", n); + let tt = n.unwrap(); + assert_eq!(tt.get_moment().unwrap().year() , 2017); + assert_eq!(tt.get_moment().unwrap().month() , 01); + assert_eq!(tt.get_moment().unwrap().day() , 01 + (week * 7)); + assert_eq!(tt.get_moment().unwrap().hour() , 00); + assert_eq!(tt.get_moment().unwrap().minute(), 00); + assert_eq!(tt.get_moment().unwrap().second(), 00); + } + } + } } |