From b80fb44d83f9460f9d1ab4c831e7c6a9baf44c16 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Sat, 25 Aug 2018 19:09:30 +0200 Subject: Basic periodic events support --- src/errors.rs | 1 + src/events.rs | 40 +++++++++++++++++++++++++++++++++--- src/main.rs | 1 + src/periodic.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 src/periodic.rs diff --git a/src/errors.rs b/src/errors.rs index d526bae..be78bcf 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -6,6 +6,7 @@ pub enum EventError { IcalError(parser::errors::Error), IntError(ParseIntError), StatusError, + FreqError, } impl From for EventError { diff --git a/src/events.rs b/src/events.rs index a78a286..9cda846 100644 --- a/src/events.rs +++ b/src/events.rs @@ -3,25 +3,31 @@ use std::fmt; use ical::IcalParser; use event::{Event, Date}; +use periodic::Periodic; use errors::EventError; pub struct Events { single: Vec, + periodic: Vec, } impl Events { pub fn parse(buf: B) -> Result { let reader = IcalParser::new(buf); let mut single = Vec::new(); + let mut periodic = Vec::new(); for line in reader { for ev in line?.events { let mut event = Event::new(); + let mut maybe_periodic = None; + for property in ev.properties { let value = property.value.unwrap_or("".to_string()); let mut time_zone = "".to_string(); - for (param, value) in property.params.unwrap_or(vec![]) { + let params = property.params.unwrap_or(vec![]); + for (param, value) in ¶ms { if param == "TZID" && value.len() > 0 { time_zone = value[0].clone(); } @@ -34,15 +40,22 @@ impl Events { "STATUS" => event.status = value.parse()?, "DTSTART" => event.start = Date::parse(&value, &time_zone)?, "DTEND" => event.end = Date::parse(&value, &time_zone)?, + "RRULE" => maybe_periodic = Some(rrule(&value, ¶ms)?), _ => (), }; } - single.push(event); + match maybe_periodic { + Some(mut p) => { + p.event = event; + periodic.push(p); + } + None => single.push(event), + } } } single.sort_by(|a, b| a.start.cmp(&b.start)); - Ok(Events { single }) + Ok(Events { single, periodic }) } } @@ -51,6 +64,27 @@ impl fmt::Display for Events { for event in &self.single { writeln!(f, "{}", event)?; } + writeln!(f, "")?; + for periodic in &self.periodic { + writeln!(f, "{}", periodic)?; + } Ok(()) } } + +fn rrule(value: &String, params: &Vec<(String, Vec)>) -> Result { + let mut periodic = Periodic::new(); + + let p: Vec<&str> = value.splitn(2, "=").collect(); + periodic.set_param(p[0], p[1])?; + + for (param, values) in params { + let mut value = ""; + if values.len() > 0 { + value = &values[0]; + } + periodic.set_param(param, value)?; + } + + Ok(periodic) +} diff --git a/src/main.rs b/src/main.rs index c923232..6b011bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ extern crate chrono; extern crate chrono_tz; mod event; +mod periodic; mod events; mod errors; diff --git a/src/periodic.rs b/src/periodic.rs new file mode 100644 index 0000000..0fa06ef --- /dev/null +++ b/src/periodic.rs @@ -0,0 +1,64 @@ +use std::fmt; +use std::str::FromStr; + +use event::Event; +use errors::EventError; + +#[derive(Debug)] +pub struct Periodic { + pub event: Event, + pub freq: Freq, + // TODO: until, count, interval, ... +} + +#[derive(Debug)] +pub enum Freq { + Secondly, + Minutely, + Hourly, + Daily, + Weekly, + Monthly, + Yearly, +} + +impl Periodic { + pub fn new() -> Self { + Self { + event: Event::new(), + freq: Freq::Secondly, + } + } + + pub fn set_param(&mut self, param: &str, value: &str) -> Result<(), EventError> { + match param { + "FREQ" => self.freq = value.parse()?, + _ => (), + } + Ok(()) + } +} + +impl fmt::Display for Periodic { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}: {}", self.freq, self.event)?; + Ok(()) + } +} + +impl FromStr for Freq { + type Err = EventError; + + fn from_str(s: &str) -> Result { + match s { + "SECONDLY" => Ok(Freq::Secondly), + "MINUTELY" => Ok(Freq::Minutely), + "HOURLY" => Ok(Freq::Hourly), + "DAILY" => Ok(Freq::Daily), + "WEEKLY" => Ok(Freq::Weekly), + "MONTHLY" => Ok(Freq::Monthly), + "YEARLY" => Ok(Freq::Yearly), + _ => Err(EventError::FreqError), + } + } +} -- cgit v1.2.3