summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFredrik Meringdal <fredrikmeringdal@Fredriks-MacBook-Pro.local>2021-02-03 17:55:43 +0100
committerFredrik Meringdal <fredrikmeringdal@Fredriks-MacBook-Pro.local>2021-02-03 17:55:43 +0100
commit61aac0d2773f7a073b63661ec150954414f5696e (patch)
tree739b82650bafd04cdd29ca7aa4f2af94c6afb1b8
parent4b12b6328955612dcb4a248a14d64864d9aecdf1 (diff)
downloadrust_rrule-61aac0d2773f7a073b63661ec150954414f5696e.zip
iterator for rrule
-rw-r--r--src/iter/iter_v2.rs151
-rw-r--r--src/iter/iterinfo.rs12
-rw-r--r--src/iter/mod.rs258
-rw-r--r--src/rrule.rs59
-rw-r--r--src/rrule_iter.rs64
5 files changed, 337 insertions, 207 deletions
diff --git a/src/iter/iter_v2.rs b/src/iter/iter_v2.rs
new file mode 100644
index 0000000..609206d
--- /dev/null
+++ b/src/iter/iter_v2.rs
@@ -0,0 +1,151 @@
+use crate::{datetime::Time, Frequenzy};
+use chrono::prelude::*;
+use chrono_tz::Tz;
+
+use super::{build_poslist, from_ordinal, increment_counter_date, remove_filtered_days, IterInfo};
+
+pub struct RRuleIter {
+ pub counter_date: DateTime<Tz>,
+ pub ii: IterInfo,
+ pub timeset: Vec<Time>,
+ pub remain: Vec<DateTime<Tz>>,
+ pub finished: bool,
+}
+
+impl Iterator for RRuleIter {
+ type Item = DateTime<Tz>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if !self.finished {
+ generate(self);
+ }
+
+ if self.remain.is_empty() {
+ return None;
+ }
+
+ Some(self.remain.remove(0))
+ }
+}
+
+pub fn generate(iter: &mut RRuleIter) {
+ let options = iter.ii.options;
+ let count = options.count.unwrap_or(0);
+
+ while iter.remain.is_empty() {
+ let (dayset, start, end) = iter.ii.getdayset(
+ &iter.ii.options.freq,
+ iter.counter_date.year() as isize,
+ iter.counter_date.month() as usize,
+ iter.counter_date.day() as usize,
+ );
+
+ let mut dayset = dayset
+ .into_iter()
+ .map(|s| Some(s as isize))
+ .collect::<Vec<Option<isize>>>();
+
+ let filtered = remove_filtered_days(&mut dayset, start, end, &iter.ii);
+
+ if options.bysetpos.len() > 0 {
+ let poslist = build_poslist(
+ &options.bysetpos,
+ &iter.timeset,
+ start,
+ end,
+ &iter.ii,
+ &dayset,
+ &options.tzid,
+ );
+
+ for j in 0..poslist.len() {
+ let res = poslist[j];
+ if options.until.is_some() && res > options.until.unwrap() {
+ // return iter_result.get_value();
+ continue; // or break ?
+ }
+
+ if res >= options.dtstart {
+ iter.remain.push(res);
+
+ if count > 0 {
+ count -= 1;
+ if count == 0 {
+ return;
+ }
+ }
+ }
+ }
+ } else {
+ for j in start..end {
+ let current_day = dayset[j];
+ if current_day.is_none() {
+ continue;
+ }
+
+ let current_day = current_day.unwrap();
+ let date =
+ from_ordinal(iter.ii.yearordinal().unwrap() + current_day, &options.tzid);
+ for k in 0..iter.timeset.len() {
+ let res = options
+ .tzid
+ .ymd(date.year(), date.month(), date.day())
+ .and_hms(
+ iter.timeset[k].hour as u32,
+ iter.timeset[k].minute as u32,
+ iter.timeset[k].second as u32,
+ );
+ if options.until.is_some() && res > options.until.unwrap() {
+ return;
+ }
+ if res >= options.dtstart {
+ iter.remain.push(res);
+ // let (add, continue_iterator) = iter_result.accept(&res);
+ // if add {
+ // iter.remain.push(res);
+ // }
+ // if !continue_iterator {
+ // return;
+ // }
+
+ if count > 0 {
+ count -= 1;
+ if count == 0 {
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if options.interval == 0 {
+ return;
+ }
+
+ // Handle frequency and interval
+ iter.counter_date = increment_counter_date(iter.counter_date, &options, filtered);
+
+ if iter.counter_date.year() > 2200 {
+ return;
+ }
+
+ if options.freq == Frequenzy::Hourly
+ || options.freq == Frequenzy::Minutely
+ || options.freq == Frequenzy::Secondly
+ {
+ iter.timeset = iter.ii.gettimeset(
+ &options.freq,
+ iter.counter_date.hour() as usize,
+ iter.counter_date.minute() as usize,
+ iter.counter_date.second() as usize,
+ 0,
+ );
+ }
+
+ iter.ii.rebuild(
+ iter.counter_date.year() as isize,
+ iter.counter_date.month() as usize,
+ );
+ }
+}
diff --git a/src/iter/iterinfo.rs b/src/iter/iterinfo.rs
index 7c47645..048632b 100644
--- a/src/iter/iterinfo.rs
+++ b/src/iter/iterinfo.rs
@@ -5,15 +5,15 @@ use crate::iter::yearinfo::{rebuild_year, YearInfo};
use crate::options::{Frequenzy, ParsedOptions};
use chrono::prelude::*;
-pub struct IterInfo<'a> {
+pub struct IterInfo {
pub yearinfo: Option<YearInfo>,
pub monthinfo: Option<MonthInfo>,
pub eastermask: Option<Vec<isize>>,
- options: &'a ParsedOptions,
+ pub options: ParsedOptions,
}
-impl<'a> IterInfo<'a> {
- pub fn new(options: &'a ParsedOptions) -> Self {
+impl IterInfo {
+ pub fn new(options: ParsedOptions) -> Self {
Self {
options,
yearinfo: None,
@@ -24,7 +24,7 @@ impl<'a> IterInfo<'a> {
pub fn rebuild(&mut self, year: isize, month: usize) {
if self.monthinfo.is_none() || year != self.monthinfo.as_ref().unwrap().lastyear {
- self.yearinfo = Some(rebuild_year(year as i32, self.options));
+ self.yearinfo = Some(rebuild_year(year as i32, &self.options));
}
if !self.options.bynweekday.is_empty()
@@ -38,7 +38,7 @@ impl<'a> IterInfo<'a> {
yearinfo.yearlen,
&yearinfo.mrange,
&yearinfo.wdaymask,
- self.options,
+ &self.options,
));
}
}
diff --git a/src/iter/mod.rs b/src/iter/mod.rs
index dc7c51d..419dcbd 100644
--- a/src/iter/mod.rs
+++ b/src/iter/mod.rs
@@ -1,11 +1,13 @@
mod iterinfo;
mod monthinfo;
mod yearinfo;
-use iterinfo::IterInfo;
+pub use iterinfo::IterInfo;
mod poslist;
use poslist::build_poslist;
mod easter;
+mod iter_v2;
mod masks;
+pub use iter_v2::{generate, RRuleIter};
use crate::datetime::{from_ordinal, get_weekday_val, DTime, Time};
use crate::options::*;
@@ -15,134 +17,133 @@ use chrono::prelude::*;
use chrono::Duration;
pub trait IterResult {
- fn accept(&mut self, date: DTime) -> bool;
- fn get_value(&self) -> Vec<DTime>;
+ fn accept(&self, date: &DTime) -> (bool, bool);
}
-pub fn iter<T: IterResult>(iter_result: &mut T, options: &mut ParsedOptions) -> Vec<DTime> {
- if (options.count.is_some() && options.count.unwrap() == 0) || options.interval == 0 {
- return iter_result.get_value();
- }
-
- let mut counter_date = options.dtstart;
- let mut ii = IterInfo::new(options);
- ii.rebuild(counter_date.year() as isize, counter_date.month() as usize);
-
- let mut timeset = make_timeset(&ii, &counter_date, options);
- let mut count = match options.count {
- Some(count) => count,
- _ => 0,
- };
-
- loop {
- let (dayset, start, end) = ii.getdayset(
- &options.freq,
- counter_date.year() as isize,
- counter_date.month() as usize,
- counter_date.day() as usize,
- );
-
- let mut dayset = dayset
- .into_iter()
- .map(|s| Some(s as isize))
- .collect::<Vec<Option<isize>>>();
-
- let filtered = remove_filtered_days(&mut dayset, start, end, &ii, options);
-
- if not_empty(&options.bysetpos) {
- let poslist = build_poslist(
- &options.bysetpos,
- &timeset,
- start,
- end,
- &ii,
- &dayset,
- &options.tzid,
- );
-
- for j in 0..poslist.len() {
- let res = poslist[j];
- if options.until.is_some() && res > options.until.unwrap() {
- return iter_result.get_value();
- }
-
- if res >= options.dtstart {
- if !iter_result.accept(res) {
- return iter_result.get_value();
- }
-
- if count > 0 {
- count -= 1;
- if count == 0 {
- return iter_result.get_value();
- }
- }
- }
- }
- } else {
- for j in start..end {
- let current_day = dayset[j];
- if current_day.is_none() {
- continue;
- }
-
- let current_day = current_day.unwrap();
- let date = from_ordinal(ii.yearordinal().unwrap() + current_day, &options.tzid);
- for k in 0..timeset.len() {
- let res = options
- .tzid
- .ymd(date.year(), date.month(), date.day())
- .and_hms(
- timeset[k].hour as u32,
- timeset[k].minute as u32,
- timeset[k].second as u32,
- );
- if options.until.is_some() && res > options.until.unwrap() {
- return iter_result.get_value();
- }
- if res >= options.dtstart {
- if !iter_result.accept(res) {
- return iter_result.get_value();
- }
-
- if count > 0 {
- count -= 1;
- if count == 0 {
- return iter_result.get_value();
- }
- }
- }
- }
- }
- }
-
- if options.interval == 0 {
- return iter_result.get_value();
- }
-
- // Handle frequency and interval
- counter_date = increment_counter_date(counter_date, options, filtered);
-
- if counter_date.year() > 2200 {
- return iter_result.get_value();
- }
-
- if options.freq == Frequenzy::Hourly
- || options.freq == Frequenzy::Minutely
- || options.freq == Frequenzy::Secondly
- {
- timeset = ii.gettimeset(
- &options.freq,
- counter_date.hour() as usize,
- counter_date.minute() as usize,
- counter_date.second() as usize,
- 0,
- );
- }
-
- ii.rebuild(counter_date.year() as isize, counter_date.month() as usize);
- }
-}
+// pub fn iter<T: IterResult>(iter_result: &mut T, options: &mut ParsedOptions) -> Vec<DTime> {
+// if (options.count.is_some() && options.count.unwrap() == 0) || options.interval == 0 {
+// return iter_result.get_value();
+// }
+
+// let mut counter_date = options.dtstart;
+// let mut ii = IterInfo::new(options);
+// ii.rebuild(counter_date.year() as isize, counter_date.month() as usize);
+
+// let mut timeset = make_timeset(&ii, &counter_date, options);
+// let mut count = match options.count {
+// Some(count) => count,
+// _ => 0,
+// };
+
+// loop {
+// let (dayset, start, end) = ii.getdayset(
+// &options.freq,
+// counter_date.year() as isize,
+// counter_date.month() as usize,
+// counter_date.day() as usize,
+// );
+
+// let mut dayset = dayset
+// .into_iter()
+// .map(|s| Some(s as isize))
+// .collect::<Vec<Option<isize>>>();
+
+// let filtered = remove_filtered_days(&mut dayset, start, end, &ii, options);
+
+// if not_empty(&options.bysetpos) {
+// let poslist = build_poslist(
+// &options.bysetpos,
+// &timeset,
+// start,
+// end,
+// &ii,
+// &dayset,
+// &options.tzid,
+// );
+
+// for j in 0..poslist.len() {
+// let res = poslist[j];
+// if options.until.is_some() && res > options.until.unwrap() {
+// return iter_result.get_value();
+// }
+
+// if res >= options.dtstart {
+// if !iter_result.accept(res) {
+// return iter_result.get_value();
+// }
+
+// if count > 0 {
+// count -= 1;
+// if count == 0 {
+// return iter_result.get_value();
+// }
+// }
+// }
+// }
+// } else {
+// for j in start..end {
+// let current_day = dayset[j];
+// if current_day.is_none() {
+// continue;
+// }
+
+// let current_day = current_day.unwrap();
+// let date = from_ordinal(ii.yearordinal().unwrap() + current_day, &options.tzid);
+// for k in 0..timeset.len() {
+// let res = options
+// .tzid
+// .ymd(date.year(), date.month(), date.day())
+// .and_hms(
+// timeset[k].hour as u32,
+// timeset[k].minute as u32,
+// timeset[k].second as u32,
+// );
+// if options.until.is_some() && res > options.until.unwrap() {
+// return iter_result.get_value();
+// }
+// if res >= options.dtstart {
+// if !iter_result.accept(res) {
+// return iter_result.get_value();
+// }
+
+// if count > 0 {
+// count -= 1;
+// if count == 0 {
+// return iter_result.get_value();
+// }
+// }
+// }
+// }
+// }
+// }
+
+// if options.interval == 0 {
+// return iter_result.get_value();
+// }
+
+// // Handle frequency and interval
+// counter_date = increment_counter_date(counter_date, options, filtered);
+
+// if counter_date.year() > 2200 {
+// return iter_result.get_value();
+// }
+
+// if options.freq == Frequenzy::Hourly
+// || options.freq == Frequenzy::Minutely
+// || options.freq == Frequenzy::Secondly
+// {
+// timeset = ii.gettimeset(
+// &options.freq,
+// counter_date.hour() as usize,
+// counter_date.minute() as usize,
+// counter_date.second() as usize,
+// 0,
+// );
+// }
+
+// ii.rebuild(counter_date.year() as isize, counter_date.month() as usize);
+// }
+// }
pub fn increment_counter_date(
counter_date: DTime,
@@ -301,14 +302,13 @@ pub fn remove_filtered_days(
start: usize,
end: usize,
ii: &IterInfo,
- options: &ParsedOptions,
) -> bool {
let mut filtered = false;
for daycounter in start..end {
match dayset[daycounter] {
Some(current_day) => {
- filtered = is_filtered(ii, current_day as usize, options);
+ filtered = is_filtered(ii, current_day as usize, &ii.options);
if filtered {
dayset[daycounter] = None;
}
diff --git a/src/rrule.rs b/src/rrule.rs
index c2a080e..d372e06 100644
--- a/src/rrule.rs
+++ b/src/rrule.rs
@@ -1,4 +1,4 @@
-use crate::iter::iter;
+use crate::iter::{generate, IterInfo};
use crate::options::*;
use crate::rrule_iter::*;
use crate::rrulestr::build_rrule;
@@ -18,55 +18,25 @@ impl RRule {
/// Returns all the recurrences of the rrule
pub fn all(&mut self) -> Vec<DateTime<Tz>> {
- let iter_args = IterArgs {
- inc: true,
- before: None,
- after: None,
- dt: None,
- };
- let mut iter_res = RRuleIterRes::new(QueryMethodTypes::All, iter_args);
-
- let res = iter(&mut iter_res, &mut self.options);
- res
+ self.into_iter().collect()
}
/// Returns the last recurrence before the given datetime instance.
/// The inc keyword defines what happens if dt is an recurrence.
/// With inc == true, if dt itself is an recurrence, it will be returned.
pub fn before(&mut self, dt: DateTime<Tz>, inc: bool) -> Option<DateTime<Tz>> {
- let iter_args = IterArgs {
- inc,
- before: None,
- after: None,
- dt: Some(dt),
- };
- let mut iter_res = RRuleIterRes::new(QueryMethodTypes::Before, iter_args);
-
- let recurrences = iter(&mut iter_res, &mut self.options);
- if recurrences.is_empty() {
- None
- } else {
- Some(recurrences[0])
- }
+ self.into_iter()
+ .take_while(|d| if inc { *d <= dt } else { *d < dt })
+ .last()
}
/// Returns the last recurrence after the given datetime instance.
/// The inc keyword defines what happens if dt is an recurrence.
/// With inc == true, if dt itself is an recurrence, it will be returned.
pub fn after(&mut self, dt: DateTime<Tz>, inc: bool) -> Option<DateTime<Tz>> {
- let iter_args = IterArgs {
- inc,
- before: None,
- after: None,
- dt: Some(dt),
- };
- let mut iter_res = RRuleIterRes::new(QueryMethodTypes::After, iter_args);
- let recurrences = iter(&mut iter_res, &mut self.options);
- if recurrences.is_empty() {
- None
- } else {
- Some(recurrences[0])
- }
+ self.into_iter()
+ .skip_while(|d| if inc { *d <= dt } else { *d < dt })
+ .next()
}
/// Returns all the recurrences of the rrule between after and before.
@@ -79,15 +49,10 @@ impl RRule {
before: DateTime<Tz>,
inc: bool,
) -> Vec<DateTime<Tz>> {
- let iter_args = IterArgs {
- inc,
- before: Some(before),
- after: Some(after),
- dt: None,
- };
- let mut iter_res = RRuleIterRes::new(QueryMethodTypes::Between, iter_args);
-
- iter(&mut iter_res, &mut self.options)
+ self.into_iter()
+ .skip_while(|d| if inc { *d <= after } else { *d < after })
+ .take_while(|d| if inc { *d <= before } else { *d < before })
+ .collect()
}
}
diff --git a/src/rrule_iter.rs b/src/rrule_iter.rs
index 7751476..1b45a77 100644
--- a/src/rrule_iter.rs
+++ b/src/rrule_iter.rs
@@ -1,4 +1,7 @@
-use crate::iter::IterResult;
+use crate::{
+ iter::{make_timeset, IterInfo, IterResult, RRuleIter},
+ RRule,
+};
use chrono::prelude::*;
use chrono::Duration;
use chrono_tz::Tz;
@@ -60,34 +63,45 @@ impl RRuleIterRes {
}
impl IterResult for RRuleIterRes {
- fn accept(&mut self, date: DateTime<Tz>) -> bool {
- self.total += 1;
- let too_early = self.min_date.is_some() && date < self.min_date.unwrap();
- let too_late = self.max_date.is_some() && date > self.max_date.unwrap();
-
+ // Returns tuple of flags indicating whether to add and continue
+ // iteration (add_date, continue_iteration)
+ fn accept(&self, date: &DateTime<Tz>) -> (bool, bool) {
+ let too_early = match self.min_date {
+ Some(d) => d > *date,
+ None => false,
+ };
+ let too_late = match self.max_date {
+ Some(d) => d < *date,
+ None => false,
+ };
match self.method {
- QueryMethodTypes::Between if too_early => true,
- QueryMethodTypes::Between if too_late => false,
- QueryMethodTypes::Before if too_late => false,
- QueryMethodTypes::After if too_early => true,
- QueryMethodTypes::After => {
- self.add(date);
- false
- }
- _ => self.add(date),
+ QueryMethodTypes::Between if too_early => (false, true),
+ QueryMethodTypes::Between if too_late => (false, false),
+ QueryMethodTypes::Before if too_late => (false, false),
+ QueryMethodTypes::After => (!too_early, too_early),
+ _ => (true, true),
}
}
+}
- // before and after returns only one date whereas all and between an array
- fn get_value(&self) -> Vec<DateTime<Tz>> {
- match self.method {
- QueryMethodTypes::Between | QueryMethodTypes::All => self.result.clone(),
- _ => {
- if self.result.is_empty() {
- return vec![];
- }
- vec![self.result[self.result.len() - 1].clone()]
- }
+impl IntoIterator for RRule {
+ type Item = DateTime<Tz>;
+
+ type IntoIter = RRuleIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ let mut ii = IterInfo::new(self.options);
+ let mut counter_date = ii.options.dtstart;
+ ii.rebuild(counter_date.year() as isize, counter_date.month() as usize);
+
+ let timeset = make_timeset(&ii, &counter_date, &ii.options);
+
+ RRuleIter {
+ counter_date,
+ ii,
+ timeset,
+ remain: vec![],
+ finished: false,
}
}
}