summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFredrik Meringdal <fredrikmeringdal@Fredriks-MacBook-Pro.local>2021-02-03 20:36:10 +0100
committerFredrik Meringdal <fredrikmeringdal@Fredriks-MacBook-Pro.local>2021-02-03 20:36:10 +0100
commit11f9f1a7b2339898bcad43d001e9e211d33eb5f9 (patch)
tree0767c1f4c875080015065d48fbd2e0f2ae5bcc31
parent61aac0d2773f7a073b63661ec150954414f5696e (diff)
downloadrust_rrule-11f9f1a7b2339898bcad43d001e9e211d33eb5f9.zip
checkpoint
-rw-r--r--src/iter/iter_v2.rs12
-rw-r--r--src/rrule.rs11
-rw-r--r--src/rruleset.rs39
-rw-r--r--src/rruleset_iter.rs238
4 files changed, 121 insertions, 179 deletions
diff --git a/src/iter/iter_v2.rs b/src/iter/iter_v2.rs
index 609206d..2a7e361 100644
--- a/src/iter/iter_v2.rs
+++ b/src/iter/iter_v2.rs
@@ -29,8 +29,8 @@ impl Iterator for RRuleIter {
}
pub fn generate(iter: &mut RRuleIter) {
- let options = iter.ii.options;
- let count = options.count.unwrap_or(0);
+ let options = &iter.ii.options;
+ let mut count = options.count.unwrap_or(0);
while iter.remain.is_empty() {
let (dayset, start, end) = iter.ii.getdayset(
@@ -143,9 +143,9 @@ pub fn generate(iter: &mut RRuleIter) {
);
}
- iter.ii.rebuild(
- iter.counter_date.year() as isize,
- iter.counter_date.month() as usize,
- );
+ let year = iter.counter_date.year();
+ let month = iter.counter_date.month();
+
+ iter.ii.rebuild(year as isize, month as usize);
}
}
diff --git a/src/rrule.rs b/src/rrule.rs
index d372e06..0fa8f24 100644
--- a/src/rrule.rs
+++ b/src/rrule.rs
@@ -18,14 +18,15 @@ impl RRule {
/// Returns all the recurrences of the rrule
pub fn all(&mut self) -> Vec<DateTime<Tz>> {
- self.into_iter().collect()
+ self.clone().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>> {
- self.into_iter()
+ self.clone()
+ .into_iter()
.take_while(|d| if inc { *d <= dt } else { *d < dt })
.last()
}
@@ -34,7 +35,8 @@ impl RRule {
/// 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>> {
- self.into_iter()
+ self.clone()
+ .into_iter()
.skip_while(|d| if inc { *d <= dt } else { *d < dt })
.next()
}
@@ -49,7 +51,8 @@ impl RRule {
before: DateTime<Tz>,
inc: bool,
) -> Vec<DateTime<Tz>> {
- self.into_iter()
+ self.clone()
+ .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/rruleset.rs b/src/rruleset.rs
index e8ddf11..dcbfe59 100644
--- a/src/rruleset.rs
+++ b/src/rruleset.rs
@@ -1,13 +1,12 @@
use crate::datetime::DTime;
use crate::options::RRuleParseError;
use crate::rrule::RRule;
-use crate::rruleset_iter::RRuleSetIter;
use crate::rrulestr::build_rruleset;
use chrono::prelude::*;
use chrono_tz::{Tz, UTC};
use std::str::FromStr;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct RRuleSet {
pub rrule: Vec<RRule>,
pub rdate: Vec<DTime>,
@@ -45,34 +44,27 @@ impl RRuleSet {
/// Returns all the recurrences of the rruleset
pub fn all(&mut self) -> Vec<DateTime<Tz>> {
- let mut iter = RRuleSetIter::all(self);
- iter.iter()
+ self.clone().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, date: DateTime<Tz>, inc: bool) -> Option<DateTime<Tz>> {
- let mut iter = RRuleSetIter::before(self, date, inc);
- let recurrences = iter.iter();
- if recurrences.is_empty() {
- None
- } else {
- Some(recurrences[0])
- }
+ pub fn before(&mut self, dt: DateTime<Tz>, inc: bool) -> Option<DateTime<Tz>> {
+ self.clone()
+ .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, date: DateTime<Tz>, inc: bool) -> Option<DateTime<Tz>> {
- let mut iter = RRuleSetIter::after(self, date, inc);
- let recurrences = iter.iter();
- if recurrences.is_empty() {
- None
- } else {
- Some(recurrences[0])
- }
+ pub fn after(&mut self, dt: DateTime<Tz>, inc: bool) -> Option<DateTime<Tz>> {
+ self.clone()
+ .into_iter()
+ .skip_while(|d| if inc { *d <= dt } else { *d < dt })
+ .next()
}
/// Returns all the recurrences of the rrule between after and before.
@@ -85,8 +77,11 @@ impl RRuleSet {
before: DateTime<Tz>,
inc: bool,
) -> Vec<DateTime<Tz>> {
- let mut iter = RRuleSetIter::between(self, after, before, inc);
- iter.iter()
+ self.clone()
+ .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/rruleset_iter.rs b/src/rruleset_iter.rs
index c9eca4e..9fe4c56 100644
--- a/src/rruleset_iter.rs
+++ b/src/rruleset_iter.rs
@@ -1,175 +1,119 @@
-use crate::iter::{iter, IterResult};
-use crate::rrule_iter::*;
use crate::rruleset::RRuleSet;
+use crate::{iter::RRuleIter, RRule};
use chrono::prelude::*;
use chrono_tz::Tz;
use std::collections::HashMap;
+use std::iter::Iterator;
-/// Result iterator for the RRuleSet type. It mostly just wraps
-/// `RRuleIterRes` and also before accepting any date makes sure that
-/// it does not collide with any exdates provided by either the exdates property
-/// or any occurence produced by any of the the exrules.
-pub struct RRuleSetIter<'a> {
- exdate_hash: HashMap<i64, ()>,
- iter_res: RRuleIterRes,
- rrule_set: &'a mut RRuleSet,
+pub struct RRuleIterSet {
+ pub queue: HashMap<usize, DateTime<Tz>>,
+ pub rrule_iters: Vec<RRuleIter>,
+ pub exrules: Vec<RRule>,
+ pub exdates: HashMap<i64, ()>,
}
-impl<'a> RRuleSetIter<'a> {
- pub fn all(rrule_set: &'a mut RRuleSet) -> Self {
- let iter_args = IterArgs {
- inc: true,
- before: None,
- after: None,
- dt: None,
- };
- let iter_res = RRuleIterRes::new(QueryMethodTypes::All, iter_args);
-
- Self {
- exdate_hash: HashMap::new(),
- iter_res,
- rrule_set,
- }
- }
-
- pub fn before(rrule_set: &'a mut RRuleSet, dt: DateTime<Tz>, inc: bool) -> Self {
- let iter_args = IterArgs {
- inc,
- before: None,
- after: None,
- dt: Some(dt),
- };
- let iter_res = RRuleIterRes::new(QueryMethodTypes::Before, iter_args);
-
- Self {
- exdate_hash: HashMap::new(),
- iter_res,
- rrule_set,
- }
- }
-
- pub fn after(rrule_set: &'a mut RRuleSet, dt: DateTime<Tz>, inc: bool) -> Self {
- let iter_args = IterArgs {
- inc,
- before: None,
- after: None,
- dt: Some(dt),
- };
- let iter_res = RRuleIterRes::new(QueryMethodTypes::After, iter_args);
-
- Self {
- exdate_hash: HashMap::new(),
- iter_res,
- rrule_set,
- }
- }
-
- pub fn between(
- rrule_set: &'a mut RRuleSet,
- after: DateTime<Tz>,
- before: DateTime<Tz>,
- inc: bool,
- ) -> Self {
- let iter_args = IterArgs {
- inc,
- before: Some(before),
- after: Some(after),
- dt: None,
- };
- let iter_res = RRuleIterRes::new(QueryMethodTypes::Between, iter_args);
-
- Self {
- exdate_hash: HashMap::new(),
- iter_res,
- rrule_set,
- }
- }
-
- /// Computes all exdates between after and before `DateTime`s for all the exrules and inserts them into
- /// the exdate_hash.
- pub fn eval_exdate(&mut self, after: &DateTime<Tz>, before: &DateTime<Tz>) {
- for rrule in self.rrule_set.exrule.iter_mut() {
- for date in rrule.between(after.clone(), before.clone(), true) {
- self.exdate_hash.insert(date.timestamp(), ());
+impl Iterator for RRuleIterSet {
+ type Item = DateTime<Tz>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let mut next_date: Option<(usize, DateTime<Tz>)> = None;
+
+ for (i, rrule_iter) in self.rrule_iters.iter().enumerate() {
+ let rrule_queue = self.queue.remove(&i);
+ let next_rrule_date = None;
+ match rrule_queue {
+ Some(d) => next_rrule_date = Some(d),
+ None => {
+ // should be generated
+ next_rrule_date = generate(rrule_iter, &self.exrules, &mut self.exdates);
+ }
}
- }
- }
- /// Here it is required to recompute exrules to see if some of the recurrences will collide with the provided date.
- fn accept_when_unknown_bounds(&mut self, date: DateTime<Tz>) -> bool {
- let dt = date.timestamp();
- if !self.exdate_hash.contains_key(&dt) {
- self.eval_exdate(
- &date.timezone().timestamp(dt - 1, 0),
- &date.timezone().timestamp(dt + 1, 0),
- );
- if !self.exdate_hash.contains_key(&dt) {
- self.exdate_hash.insert(dt, ());
- return self.iter_res.accept(date);
+ match next_rrule_date {
+ Some(next_rrule_date) => match next_date {
+ None => next_date = Some((i, next_rrule_date)),
+ Some(date) => {
+ if date.1 < next_rrule_date {
+ // Add previous date to its rrule queue
+ self.queue.insert(date.0, date.1);
+
+ // Update next_date
+ next_date = Some((i, next_rrule_date));
+ } else {
+ // Store for next iterations
+ self.queue.insert(i, next_rrule_date);
+ }
+ }
+ },
+ None => {}
}
}
- true
+ next_date.map(|d| d.1)
}
+}
- /// No need to recompute exrules as it has already been computed in the start of the iter method
- /// because the bounds where known.
- fn accept_when_known_bounds(&mut self, date: DateTime<Tz>) -> bool {
- let dt = date.timestamp();
- if !self.exdate_hash.contains_key(&dt) {
- self.exdate_hash.insert(dt, ());
- return self.iter_res.accept(date);
- }
-
- true
+fn generate(
+ rrule_iter: &RRuleIter,
+ exrules: &Vec<RRule>,
+ exdates: &mut HashMap<i64, ()>,
+) -> Option<DateTime<Tz>> {
+ let mut date = rrule_iter.next();
+ while !accept_generated_date(&date, exrules, exdates) {
+ date = rrule_iter.next();
}
- pub fn iter(&mut self) -> Vec<DateTime<Tz>> {
- // Add all exdates to exdate_hash
- for date in &self.rrule_set.exdate {
- self.exdate_hash.insert(date.timestamp(), ());
- }
+ date
+}
- // Small performance improvement by computing all exdates between
- // before and after dates when. For all the other `QueryMethodTypes`
- // the iter has to eval_exdate for every DateTime value produced by rdate or rrule
- // to check if it conflicts with any exrule or exdate rules, this is because
- // All, Before, After QueryMethodTypes has no time bounds and all the exdates can not be known beforehand.
- match &self.iter_res.method {
- QueryMethodTypes::Between => {
- self.eval_exdate(
- &self.iter_res.args.after.unwrap().clone(),
- &self.iter_res.args.before.unwrap().clone(),
- );
+fn accept_generated_date(
+ date: &Option<DateTime<Tz>>,
+ exrules: &Vec<RRule>,
+ exdates: &mut HashMap<i64, ()>,
+) -> bool {
+ match date {
+ None => true,
+ Some(date) => {
+ let dt = date.timestamp();
+
+ if !exrules.is_empty() {
+ let after = date.timezone().timestamp(dt - 1, 0);
+ let before = date.timezone().timestamp(dt + 1, 0);
+ for exrule in exrules.iter_mut() {
+ for date in exrule.between(after, before, true) {
+ exdates.insert(date.timestamp(), ());
+ }
+ }
}
- _ => (),
- };
- for date in self.rrule_set.rdate.clone().into_iter() {
- if !self.accept(date) {
- break;
+ if !exdates.contains_key(&dt) {
+ return false;
}
- }
- for rule in self.rrule_set.rrule.clone().iter_mut() {
- iter(self, &mut rule.options);
+ true
}
-
- let mut res = self.iter_res.get_value();
- res.sort();
- res
}
}
-impl<'a> IterResult for RRuleSetIter<'a> {
- fn accept(&mut self, date: DateTime<Tz>) -> bool {
- match &self.iter_res.method {
- QueryMethodTypes::Between => self.accept_when_known_bounds(date),
- _ => self.accept_when_unknown_bounds(date),
+impl IntoIterator for RRuleSet {
+ type Item = DateTime<Tz>;
+
+ type IntoIter = RRuleIterSet;
+
+ fn into_iter(self) -> Self::IntoIter {
+ RRuleIterSet {
+ queue: Default::default(),
+ rrule_iters: self
+ .rrule
+ .into_iter()
+ .map(|rrule| rrule.into_iter())
+ .collect(),
+ exrules: self.exrule,
+ exdates: self
+ .exdate
+ .iter()
+ .map(|exdate| (exdate.timestamp(), ()))
+ .collect(),
}
}
-
- fn get_value(&self) -> Vec<DateTime<Tz>> {
- self.iter_res.get_value()
- }
}