diff options
author | Fredrik Meringdal <fmeringdal@hotmail.com> | 2020-10-25 23:00:50 +0100 |
---|---|---|
committer | Fredrik Meringdal <fmeringdal@hotmail.com> | 2020-10-25 23:00:50 +0100 |
commit | dc44e5f2312bbb8ac411b9dc0b3b52eb3b351b6c (patch) | |
tree | ee75b9aeac7c4b18d21b5dd0cb37e9c2098cfc54 /src | |
parent | 55db5800701e9965b19ede01266442b11956b54b (diff) | |
download | rust_rrule-dc44e5f2312bbb8ac411b9dc0b3b52eb3b351b6c.zip |
restructure files
Diffstat (limited to 'src')
-rw-r--r-- | src/datetime.rs | 16 | ||||
-rw-r--r-- | src/iter/iterinfo.rs (renamed from src/iterinfo.rs) | 4 | ||||
-rw-r--r-- | src/iter/mod.rs (renamed from src/iter.rs) | 213 | ||||
-rw-r--r-- | src/iter/monthinfo.rs (renamed from src/monthinfo.rs) | 2 | ||||
-rw-r--r-- | src/iter/poslist.rs (renamed from src/poslist.rs) | 11 | ||||
-rw-r--r-- | src/iter/yearinfo.rs (renamed from src/yearinfo.rs) | 6 | ||||
-rw-r--r-- | src/iter_set.rs | 138 | ||||
-rw-r--r-- | src/lib.rs | 7 | ||||
-rw-r--r-- | src/rrule.rs | 12 | ||||
-rw-r--r-- | src/rrule_iter.rs | 93 | ||||
-rw-r--r-- | src/rruleset.rs | 170 | ||||
-rw-r--r-- | src/rruleset_iter.rs | 161 |
12 files changed, 424 insertions, 409 deletions
diff --git a/src/datetime.rs b/src/datetime.rs index 871ccfa..2e06d24 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -1,3 +1,19 @@ +use chrono::prelude::*; +use chrono_tz::Tz; + + +pub type DTime = DateTime<Tz>; + +pub fn from_ordinal(ordinal: isize) -> DateTime<Utc> { + let timestamp = ordinal * 24 * 60 * 60; + let naive = NaiveDateTime::from_timestamp(timestamp as i64, 0); + DateTime::from_utc(naive, Utc) +} + +pub fn to_ordinal(date: &DateTime<Utc>) -> isize { + (date.timestamp() / 60 / 60 / 24) as isize +} + #[derive(Debug)] pub struct Time { pub hour: usize, diff --git a/src/iterinfo.rs b/src/iter/iterinfo.rs index 6f3044e..09090f1 100644 --- a/src/iterinfo.rs +++ b/src/iter/iterinfo.rs @@ -1,8 +1,8 @@ use crate::datetime::*; use crate::easter::*; -use crate::monthinfo::*; +use crate::iter::monthinfo::{MonthInfo, rebuild_month}; +use crate::iter::yearinfo::{YearInfo, rebuild_year}; use crate::options::*; -use crate::yearinfo::*; use chrono::prelude::*; pub struct IterInfo<'a> { diff --git a/src/iter.rs b/src/iter/mod.rs index 6922ed4..d426a98 100644 --- a/src/iter.rs +++ b/src/iter/mod.rs @@ -1,101 +1,152 @@ -use crate::datetime::*; -use crate::iter_set::IterResult; -use crate::iterinfo::*; +mod yearinfo; +use yearinfo::get_weekday_val; + +mod monthinfo; + +mod iterinfo; +use iterinfo::IterInfo; + +mod poslist; +use poslist::build_poslist; + use crate::options::*; -use crate::yearinfo::*; +use crate::datetime::{Time, from_ordinal}; +use chrono::offset::TimeZone; use chrono::prelude::*; -use chrono::Duration; -use chrono_tz::Tz; - -pub enum QueryMethodTypes { - All, - Between, - Before, - After, -} +use chrono::{DateTime, Duration}; +use chrono_tz::*; -pub struct IterArgs { - pub inc: bool, - pub before: Option<DateTime<Tz>>, - pub after: Option<DateTime<Tz>>, - pub dt: Option<DateTime<Tz>>, +pub trait IterResult { + fn accept(&mut self, date: DateTime<Tz>) -> bool; + fn get_value(&self) -> Vec<DateTime<Tz>>; } -pub struct RRuleIterRes { - pub method: QueryMethodTypes, - pub args: IterArgs, - pub min_date: Option<DateTime<Tz>>, - pub max_date: Option<DateTime<Tz>>, - pub result: Vec<DateTime<Tz>>, - pub total: usize, -} +pub fn iter<T: IterResult>( + iter_result: &mut T, + options: &mut ParsedOptions, +) -> Vec<DateTime<Tz>> { -impl RRuleIterRes { - pub fn new(method: QueryMethodTypes, args: IterArgs) -> Self { - let (max_date, min_date) = match method { - QueryMethodTypes::Between if args.inc => { - (Some(args.before.unwrap()), Some(args.after.unwrap())) - } - QueryMethodTypes::Between => ( - Some(args.before.unwrap() - Duration::milliseconds(1)), - Some(args.after.unwrap() + Duration::milliseconds(1)), - ), - QueryMethodTypes::Before if args.inc => (Some(args.dt.unwrap()), None), - QueryMethodTypes::Before => (Some(args.dt.unwrap() - Duration::milliseconds(1)), None), - QueryMethodTypes::After if args.inc => (None, Some(args.dt.unwrap())), - QueryMethodTypes::After => (None, Some(args.dt.unwrap() + Duration::milliseconds(1))), - _ => (None, None), - }; - - Self { - method, - args, - min_date, - max_date, - total: 0, - result: vec![], - } + if (options.count.is_some() && options.count.unwrap() == 0) || options.interval == 0 { + return iter_result.get_value(); } - pub fn add(&mut self, date: DateTime<Tz>) -> bool { - self.result.push(date); - true - } -} + 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, ×et, 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(); + } -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(); - - 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 + if res >= options.dtstart { + //let rezoned_date = rezone_if_needed(&res, &options); + // let rezoned_date = UTC.timestamp(res.timestamp(), 0); + + if !iter_result.accept(res) { + return iter_result.get_value(); + } + + if count > 0 { + count -= 1; + if count == 0 { + return iter_result.get_value(); + } + } + } } - _ => self.add(date), - } - } + } else { + for j in start..end { + let current_day = dayset[j]; + if current_day.is_none() { + continue; + } - // 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![]; + let current_day = current_day.unwrap(); + let date = from_ordinal(ii.yearordinal().unwrap() + current_day); + 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 { + //let rezoned_date = rezone_if_needed(&res, &options); + // let rezoned_date = UTC.timestamp(res.timestamp(), 0); + // let rezoned_date = tzid.from_utc_datetime(&res.naive_utc()); + // let rezoned_date = res.with_timezone(&options.tzid); + + if !iter_result.accept(res) { + return iter_result.get_value(); + } + if count > 0 { + count -= 1; + if count == 0 { + return iter_result.get_value(); + } + } + } } - vec![self.result[self.result.len() - 1].clone()] } } + + 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: DateTime<Utc>, options: &ParsedOptions, diff --git a/src/monthinfo.rs b/src/iter/monthinfo.rs index c0af98a..c89bfc3 100644 --- a/src/monthinfo.rs +++ b/src/iter/monthinfo.rs @@ -1,5 +1,5 @@ use crate::options::*; -use crate::yearinfo::*; +use crate::iter::yearinfo::pymod; #[derive(Debug)] pub struct MonthInfo { diff --git a/src/poslist.rs b/src/iter/poslist.rs index 94ad6e9..fa9fbd8 100644 --- a/src/poslist.rs +++ b/src/iter/poslist.rs @@ -1,15 +1,10 @@ use crate::datetime::*; -use crate::iterinfo::*; -use crate::yearinfo::*; +use crate::iter::iterinfo::IterInfo; +use crate::iter::yearinfo::pymod; +use crate::datetime::from_ordinal; use chrono::prelude::*; use chrono_tz::Tz; -pub fn from_ordinal(ordinal: isize) -> DateTime<Utc> { - let timestamp = ordinal * 24 * 60 * 60; - let naive = NaiveDateTime::from_timestamp(timestamp as i64, 0); - DateTime::from_utc(naive, Utc) -} - pub fn build_poslist( bysetpost: &Vec<isize>, timeset: &Vec<Time>, diff --git a/src/yearinfo.rs b/src/iter/yearinfo.rs index 9bc0906..8a944f7 100644 --- a/src/yearinfo.rs +++ b/src/iter/yearinfo.rs @@ -1,7 +1,7 @@ use crate::masks::MASKS; use crate::options::*; use chrono::prelude::*; -use chrono::DateTime; +use crate::datetime::to_ordinal; #[derive(Debug)] @@ -29,10 +29,6 @@ fn get_year_len(year: i32) -> usize { 365 } -pub fn to_ordinal(date: &DateTime<Utc>) -> isize { - (date.timestamp() / 60 / 60 / 24) as isize -} - pub fn get_weekday_val(wk: &Weekday) -> usize { match wk { Weekday::Mon => 0, diff --git a/src/iter_set.rs b/src/iter_set.rs deleted file mode 100644 index 60eced6..0000000 --- a/src/iter_set.rs +++ /dev/null @@ -1,138 +0,0 @@ -use crate::iter::*; -use crate::iterinfo::*; -use crate::options::*; -use crate::poslist::*; -use chrono::offset::TimeZone; -use chrono::prelude::*; -use chrono::DateTime; -use chrono_tz::*; - -pub trait IterResult { - fn accept(&mut self, date: DateTime<Tz>) -> bool; - fn get_value(&self) -> Vec<DateTime<Tz>>; -} - -pub fn iter_v2<T: IterResult>( - iter_result: &mut T, - options: &mut ParsedOptions, -) -> Vec<DateTime<Tz>> { - - 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, ×et, 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 { - //let rezoned_date = rezone_if_needed(&res, &options); - // let rezoned_date = UTC.timestamp(res.timestamp(), 0); - - 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); - 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 { - //let rezoned_date = rezone_if_needed(&res, &options); - // let rezoned_date = UTC.timestamp(res.timestamp(), 0); - // let rezoned_date = tzid.from_utc_datetime(&res.naive_utc()); - // let rezoned_date = res.with_timezone(&options.tzid); - - 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); - } -} @@ -40,17 +40,14 @@ extern crate regex; mod datetime; mod easter; mod iter; -mod iter_set; -mod iterinfo; mod masks; -mod monthinfo; -mod poslist; mod parse_options; -mod yearinfo; mod options; mod rrulestr; mod rrule; +mod rrule_iter; mod rruleset; +mod rruleset_iter; pub use crate::rrule::RRule; pub use crate::rruleset::RRuleSet; diff --git a/src/rrule.rs b/src/rrule.rs index 6904d6c..d7aa198 100644 --- a/src/rrule.rs +++ b/src/rrule.rs @@ -1,5 +1,5 @@ -use crate::iter::*; -use crate::iter_set::iter_v2; +use crate::iter::iter; +use crate::rrule_iter::*; use crate::options::*; use chrono::prelude::*; use chrono_tz::Tz; @@ -25,7 +25,7 @@ impl RRule { }; let mut iter_res = RRuleIterRes::new(QueryMethodTypes::All, iter_args); - let res = iter_v2(&mut iter_res, &mut self.options); + let res = iter(&mut iter_res, &mut self.options); res } @@ -38,7 +38,7 @@ impl RRule { }; let mut iter_res = RRuleIterRes::new(QueryMethodTypes::Before, iter_args); - iter_v2(&mut iter_res, &mut self.options) + iter(&mut iter_res, &mut self.options) } pub fn after(&mut self, dt: DateTime<Tz>, inc: bool) -> Vec<DateTime<Tz>> { @@ -50,7 +50,7 @@ impl RRule { }; let mut iter_res = RRuleIterRes::new(QueryMethodTypes::After, iter_args); - iter_v2(&mut iter_res, &mut self.options) + iter(&mut iter_res, &mut self.options) } pub fn between( @@ -67,6 +67,6 @@ impl RRule { }; let mut iter_res = RRuleIterRes::new(QueryMethodTypes::Between, iter_args); - iter_v2(&mut iter_res, &mut self.options) + iter(&mut iter_res, &mut self.options) } } diff --git a/src/rrule_iter.rs b/src/rrule_iter.rs new file mode 100644 index 0000000..7751476 --- /dev/null +++ b/src/rrule_iter.rs @@ -0,0 +1,93 @@ +use crate::iter::IterResult; +use chrono::prelude::*; +use chrono::Duration; +use chrono_tz::Tz; + +pub enum QueryMethodTypes { + All, + Between, + Before, + After, +} + +pub struct IterArgs { + pub inc: bool, + pub before: Option<DateTime<Tz>>, + pub after: Option<DateTime<Tz>>, + pub dt: Option<DateTime<Tz>>, +} + +pub struct RRuleIterRes { + pub method: QueryMethodTypes, + pub args: IterArgs, + pub min_date: Option<DateTime<Tz>>, + pub max_date: Option<DateTime<Tz>>, + pub result: Vec<DateTime<Tz>>, + pub total: usize, +} + +impl RRuleIterRes { + pub fn new(method: QueryMethodTypes, args: IterArgs) -> Self { + let (max_date, min_date) = match method { + QueryMethodTypes::Between if args.inc => { + (Some(args.before.unwrap()), Some(args.after.unwrap())) + } + QueryMethodTypes::Between => ( + Some(args.before.unwrap() - Duration::milliseconds(1)), + Some(args.after.unwrap() + Duration::milliseconds(1)), + ), + QueryMethodTypes::Before if args.inc => (Some(args.dt.unwrap()), None), + QueryMethodTypes::Before => (Some(args.dt.unwrap() - Duration::milliseconds(1)), None), + QueryMethodTypes::After if args.inc => (None, Some(args.dt.unwrap())), + QueryMethodTypes::After => (None, Some(args.dt.unwrap() + Duration::milliseconds(1))), + _ => (None, None), + }; + + Self { + method, + args, + min_date, + max_date, + total: 0, + result: vec![], + } + } + + pub fn add(&mut self, date: DateTime<Tz>) -> bool { + self.result.push(date); + true + } +} + +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(); + + 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), + } + } + + // 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()] + } + } + } +} diff --git a/src/rruleset.rs b/src/rruleset.rs index f572404..dc9d589 100644 --- a/src/rruleset.rs +++ b/src/rruleset.rs @@ -1,174 +1,18 @@ -use crate::iter::*; -use crate::iter_set::{iter_v2, IterResult}; -use crate::rrule::*; +use crate::iter::{iter, IterResult}; use chrono::prelude::*; use chrono_tz::{Tz, UTC}; -use std::collections::HashMap; +use crate::rrule::RRule; +use crate::rruleset_iter::RRuleSetIter; #[derive(Debug)] pub struct RRuleSet { - rrule: Vec<RRule>, - rdate: Vec<DateTime<Utc>>, - exrule: Vec<RRule>, - exdate: Vec<DateTime<Utc>>, + pub rrule: Vec<RRule>, + pub rdate: Vec<DateTime<Utc>>, + pub exrule: Vec<RRule>, + pub exdate: Vec<DateTime<Utc>>, pub dtstart: Option<DateTime<Utc>>, } -struct RRuleSetIter<'a> { - exdate_hash: HashMap<i64, ()>, - iter_res: RRuleIterRes, - rrule_set: &'a mut RRuleSet, -} - -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, - } - } - - 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(), ()); - } - } - } - - 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.clone()); - } - } - - true - } - - 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.clone()); - } - - true - } - - pub fn iter(&mut self, tzid: Option<String>) -> Vec<DateTime<Tz>> { - let tzid: Tz = tzid.unwrap_or(String::from("UTC")).parse().unwrap_or(UTC); - - for date in &self.rrule_set.exdate { - let zoned_date = date.with_timezone(&tzid); - self.exdate_hash.insert(zoned_date.timestamp(), ()); - } - - match &self.iter_res.method { - QueryMethodTypes::Between => { - self.eval_exdate( - &self.iter_res.args.after.unwrap().clone(), - &self.iter_res.args.before.unwrap().clone(), - ); - } - _ => (), - }; - - for date in &self.rrule_set.rdate.clone() { - let zoned_date = date.with_timezone(&tzid); - if !self.accept(zoned_date) { - break; - } - } - - for rule in self.rrule_set.rrule.clone().iter_mut() { - iter_v2(self, &mut rule.options); - } - - 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), - } - } - - fn get_value(&self) -> Vec<DateTime<Tz>> { - self.iter_res.get_value() - } -} - impl RRuleSet { pub fn new() -> Self { Self { diff --git a/src/rruleset_iter.rs b/src/rruleset_iter.rs new file mode 100644 index 0000000..ba8e305 --- /dev/null +++ b/src/rruleset_iter.rs @@ -0,0 +1,161 @@ +use crate::iter::{iter, IterResult}; +use chrono::prelude::*; +use crate::rruleset::RRuleSet; +use crate::rrule_iter::*; +use std::collections::HashMap; +use chrono_tz::{Tz, UTC}; + +pub struct RRuleSetIter<'a> { + exdate_hash: HashMap<i64, ()>, + iter_res: RRuleIterRes, + rrule_set: &'a mut RRuleSet, +} + +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, + } + } + + 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(), ()); + } + } + } + + 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.clone()); + } + } + + true + } + + 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.clone()); + } + + true + } + + pub fn iter(&mut self, tzid: Option<String>) -> Vec<DateTime<Tz>> { + let tzid: Tz = tzid.unwrap_or(String::from("UTC")).parse().unwrap_or(UTC); + + for date in &self.rrule_set.exdate { + let zoned_date = date.with_timezone(&tzid); + self.exdate_hash.insert(zoned_date.timestamp(), ()); + } + + match &self.iter_res.method { + QueryMethodTypes::Between => { + self.eval_exdate( + &self.iter_res.args.after.unwrap().clone(), + &self.iter_res.args.before.unwrap().clone(), + ); + } + _ => (), + }; + + for date in &self.rrule_set.rdate.clone() { + let zoned_date = date.with_timezone(&tzid); + if !self.accept(zoned_date) { + break; + } + } + + for rule in self.rrule_set.rrule.clone().iter_mut() { + iter(self, &mut rule.options); + } + + 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), + } + } + + fn get_value(&self) -> Vec<DateTime<Tz>> { + self.iter_res.get_value() + } +} |