summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFredrik Meringdal <fmeringdal@hotmail.com>2020-10-25 21:51:21 +0100
committerFredrik Meringdal <fmeringdal@hotmail.com>2020-10-25 21:51:21 +0100
commita003b9b174d6df1421796a64943666129868ad16 (patch)
tree045c79c2a56fe4da8c03903e5c662d22990a5aaa /src
parent6a9c33a36255cf0f34f35446c22ea98434a566f0 (diff)
downloadrust_rrule-a003b9b174d6df1421796a64943666129868ad16.zip
more docs
Diffstat (limited to 'src')
-rw-r--r--src/iter_set.rs2
-rw-r--r--src/lib.rs62
-rw-r--r--src/rrule.rs39
-rw-r--r--src/rruleset.rs4
-rw-r--r--src/rrulestr.rs26
5 files changed, 116 insertions, 17 deletions
diff --git a/src/iter_set.rs b/src/iter_set.rs
index 3e96231..60eced6 100644
--- a/src/iter_set.rs
+++ b/src/iter_set.rs
@@ -4,7 +4,7 @@ use crate::options::*;
use crate::poslist::*;
use chrono::offset::TimeZone;
use chrono::prelude::*;
-use chrono::{DateTime, Utc};
+use chrono::DateTime;
use chrono_tz::*;
pub trait IterResult {
diff --git a/src/lib.rs b/src/lib.rs
index 61a5d00..2205bfd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,63 @@
+//! A partial implementation of recurrence rules as defined in the iCalendar RFC.
+//!
+//! This map implementation allows reads and writes to execute entirely in parallel, with no
+//! implicit synchronization overhead. Reads never take locks on their critical path, and neither
+//! do writes assuming there is a single writer (multi-writer is possible using a `Mutex`), which
+//! significantly improves performance under contention.
+//!
+//! The trade-off exposed by this module is one of eventual consistency: writes are not visible to
+//! readers except following explicit synchronization. Specifically, readers only see the
+//! operations that preceeded the last call to `WriteHandle::refresh` by a writer. This lets
+//! writers decide how stale they are willing to let reads get. They can refresh the map after
+//! every write to emulate a regular concurrent `HashMap`, or they can refresh only occasionally to
+//! reduce the synchronization overhead at the cost of stale reads.
+//!
+//! For read-heavy workloads, the scheme used by this module is particularly useful. Writers can
+//! afford to refresh after every write, which provides up-to-date reads, and readers remain fast
+//! as they do not need to ever take locks.
+//!
+//! The map is multi-value, meaning that every key maps to a *collection* of values. This
+//! introduces some memory cost by adding a layer of indirection through a `Vec` for each value,
+//! but enables more advanced use. This choice was made as it would not be possible to emulate such
+//! functionality on top of the semantics of this map (think about it -- what would the operational
+//! log contain?).
+//!
+//! To faciliate more advanced use-cases, each of the two maps also carry some customizeable
+//! meta-information. The writers may update this at will, and when a refresh happens, the current
+//! meta will also be made visible to readers. This could be useful, for example, to indicate what
+//! time the refresh happened.
+//!
+//! # Examples
+//!
+//! RRule
+//!
+//! ```
+//! extern crate rrule;
+//! extern crate chrono;
+//!
+//! use chrono::prelude::*;
+//! use rrule::build_rrule;
+//!
+//! // Parse a RRule string, return a RRule type
+//! let mut rrule = build_rrule("DTSTART:20120201T093000Z\nRRULE:FREQ=WEEKLY;INTERVAL=5;UNTIL=20130130T230000Z;BYDAY=MO,FR");
+//! assert_eq!(rrule.all().len(), 21);
+//! ```
+//!
+//!
+//! RRuleSet
+//!
+//! ```
+//! extern crate rrule;
+//! extern crate chrono;
+//!
+//! use chrono::prelude::*;
+//! use rrule::build_rruleset;
+//!
+//! // Parse a RRuleSet string, return a RRuleSet type
+//! let mut rrule = build_rruleset("DTSTART:20120201T023000Z\nRRULE:FREQ=MONTHLY;COUNT=5\nRDATE:20120701T023000Z,20120702T023000Z\nEXRULE:FREQ=MONTHLY;COUNT=2\nEXDATE:20120601T023000Z");
+//! assert_eq!(rrule.all().len(), 6);
+//! ```
+
extern crate chrono;
extern crate chrono_tz;
extern crate once_cell;
@@ -20,5 +80,5 @@ mod rruleset;
pub use crate::rrule::RRule;
pub use crate::rruleset::RRuleSet;
-pub use crate::rrulestr::build_rule;
+pub use crate::rrulestr::{build_rrule, build_rruleset};
pub use crate::options::{Frequenzy, ParsedOptions, PartialOptions}; \ No newline at end of file
diff --git a/src/rrule.rs b/src/rrule.rs
index 08ebd7d..6904d6c 100644
--- a/src/rrule.rs
+++ b/src/rrule.rs
@@ -2,7 +2,7 @@ use crate::iter::*;
use crate::iter_set::iter_v2;
use crate::options::*;
use chrono::prelude::*;
-use chrono_tz::{Tz, UTC};
+use chrono_tz::Tz;
#[derive(Clone, Debug)]
pub struct RRule {
@@ -29,21 +29,44 @@ impl RRule {
res
}
+ pub fn before(&mut self, dt: DateTime<Tz>, inc: bool) -> Vec<DateTime<Tz>> {
+ let iter_args = IterArgs {
+ inc,
+ before: None,
+ after: None,
+ dt: Some(dt),
+ };
+ let mut iter_res = RRuleIterRes::new(QueryMethodTypes::Before, iter_args);
+
+ iter_v2(&mut iter_res, &mut self.options)
+ }
+
+ pub fn after(&mut self, dt: DateTime<Tz>, inc: bool) -> Vec<DateTime<Tz>> {
+ let iter_args = IterArgs {
+ inc,
+ before: None,
+ after: None,
+ dt: Some(dt),
+ };
+ let mut iter_res = RRuleIterRes::new(QueryMethodTypes::After, iter_args);
+
+ iter_v2(&mut iter_res, &mut self.options)
+ }
+
pub fn between(
&mut self,
- after: &DateTime<Tz>,
- before: &DateTime<Tz>,
+ after: DateTime<Tz>,
+ before: DateTime<Tz>,
inc: bool,
) -> Vec<DateTime<Tz>> {
let iter_args = IterArgs {
inc,
- before: Some(before.clone()),
- after: Some(after.clone()),
+ before: Some(before),
+ after: Some(after),
dt: None,
};
- let mut iter_res = RRuleIterRes::new(QueryMethodTypes::All, iter_args);
+ let mut iter_res = RRuleIterRes::new(QueryMethodTypes::Between, iter_args);
- let res = iter_v2(&mut iter_res, &mut self.options);
- res
+ iter_v2(&mut iter_res, &mut self.options)
}
}
diff --git a/src/rruleset.rs b/src/rruleset.rs
index ab8437f..630bc27 100644
--- a/src/rruleset.rs
+++ b/src/rruleset.rs
@@ -1,6 +1,5 @@
use crate::iter::*;
use crate::iter_set::{iter_v2, IterResult};
-use crate::options::*;
use crate::rrule::*;
use chrono::prelude::*;
use chrono_tz::{Tz, UTC};
@@ -93,7 +92,7 @@ impl<'a> RRuleSetIter<'a> {
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, before, true) {
+ for date in rrule.between(after.clone(), before.clone(), true) {
self.exdate_hash.insert(date.timestamp(), ());
}
}
@@ -238,6 +237,7 @@ impl RRuleSet {
#[cfg(test)]
mod test_iter_set {
use super::*;
+ use crate::options::*;
fn ymd_hms(
year: i32,
diff --git a/src/rrulestr.rs b/src/rrulestr.rs
index 1f90b4a..1584306 100644
--- a/src/rrulestr.rs
+++ b/src/rrulestr.rs
@@ -4,7 +4,6 @@ use crate::rrule::RRule;
use crate::rruleset::RRuleSet;
use chrono::prelude::*;
use chrono::DateTime;
-use chrono_tz::{Tz, UTC};
use once_cell::sync::Lazy;
use regex::Regex;
@@ -356,7 +355,7 @@ fn parse_rdate(rdateval: &str, params: Vec<String>) -> Vec<DateTime<Utc>> {
}
-pub fn build_rule(s: &str) -> RRuleSet {
+pub fn build_rruleset(s: &str) -> RRuleSet {
let ParsedInput {
mut rrule_vals,
rdate_vals,
@@ -411,21 +410,38 @@ pub fn build_rule(s: &str) -> RRuleSet {
rset
}
+pub fn build_rrule(s: &str) -> RRule {
+ let ParsedInput {
+ mut rrule_vals,
+ tzid,
+ dtstart,
+ ..
+ } = parse_input(s);
+
+ rrule_vals[0].tzid = tzid;
+ rrule_vals[0].dtstart = dtstart;
+
+ let parsed_opts = parse_options(&rrule_vals[0]);
+
+ RRule::new(parsed_opts)
+}
+
#[cfg(test)]
mod test {
use super::*;
+ use chrono_tz::{Tz, UTC};
#[test]
fn it_works_1() {
- let options = build_rule("DTSTART:19970902T090000Z\nRRULE:FREQ=YEARLY;COUNT=3\n");
+ let options = build_rruleset("DTSTART:19970902T090000Z\nRRULE:FREQ=YEARLY;COUNT=3\n");
println!("?????????????=================?????????????");
println!("{:?}", options);
}
#[test]
fn it_works_2() {
- let mut options = build_rule("RRULE:UNTIL=19990404T110000Z;DTSTART=19990104T110000Z;FREQ=WEEKLY;BYDAY=TU,WE");
+ let mut options = build_rruleset("RRULE:UNTIL=19990404T110000Z;DTSTART=19990104T110000Z;FREQ=WEEKLY;BYDAY=TU,WE");
println!("?????????????=================?????????????");
println!("{:?}", options);
println!("?????????????=== ALLL ==============?????????????");
@@ -434,7 +450,7 @@ mod test {
#[test]
fn it_works_3() {
- let mut options = build_rule("RRULE:UNTIL=19990404T110000Z;DTSTART;TZID=America/Denver:19990104T110000Z;FREQ=WEEKLY;BYDAY=TU,WE");
+ let mut options = build_rruleset("RRULE:UNTIL=19990404T110000Z;DTSTART;TZID=America/Denver:19990104T110000Z;FREQ=WEEKLY;BYDAY=TU,WE");
println!("?????????????=================?????????????");
println!("{:?}", options);
let tzid: Tz = "America/Denver".parse().unwrap();