summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/iterinfo.rs118
-rw-r--r--src/lib.rs2
-rw-r--r--src/masks.rs36
-rw-r--r--src/monthinfo.rs106
-rw-r--r--src/yearinfo.rs84
5 files changed, 286 insertions, 60 deletions
diff --git a/src/iterinfo.rs b/src/iterinfo.rs
new file mode 100644
index 0000000..bf7f1d7
--- /dev/null
+++ b/src/iterinfo.rs
@@ -0,0 +1,118 @@
+use crate::monthinfo::*;
+use crate::yearinfo::*;
+
+struct IterInfo<'a> {
+ pub yearinfo: Option<YearInfo>,
+ pub monthinfo: Option<MonthInfo>,
+ options: &'a ParsedOptions,
+}
+
+impl<'a> IterInfo<'a> {
+ pub fn new(options: &'a ParsedOptions) -> Self {
+ Self {
+ options,
+ yearinfo: None,
+ monthinfo: None,
+ }
+ }
+
+ 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));
+ }
+
+ if !self.options.bynweekday.is_empty()
+ && ((self.monthinfo.is_none() || month != self.monthinfo.as_ref().unwrap().lastmonth)
+ || (self.monthinfo.is_none() || year != self.monthinfo.as_ref().unwrap().lastyear))
+ {
+ if let Some(yearinfo) = &self.yearinfo {
+ self.monthinfo = Some(rebuild_month(
+ year,
+ month,
+ yearinfo.yearlen,
+ &yearinfo.mrange,
+ &yearinfo.wdaymask,
+ self.options,
+ ));
+ }
+ }
+ }
+
+ pub fn lastyear(&self) -> Option<isize> {
+ match &self.monthinfo {
+ Some(info) => Some(info.lastyear),
+ None => None,
+ }
+ }
+ pub fn lastmonth(&self) -> Option<usize> {
+ match &self.monthinfo {
+ Some(info) => Some(info.lastmonth),
+ None => None,
+ }
+ }
+ pub fn yearlen(&self) -> Option<usize> {
+ match &self.yearinfo {
+ Some(info) => Some(info.yearlen),
+ None => None,
+ }
+ }
+ pub fn yearordinal(&self) -> Option<isize> {
+ match &self.yearinfo {
+ Some(info) => Some(info.yearordinal),
+ None => None,
+ }
+ }
+ pub fn mrange(&self) -> Option<&Vec<usize>> {
+ match &self.yearinfo {
+ Some(info) => Some(&info.mrange),
+ None => None,
+ }
+ }
+ pub fn wdaymask(&self) -> Option<&Vec<usize>> {
+ match &self.yearinfo {
+ Some(info) => Some(&info.wdaymask),
+ None => None,
+ }
+ }
+
+ pub fn mmask(&self) -> Option<&Vec<usize>> {
+ match &self.yearinfo {
+ Some(info) => Some(&info.mmask),
+ None => None,
+ }
+ }
+
+ pub fn wnomask(&self) -> Option<&Vec<usize>> {
+ match &self.yearinfo {
+ Some(info) => match &info.wnomask {
+ Some(mask) => Some(mask),
+ None => None,
+ },
+ None => None,
+ }
+ }
+ pub fn nwdaymask(&self) -> Option<&Vec<isize>> {
+ match &self.monthinfo {
+ Some(info) => Some(&info.nwdaymask),
+ None => None,
+ }
+ }
+ pub fn nextyearlen(&self) -> Option<usize> {
+ match &self.yearinfo {
+ Some(info) => Some(info.nextyearlen),
+ None => None,
+ }
+ }
+ pub fn mdaymask(&self) -> Option<&Vec<usize>> {
+ match &self.yearinfo {
+ Some(info) => Some(&info.mdaymask),
+ None => None,
+ }
+ }
+ pub fn nmdaymask(&self) -> Option<&Vec<isize>> {
+ match &self.yearinfo {
+ Some(info) => Some(&info.nmdaymask),
+ None => None,
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index ede868c..5c7c03b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,6 @@
extern crate chrono;
+mod iterinfo;
mod masks;
+mod monthinfo;
mod yearinfo;
diff --git a/src/masks.rs b/src/masks.rs
index e2ca977..75730d8 100644
--- a/src/masks.rs
+++ b/src/masks.rs
@@ -5,31 +5,31 @@
// Every mask is 7 days longer to handle cross-year weekly periods.
pub struct Masks {
- pub WDAY: Vec<u32>,
- pub M365: Vec<u32>,
- pub M365RANGE: Vec<u32>,
- pub M366: Vec<u32>,
- pub M366RANGE: Vec<u32>,
- pub MDAY365: Vec<u32>,
- pub MDAY366: Vec<u32>,
- pub NMDAY365: Vec<i32>,
- pub NMDAY366: Vec<i32>,
+ pub WDAY: Vec<usize>,
+ pub M365: Vec<usize>,
+ pub M365RANGE: Vec<usize>,
+ pub M366: Vec<usize>,
+ pub M366RANGE: Vec<usize>,
+ pub MDAY365: Vec<usize>,
+ pub MDAY366: Vec<usize>,
+ pub NMDAY365: Vec<isize>,
+ pub NMDAY366: Vec<isize>,
}
impl Masks {
pub fn new() -> Self {
- let M28: Vec<u32> = (1..29).collect();
- let M29: Vec<u32> = (1..30).collect();
- let M30: Vec<u32> = (1..31).collect();
- let M31: Vec<u32> = (1..32).collect();
+ let M28: Vec<usize> = (1..29).collect();
+ let M29: Vec<usize> = (1..30).collect();
+ let M30: Vec<usize> = (1..31).collect();
+ let M31: Vec<usize> = (1..32).collect();
- let NM28: Vec<i32> = (-28..0).collect();
- let NM29: Vec<i32> = (-29..0).collect();
- let NM30: Vec<i32> = (-30..0).collect();
- let NM31: Vec<i32> = (-31..0).collect();
+ let NM28: Vec<isize> = (-28..0).collect();
+ let NM29: Vec<isize> = (-29..0).collect();
+ let NM30: Vec<isize> = (-30..0).collect();
+ let NM31: Vec<isize> = (-31..0).collect();
Self {
- WDAY: vec![(0..7).collect::<Vec<u32>>(); 55]
+ WDAY: vec![(0..7).collect::<Vec<usize>>(); 55]
.into_iter()
.flatten()
.collect(),
diff --git a/src/monthinfo.rs b/src/monthinfo.rs
new file mode 100644
index 0000000..3b82ee5
--- /dev/null
+++ b/src/monthinfo.rs
@@ -0,0 +1,106 @@
+use crate::masks::Masks;
+use crate::yearinfo::*;
+use chrono::prelude::*;
+use chrono::{DateTime, Duration};
+
+struct RRule {}
+
+#[derive(Debug)]
+pub struct MonthInfo {
+ pub lastyear: isize,
+ pub lastmonth: usize,
+ pub nwdaymask: Vec<isize>,
+}
+
+pub fn rebuild_month(
+ year: isize,
+ month: usize,
+ yearlen: usize,
+ mrange: &Vec<usize>,
+ wdaymask: &Vec<usize>,
+ options: &ParsedOptions,
+) -> MonthInfo {
+ let mut result = MonthInfo {
+ lastyear: year,
+ lastmonth: month,
+ nwdaymask: vec![],
+ };
+
+ let mut ranges: Vec<(isize, isize)> = vec![];
+ if options.freq == Frequenzy::YEARLY {
+ if options.bymonth.is_empty() {
+ ranges = vec![(0, year as isize)];
+ } else {
+ for j in 0..options.bymonth.len() {
+ let m = options.bymonth[j];
+ ranges.push((mrange[m - 1] as isize, mrange[m] as isize))
+ }
+ }
+ } else if options.freq == Frequenzy::MONTHLY {
+ ranges.push((mrange[month - 1] as isize, mrange[month] as isize));
+ }
+
+ if ranges.is_empty() {
+ return result;
+ }
+
+ // Weekly frequency won't get here, so we may not
+ // care about cross-year weekly periods.
+ result.nwdaymask = vec![0; yearlen];
+
+ for j in 0..ranges.len() {
+ let rang = ranges[j];
+ let first = rang.0;
+ let last = rang.1 - 1;
+
+ for k in 0..options.bynweekday.len() {
+ let mut i: isize;
+ let wday = options.bynweekday[k][0];
+ let n = options.bynweekday[k][1];
+ if n < 0 {
+ i = last + (n + 1) * 7;
+ i -= pymod(wdaymask[i as usize] as isize - wday, 7);
+ } else {
+ i = first + (n - 1) * 7;
+ i += pymod(7 - wdaymask[i as usize] as isize + wday, 7);
+ }
+ if first <= i && i <= last {
+ result.nwdaymask[i as usize] = 1;
+ }
+ }
+ }
+
+ result
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let options = ParsedOptions {
+ freq: Frequenzy::YEARLY,
+ interval: 1,
+ count: Some(10),
+ until: None,
+ tzid: None,
+ dtstart: Utc.ymd(2020, 1, 1).and_hms(0, 0, 0),
+ wkst: 0,
+ bysetpos: vec![],
+ bymonth: vec![],
+ bymonthday: vec![],
+ bynmonthday: vec![],
+ byyearday: vec![],
+ byweekno: vec![1],
+ byweekday: vec![],
+ byhour: vec![],
+ byminute: vec![],
+ bysecond: vec![],
+ bynweekday: vec![],
+ };
+ let res = rebuild_month(2020, 1, 366, &vec![], &vec![], &options);
+ println!("Res: {:?}", res);
+ assert_eq!(2 + 2, 4);
+ }
+}
diff --git a/src/yearinfo.rs b/src/yearinfo.rs
index ee398e7..37767c1 100644
--- a/src/yearinfo.rs
+++ b/src/yearinfo.rs
@@ -2,24 +2,22 @@ use crate::masks::Masks;
use chrono::prelude::*;
use chrono::{DateTime, Duration};
-struct RRule {}
-
#[derive(Debug)]
-struct YearInfo {
- yearlen: usize,
- nextyearlen: usize,
- yearordinal: i64,
- yearweekday: usize,
- mmask: Vec<u32>,
- mrange: Vec<u32>,
- mdaymask: Vec<u32>,
- nmdaymask: Vec<i32>,
- wdaymask: Vec<u32>,
- wnomask: Option<Vec<u32>>,
+pub struct YearInfo {
+ pub yearlen: usize,
+ pub nextyearlen: usize,
+ pub yearordinal: isize,
+ pub yearweekday: usize,
+ pub mmask: Vec<usize>,
+ pub mrange: Vec<usize>,
+ pub mdaymask: Vec<usize>,
+ pub nmdaymask: Vec<isize>,
+ pub wdaymask: Vec<usize>,
+ pub wnomask: Option<Vec<usize>>,
}
-#[derive(Debug)]
-enum Frequenzy {
+#[derive(Debug, PartialEq)]
+pub enum Frequenzy {
YEARLY,
MONTHLY,
WEEKLY,
@@ -30,24 +28,25 @@ enum Frequenzy {
}
#[derive(Debug)]
-struct ParsedOptions {
- freq: Frequenzy,
- interval: usize,
- count: Option<u32>,
- until: Option<DateTime<Utc>>,
- tzid: Option<String>,
- dtstart: DateTime<Utc>,
- wkst: usize,
- bysetpos: Vec<u32>,
- bymonth: Vec<u32>,
- bymonthday: Vec<u32>,
- bynmonthday: Vec<u32>,
- byyearday: Vec<u32>,
- byweekno: Vec<isize>,
- byweekday: Vec<u32>,
- byhour: Vec<u32>,
- byminute: Vec<u32>,
- bysecond: Vec<u32>,
+pub struct ParsedOptions {
+ pub freq: Frequenzy,
+ pub interval: usize,
+ pub count: Option<u32>,
+ pub until: Option<DateTime<Utc>>,
+ pub tzid: Option<String>,
+ pub dtstart: DateTime<Utc>,
+ pub wkst: usize,
+ pub bysetpos: Vec<usize>,
+ pub bymonth: Vec<usize>,
+ pub bymonthday: Vec<usize>,
+ pub bynmonthday: Vec<isize>,
+ pub byyearday: Vec<usize>,
+ pub byweekno: Vec<isize>,
+ pub byweekday: Vec<usize>,
+ pub byhour: Vec<usize>,
+ pub byminute: Vec<usize>,
+ pub bysecond: Vec<usize>,
+ pub bynweekday: Vec<Vec<isize>>,
}
fn is_leap_year(year: i32) -> bool {
@@ -61,8 +60,8 @@ fn get_year_len(year: i32) -> usize {
365
}
-fn to_ordinal(date: &DateTime<Utc>) -> i64 {
- date.timestamp() / 60 / 60 / 24
+fn to_ordinal(date: &DateTime<Utc>) -> isize {
+ (date.timestamp() / 60 / 60 / 24) as isize
}
fn get_weekday_val(wk: &Weekday) -> usize {
@@ -77,12 +76,12 @@ fn get_weekday_val(wk: &Weekday) -> usize {
}
}
-struct BaseMasks {
- mmask: Vec<u32>,
- mdaymask: Vec<u32>,
- nmdaymask: Vec<i32>,
- wdaymask: Vec<u32>,
- mrange: Vec<u32>,
+pub struct BaseMasks {
+ mmask: Vec<usize>,
+ mdaymask: Vec<usize>,
+ nmdaymask: Vec<isize>,
+ wdaymask: Vec<usize>,
+ mrange: Vec<usize>,
}
fn base_year_masks(year: i32) -> BaseMasks {
@@ -119,7 +118,7 @@ pub fn pymod(a: isize, b: isize) -> isize {
r
}
-fn rebuild_year(year: i32, options: &ParsedOptions) -> YearInfo {
+pub fn rebuild_year(year: i32, options: &ParsedOptions) -> YearInfo {
let firstyday = Utc.ymd(year, 1, 1).and_hms_milli(0, 0, 0, 0);
let yearlen = get_year_len(year);
@@ -276,6 +275,7 @@ mod tests {
byhour: vec![],
byminute: vec![],
bysecond: vec![],
+ bynweekday: vec![],
};
let res = rebuild_year(2020, &options);
println!("Res: {:?}", res);