diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2017-09-26 18:05:52 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2017-09-26 18:07:52 +0200 |
commit | 7f919334902d8c8d0064a8c1792ad1629555952a (patch) | |
tree | 4e89589a564cdeca88b79bb83e046028dd80f36a | |
parent | 874fcc34d50d6d69e30cc3ce6ef14e617354fe4c (diff) |
Make Iter auto-calculating, eliminate CalculatingIter
It turns out that using a cheap iterator which only wraps objects makes
the stack overflow with a very basic query:
today()
.yearly(1)
.unwrap()
.every(::indicator::Day::Monday)
.every(::indicator::Month::January)
.collect::<Vec<_>>()
So here we cgo and optimize the Iter type to automatically calculate all
the things right away. This makes it a bit more expensive to call, of
course, but is better than overflowing.
-rw-r--r-- | src/iter.rs | 68 |
1 files changed, 16 insertions, 52 deletions
diff --git a/src/iter.rs b/src/iter.rs index 0b8c6a0..9713e51 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -39,13 +39,24 @@ impl Iter { } /// Skip one `next()` call - pub fn skip(&mut self) { + pub fn skip(&mut self) -> Result<()> { self.base += self.increment.clone(); + self.recalculate() } /// Redo the latest `next()` call with the next `next()` call - pub fn rollback(&mut self) { + pub fn rollback(&mut self) -> Result<()> { self.base -= self.increment.clone(); + self.recalculate() + } + + fn recalculate(&mut self) -> Result<()> { + self.base + .clone() + .calculate() + .map(|res| { + self.base = res; + }) } } @@ -61,51 +72,14 @@ impl Iter { /// Be warned. /// impl Iterator for Iter { - type Item = TimeType; - - fn next(&mut self) -> Option<Self::Item> { - self.skip(); - Some(self.base.clone()) - } - -} - -/// An iterator type that calls `calculate()` on the `TimeType` instances which are yielded by its -/// inner iterator type. -pub struct CalculatingIter<I>(I) - where I: Iterator<Item = TimeType>; - -impl<I> CalculatingIter<I> - where I: Iterator<Item = TimeType> -{ - pub fn new(i: I) -> CalculatingIter<I> { - CalculatingIter(i) - } -} - -impl<I> Iterator for CalculatingIter<I> - where I: Iterator<Item = TimeType> -{ type Item = Result<TimeType>; fn next(&mut self) -> Option<Self::Item> { - self.0.next().map(TimeType::calculate) + Some(self.skip().map(|_| self.base.clone())) } } -pub trait IntoCalculatingIter : Iterator<Item = TimeType> + Sized { - fn calculate(self) -> CalculatingIter<Self>; -} - -impl<I> IntoCalculatingIter for I - where I: Iterator<Item = TimeType> -{ - fn calculate(self) -> CalculatingIter<Self> { - CalculatingIter(self) - } -} - pub struct FilterIter<I, M>(I, M) where I: Iterator<Item = Result<TimeType>>, M: Matcher; @@ -294,7 +268,6 @@ pub mod extensions { use super::*; use timetype::TimeType as TT; use chrono::NaiveDate as ND; - use iter::IntoCalculatingIter; fn ymd_hms(y: i32, m: u32, d: u32, h: u32, mi: u32, s: u32) -> TT { TT::moment(ND::from_ymd(y, m, d).and_hms(h, mi, s)) @@ -305,7 +278,6 @@ pub mod extensions { let minutes = ymd_hms(2000, 1, 1, 0, 0, 0) .minutely(1) .unwrap() - .calculate() .take(5) .collect::<Vec<_>>(); @@ -321,7 +293,6 @@ pub mod extensions { let minutes = ymd_hms(2000, 1, 1, 0, 0, 0) .hourly(1) .unwrap() - .calculate() .take(5) .collect::<Vec<_>>(); @@ -337,7 +308,6 @@ pub mod extensions { let minutes = ymd_hms(2000, 1, 1, 1, 0, 0) .weekly(1) .unwrap() - .calculate() .take(5) .collect::<Vec<_>>(); @@ -353,7 +323,6 @@ pub mod extensions { let minutes = ymd_hms(2000, 1, 1, 0, 0, 0) .monthly(1) .unwrap() - .calculate() .take(5) .collect::<Vec<_>>(); @@ -369,7 +338,6 @@ pub mod extensions { let minutes = ymd_hms(2000, 1, 1, 0, 0, 0) .yearly(1) .unwrap() - .calculate() .take(5) .collect::<Vec<_>>(); @@ -387,7 +355,6 @@ pub mod extensions { #[cfg(test)] mod type_tests { use super::*; - use super::IntoCalculatingIter; use super::extensions::*; #[test] @@ -396,7 +363,6 @@ mod type_tests { let _ = TimeType::today() .yearly(1) .unwrap() - .calculate() .every(::indicator::Day::Monday); } @@ -406,7 +372,6 @@ mod type_tests { let _ = TimeType::today() .yearly(1) // collecting makes us stack-overflow because of the heavy filtering! .unwrap() - .calculate() .every(::indicator::Day::Monday) .every(::indicator::Month::January); } @@ -415,7 +380,6 @@ mod type_tests { #[cfg(all(feature = "with-filters", test))] mod type_tests_filter_interface { use super::*; - use super::IntoCalculatingIter; use super::extensions::*; #[test] @@ -424,8 +388,8 @@ mod type_tests_filter_interface { let _ = TimeType::today() .yearly(1) .unwrap() - .calculate() - .every(::indicator::Day::Monday.or(::indicator::Month::January)); + .every(::indicator::Day::Monday.or(::indicator::Month::January)) + .collect::<Vec<_>>(); } } |