diff options
-rw-r--r-- | src/calendar.rs (renamed from src/events.rs) | 54 | ||||
-rw-r--r-- | src/event.rs | 27 | ||||
-rw-r--r-- | src/main.rs | 15 | ||||
-rw-r--r-- | src/periodic.rs | 45 |
4 files changed, 124 insertions, 17 deletions
diff --git a/src/events.rs b/src/calendar.rs index b0111e7..c49e747 100644 --- a/src/events.rs +++ b/src/calendar.rs @@ -1,18 +1,19 @@ use std::io::BufRead; use std::fmt; use ical::IcalParser; +use chrono::Duration; use date::Date; -use event::Event; +use event::{Event, End}; use periodic::Periodic; use errors::EventError; -pub struct Events { +pub struct Calendar { single: Vec<Event>, periodic: Vec<Periodic>, } -impl Events { +impl Calendar { pub fn parse<B: BufRead>(buf: B) -> Result<Self, EventError> { let reader = IcalParser::new(buf); let mut single = Vec::new(); @@ -40,7 +41,8 @@ impl Events { "DESCRIPTION" => event.description = value, "STATUS" => event.status = value.parse()?, "DTSTART" => event.start = Date::parse(&value, &time_zone)?, - "DTEND" => event.end = Date::parse(&value, &time_zone)?, + "DTEND" => event.end = End::Date(Date::parse(&value, &time_zone)?), + "DURATION" => event.end = End::Duration(duration(&value)?), "RRULE" => maybe_periodic = Some(rrule(&value, ¶ms)?), _ => (), }; @@ -55,12 +57,22 @@ impl Events { } } - single.sort_by(|a, b| a.start.cmp(&b.start)); - Ok(Events { single, periodic }) + single.sort_by_key(|k| k.start); + Ok(Calendar { single, periodic }) + } + + pub fn get(&self, first: &Date, last: &Date) -> Vec<Event> { + // TODO: not all single, just the one by date + let mut events = self.single.clone(); + for p in &self.periodic { + events.append(&mut p.get(first, last)); + } + events.sort_by_key(|k| k.start); + events } } -impl fmt::Display for Events { +impl fmt::Display for Calendar { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for event in &self.single { writeln!(f, "{}", event)?; @@ -73,7 +85,7 @@ impl fmt::Display for Events { } } -fn rrule(value: &String, params: &Vec<(String, Vec<String>)>) -> Result<Periodic, EventError> { +fn rrule(value: &str, params: &Vec<(String, Vec<String>)>) -> Result<Periodic, EventError> { let mut periodic = Periodic::new(); for entry in value.split(";") { @@ -91,3 +103,29 @@ fn rrule(value: &String, params: &Vec<(String, Vec<String>)>) -> Result<Periodic Ok(periodic) } + +fn duration(value: &str) -> Result<Duration, EventError> { + let mut duration = Duration::seconds(0); + let mut acc = "".to_string(); + for c in value.chars() { + match c { + '0'...'9' => acc.push(c), + '-' => duration = -duration, + 'W' | 'H' | 'M' | 'S' | 'D' => { + let count = acc.parse()?; + acc = "".to_string(); + let d = match c { + 'W' => Duration::weeks(count), + 'H' => Duration::hours(count), + 'M' => Duration::minutes(count), + 'S' => Duration::seconds(count), + 'D' => Duration::days(count), + _ => Duration::seconds(0), + }; + duration = duration + d; + } + _ => (), + } + } + Ok(Duration::weeks(1)) +} diff --git a/src/event.rs b/src/event.rs index 904b718..b54c422 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,6 +1,8 @@ use std::fmt; use std::str::FromStr; +use chrono::Duration; + use date::Date; use errors::EventError; @@ -8,7 +10,7 @@ use errors::EventError; #[derive(Debug, Clone)] pub struct Event { pub start: Date, - pub end: Date, + pub end: End, pub summary: String, pub location: String, pub description: String, @@ -22,6 +24,12 @@ pub enum Status { Canceled, } +#[derive(Debug, Copy, Clone)] +pub enum End { + Date(Date), + Duration(Duration), +} + impl Event { pub fn new() -> Event { @@ -31,14 +39,27 @@ impl Event { description: "".to_string(), status: Status::Confirmed, start: Date::empty(), - end: Date::empty(), + end: End::Date(Date::empty()), }; } + + pub fn end_date(&self) -> Date { + match self.end { + End::Date(date) => date, + End::Duration(duration) => self.start + duration, + } + } } impl fmt::Display for Event { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}: {}", self.start, self.summary)?; + write!( + f, + "{:?}-{:?}: {}", + self.start, + self.end_date(), + self.summary + )?; if !self.location.is_empty() { write!(f, " ({})", self.location)?; } diff --git a/src/main.rs b/src/main.rs index 022b811..66e1df1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,18 +5,25 @@ extern crate chrono_tz; mod date; mod event; mod periodic; -mod events; +mod calendar; mod errors; use std::env; use std::io::BufReader; use std::fs::File; -use events::Events; +use chrono::Duration; +use date::Date; +use calendar::Calendar; fn main() { let args: Vec<_> = env::args().collect(); let file = File::open(&args[1]).unwrap(); let buf = BufReader::new(file); - let events = Events::parse(buf).unwrap(); - println!("{}", events); + let calendar = Calendar::parse(buf).unwrap(); + println!("{}", calendar); + println!(""); + + let now = Date::now(); + let events = calendar.get(&now, &(now + Duration::weeks(10))); + println!("{:?}", events); } diff --git a/src/periodic.rs b/src/periodic.rs index e46a13b..f6cd2d7 100644 --- a/src/periodic.rs +++ b/src/periodic.rs @@ -1,7 +1,10 @@ use std::fmt; use std::str::FromStr; -use event::Event; +use chrono::Duration; + +use date::Date; +use event::{Event, End}; use errors::EventError; #[derive(Debug)] @@ -9,7 +12,8 @@ pub struct Periodic { pub event: Event, pub freq: Freq, pub interval: i64, - // TODO: until, count, ... + pub until: Date, + // TODO: count, ... } #[derive(Debug)] @@ -29,6 +33,7 @@ impl Periodic { event: Event::new(), freq: Freq::Secondly, interval: 1, + until: Date::empty(), } } @@ -36,10 +41,32 @@ impl Periodic { match param { "FREQ" => self.freq = value.parse()?, "INTERVAL" => self.interval = value.parse()?, + "UNTIL" => self.until = Date::parse(&value, "")?, _ => (), } Ok(()) } + + pub fn get(&self, first: &Date, last: &Date) -> Vec<Event> { + let mut start = self.event.start; + let mut end = self.event.end_date(); + let mut events = Vec::new(); + while start <= *last { + if !self.until.is_empty() && start <= self.until { + break; + } + + if start >= *first { + let mut e = self.event.clone(); + e.start = start; + e.end = End::Date(end); + events.push(e); + } + start = start + self.freq.duration(self.interval); + end = end + self.freq.duration(self.interval); + } + events + } } impl fmt::Display for Periodic { @@ -53,6 +80,20 @@ impl fmt::Display for Periodic { } } +impl Freq { + pub fn duration(&self, count: i64) -> Duration { + match self { + Freq::Secondly => Duration::seconds(count), + Freq::Minutely => Duration::minutes(count), + Freq::Hourly => Duration::hours(count), + Freq::Daily => Duration::days(count), + Freq::Weekly => Duration::weeks(count), + Freq::Monthly => Duration::days(count * 30), // FIXME + Freq::Yearly => Duration::days(count * 365), // FIXME + } + } +} + impl FromStr for Freq { type Err = EventError; |