diff options
-rw-r--r-- | src/event.rs | 123 | ||||
-rw-r--r-- | src/ics.rs | 124 | ||||
-rw-r--r-- | src/main.rs | 1 |
3 files changed, 128 insertions, 120 deletions
diff --git a/src/event.rs b/src/event.rs new file mode 100644 index 0000000..904e550 --- /dev/null +++ b/src/event.rs @@ -0,0 +1,123 @@ +use std::cmp::Ordering; +use std::fmt; +use std::str::FromStr; + +use chrono; +use chrono::prelude::{DateTime, TimeZone}; +use chrono_tz::{Tz, UTC}; + +use ics::IcsError; + + +#[derive(Debug)] +pub struct Event { + pub start: Date, + pub end: Date, + pub summary: String, + pub location: String, + pub description: String, + pub status: Status, +} + +#[derive(Debug)] +pub enum Date { + Time(DateTime<Tz>), + AllDay(chrono::Date<Tz>), +} + +#[derive(Debug)] +pub enum Status { + Confirmed, + Tentative, + Canceled, +} + + +impl Event { + pub fn new() -> Event { + return Event { + summary: "".to_string(), + location: "".to_string(), + description: "".to_string(), + status: Status::Confirmed, + start: Date::Time(UTC.timestamp(0, 0)), + end: Date::Time(UTC.timestamp(0, 0)), + }; + } +} + +impl fmt::Display for Event { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}: {}", self.start, self.summary)?; + if !self.location.is_empty() { + write!(f, " ({})", self.location)?; + } + if !self.description.is_empty() { + write!(f, "\n\t{}", self.description)?; + } + Ok(()) + } +} + +impl Date { + pub fn cmp(&self, other: &Self) -> Ordering { + match *self { + Date::Time(t1) => { + match *other { + Date::Time(t2) => t1.cmp(&t2), + Date::AllDay(d) => cmp_date_time(&d, &t1).reverse(), + } + } + Date::AllDay(d1) => { + match *other { + Date::Time(t) => cmp_date_time(&d1, &t), + Date::AllDay(d2) => d1.cmp(&d2), + } + } + } + } + + pub fn parse(date: String, time_zone: String) -> Result<Self, IcsError> { + let tz: Tz = time_zone.parse().unwrap_or(UTC); + let date = match date.find("T") { + Some(_) => { + let time = tz.datetime_from_str(&date, "%Y%m%dT%H%M%S").unwrap_or( + UTC.timestamp( + 0, + 0, + ), + ); + Date::Time(time) + } + None => { + Date::AllDay(tz.ymd( + i32::from_str(&date[0..4])?, + u32::from_str(&date[4..6])?, + u32::from_str(&date[6..8])?, + )) + } + }; + Ok(date) + } +} + +impl FromStr for Status { + type Err = IcsError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "CONFIRMED" => Ok(Status::Confirmed), + "TENTATIVE" => Ok(Status::Tentative), + "CANCELED" => Ok(Status::Canceled), + _ => Err(IcsError::StatusError), + } + } +} + +fn cmp_date_time<T: TimeZone>(date: &chrono::Date<T>, time: &DateTime<T>) -> Ordering { + let d2 = time.date(); + if date.eq(&d2) { + return Ordering::Less; + } + date.cmp(&d2) +} @@ -2,40 +2,13 @@ use std::io; use std::io::BufReader; use std::fs::File; use std::path::Path; -use std::str::FromStr; use std::num::ParseIntError; -use std::fmt; -use std::cmp::Ordering; use ical::parser; use ical::IcalParser; -use chrono; -use chrono_tz::{Tz, UTC}; -use chrono::prelude::{DateTime, TimeZone}; +use event::{Event, Date}; -#[derive(Debug)] -pub enum Date { - Time(DateTime<Tz>), - AllDay(chrono::Date<Tz>), -} - -#[derive(Debug)] -pub enum Status { - Confirmed, - Tentative, - Canceled, -} - -#[derive(Debug)] -pub struct Event { - pub start: Date, - pub end: Date, - pub summary: String, - pub location: String, - pub description: String, - pub status: Status, -} pub fn parse<P: AsRef<Path>>(ics: P) -> Result<Vec<Event>, IcsError> { let buf = BufReader::new(File::open(ics)?); @@ -59,9 +32,9 @@ pub fn parse<P: AsRef<Path>>(ics: P) -> Result<Vec<Event>, IcsError> { "SUMMARY" => event.summary = value, "LOCATION" => event.location = value, "DESCRIPTION" => event.description = value, - "STATUS" => event.status = Status::from_str(&value)?, - "DTSTART" => event.start = parse_date(value, time_zone)?, - "DTEND" => event.end = parse_date(value, time_zone)?, + "STATUS" => event.status = value.parse()?, + "DTSTART" => event.start = Date::parse(value, time_zone)?, + "DTEND" => event.end = Date::parse(value, time_zone)?, _ => (), }; } @@ -73,95 +46,6 @@ pub fn parse<P: AsRef<Path>>(ics: P) -> Result<Vec<Event>, IcsError> { Ok(events) } -fn parse_date(date: String, time_zone: String) -> Result<Date, IcsError> { - let tz: Tz = time_zone.parse().unwrap_or(UTC); - let date = match date.find("T") { - Some(_) => { - let time = tz.datetime_from_str(&date, "%Y%m%dT%H%M%S").unwrap_or( - UTC.timestamp( - 0, - 0, - ), - ); - Date::Time(time) - } - None => { - Date::AllDay(tz.ymd( - i32::from_str(&date[0..4])?, - u32::from_str(&date[4..6])?, - u32::from_str(&date[6..8])?, - )) - } - }; - Ok(date) -} - -impl Event { - fn new() -> Event { - return Event { - summary: "".to_string(), - location: "".to_string(), - description: "".to_string(), - status: Status::Confirmed, - start: Date::Time(UTC.timestamp(0, 0)), - end: Date::Time(UTC.timestamp(0, 0)), - }; - } -} - -impl fmt::Display for Event { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}: {}", self.start, self.summary)?; - if !self.location.is_empty() { - write!(f, " ({})", self.location)?; - } - if !self.description.is_empty() { - write!(f, "\n\t{}", self.description)?; - } - Ok(()) - } -} - -impl Date { - fn cmp(&self, other: &Date) -> Ordering { - match *self { - Date::Time(t1) => { - match *other { - Date::Time(t2) => t1.cmp(&t2), - Date::AllDay(d) => cmp_date_time(&d, &t1).reverse(), - } - } - Date::AllDay(d1) => { - match *other { - Date::Time(t) => cmp_date_time(&d1, &t), - Date::AllDay(d2) => d1.cmp(&d2), - } - } - } - } -} - -impl FromStr for Status { - type Err = IcsError; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - match s { - "CONFIRMED" => Ok(Status::Confirmed), - "TENTATIVE" => Ok(Status::Tentative), - "CANCELED" => Ok(Status::Canceled), - _ => Err(IcsError::StatusError), - } - } -} - -fn cmp_date_time<T: TimeZone>(date: &chrono::Date<T>, time: &DateTime<T>) -> Ordering { - let d2 = time.date(); - if date.eq(&d2) { - return Ordering::Less; - } - date.cmp(&d2) -} - #[derive(Debug)] pub enum IcsError { IoError(io::Error), diff --git a/src/main.rs b/src/main.rs index 4d9b703..f51f763 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate chrono_tz; use std::env; mod ics; +mod event; fn main() { let args: Vec<_> = env::args().collect(); |