diff options
author | Vincent Breitmoser <look@my.amazin.horse> | 2019-01-25 20:06:09 +0100 |
---|---|---|
committer | Vincent Breitmoser <look@my.amazin.horse> | 2019-01-25 20:06:09 +0100 |
commit | 8c476036178ed5011606053a550bead317e0a4b2 (patch) | |
tree | 1b1d62fa3e842e299f11404ed18ca47654886ab9 /src/icalwrap | |
parent | 530c85b176bfa1eb2f920c79eb49ff92c48a749d (diff) |
icalwrap: add IcalDuration type
Diffstat (limited to 'src/icalwrap')
-rw-r--r-- | src/icalwrap/icalduration.rs | 177 | ||||
-rw-r--r-- | src/icalwrap/icaltime.rs | 24 | ||||
-rw-r--r-- | src/icalwrap/icalvevent.rs | 21 | ||||
-rw-r--r-- | src/icalwrap/mod.rs | 16 |
4 files changed, 229 insertions, 9 deletions
diff --git a/src/icalwrap/icalduration.rs b/src/icalwrap/icalduration.rs new file mode 100644 index 0000000..96fd073 --- /dev/null +++ b/src/icalwrap/icalduration.rs @@ -0,0 +1,177 @@ +use std::ops::{Deref,Add}; +use std::ffi::{CStr,CString}; +use ical; +use std::fmt::{Error,Display,Formatter}; +use std::str::FromStr; +use std::cmp::Ordering; + + +#[derive(Clone,Debug)] +pub struct IcalDuration { + duration: ical::icaldurationtype, +} + +impl IcalDuration { + pub fn from_seconds(seconds: i32) -> IcalDuration { + let duration = unsafe { ical::icaldurationtype_from_int(seconds) }; + IcalDuration{ duration } + } + + pub fn to_seconds(&self) -> i32 { + unsafe { ical::icaldurationtype_as_int(self.duration) } + } +} + +impl Deref for IcalDuration { + type Target = ical::icaldurationtype; + + fn deref(&self) -> &ical::icaldurationtype { + &self.duration + } +} + +impl Display for IcalDuration { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + let cstr = unsafe { + CStr::from_ptr(ical::icaldurationtype_as_ical_string(self.duration)) + }; + let string = cstr.to_string_lossy(); + write!(f, "{}", string) + } +} + +impl FromStr for IcalDuration { + type Err = String; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let c_str = CString::new(s).unwrap(); + let duration = unsafe { + let duration = ical::icaldurationtype_from_string(c_str.as_ptr()); + if ical::icaldurationtype_is_null_duration(duration) == 0 { + Some(duration) + } else { + None + } + }; + if let Some(duration) = duration { + Ok(IcalDuration { duration }) + } else { + return Err(format!("Could not parse duration {}", s)); + } + } +} + +impl PartialEq<IcalDuration> for IcalDuration { + fn eq(&self, rhs: &IcalDuration) -> bool { + self.to_seconds() == rhs.to_seconds() + } +} + +impl Eq for IcalDuration {} + +impl PartialOrd for IcalDuration { + fn partial_cmp(&self, rhs: &IcalDuration) -> Option<Ordering> { + Some(self.cmp(rhs)) + } +} + +impl Ord for IcalDuration { + fn cmp(&self, rhs: &IcalDuration) -> Ordering { + let left = self.to_seconds(); + let right = rhs.to_seconds(); + if left == right { + Ordering::Equal + } else if left < right { + Ordering::Less + } else { + Ordering::Greater + } + } +} + +impl From<ical::icaldurationtype> for IcalDuration { + fn from(duration: ical::icaldurationtype) -> IcalDuration { + IcalDuration { duration } + } +} + +impl From<IcalDuration> for chrono::Duration { + fn from(duration: IcalDuration) -> chrono::Duration { + chrono::Duration::seconds(i64::from(duration.to_seconds())) + } +} + +impl From<chrono::Duration> for IcalDuration { + fn from(duration: chrono::Duration) -> IcalDuration { + IcalDuration::from_seconds(duration.num_seconds() as i32) + } +} +impl Add for IcalDuration { + type Output = IcalDuration; + + fn add(self, other: IcalDuration) -> IcalDuration { + let seconds = self.to_seconds() + other.to_seconds(); + IcalDuration::from_seconds(seconds) + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse() { + let duration = "PT86400S".parse::<IcalDuration>().unwrap(); + assert_eq!(IcalDuration::from_seconds(24*60*60), duration); + assert_eq!(86400, duration.to_seconds()); + } + + #[test] + fn test_parse_fail() { + let duration = "swag".parse::<IcalDuration>(); + assert!(duration.is_err()); + } + + #[test] + fn test_display() { + let duration = IcalDuration::from_seconds(5*24*60*60 + 22*60*60 + 33*60 + 33); + assert_eq!("P5DT22H33M33S", duration.to_string()); + } + + #[test] + fn test_to_chrono() { + let from_duration = IcalDuration::from_seconds(5*24*60*60 + 22*60*60 + 33*60 + 33); + let duration: chrono::Duration = from_duration.into(); + assert_eq!(chrono::Duration::seconds(5*24*60*60 + 22*60*60 + 33*60 + 33), duration); + } + + #[test] + fn test_from_chrono() { + let from_duration = chrono::Duration::seconds(5*24*60*60 + 22*60*60 + 33*60 + 33); + let duration: IcalDuration = from_duration.into(); + assert_eq!(IcalDuration::from_seconds(5*24*60*60 + 22*60*60 + 33*60 + 33), duration); + } + + #[test] + fn test_add() { + let fst = IcalDuration::from_seconds(123); + let snd = IcalDuration::from_seconds(4567); + + let sum = fst + snd; + + assert_eq!(IcalDuration::from_seconds(123+4567), sum); + } + + #[test] + fn test_cmp() { + let more = chrono::Duration::seconds(49128); + let less = chrono::Duration::seconds(5); + + assert!(less == less); + assert!(more == more); + assert!(less < more); + assert!(!(more < less)); + assert!(!(more == less)); + } +} diff --git a/src/icalwrap/icaltime.rs b/src/icalwrap/icaltime.rs index c618885..96a6368 100644 --- a/src/icalwrap/icaltime.rs +++ b/src/icalwrap/icaltime.rs @@ -1,9 +1,10 @@ -use std::ops::Deref; +use std::ops::{Add,Deref}; use std::ffi::{CStr,CString}; use chrono::{Date,DateTime,TimeZone,Utc,Local}; use ical; use utils::dateutil; use super::IcalTimeZone; +use super::IcalDuration; use super::TZ_MUTEX; use std::fmt::{Error,Display,Formatter}; use std::str::FromStr; @@ -116,7 +117,7 @@ impl Display for IcalTime { let cstr = unsafe { CStr::from_ptr(ical::icaltime_as_ical_string(self.time)) }; - let string = cstr.to_string_lossy().into_owned(); + let string = cstr.to_string_lossy(); write!(f, "{}", string) } } @@ -158,6 +159,15 @@ impl From<ical::icaltimetype> for IcalTime { } } +impl Add<IcalDuration> for IcalTime { + type Output = IcalTime; + + fn add(self, other: IcalDuration) -> IcalTime { + let time = unsafe { ical::icaltime_add(self.time, *other) }; + IcalTime { time } + } +} + impl<T: Into<IcalTime> + Clone> From<&T> for IcalTime { fn from(time: &T) -> IcalTime { time.clone().into() @@ -273,4 +283,14 @@ mod tests { assert_eq!("20140101", time.to_string()); } + + #[test] + fn test_add() { + let now = IcalTime::utc(); + let duration = IcalDuration::from_seconds(123); + + let sum = now + duration; + + assert_eq!(1357002123 + 123, sum.timestamp()); + } } diff --git a/src/icalwrap/icalvevent.rs b/src/icalwrap/icalvevent.rs index f4adf0f..15bd9c0 100644 --- a/src/icalwrap/icalvevent.rs +++ b/src/icalwrap/icalvevent.rs @@ -4,6 +4,7 @@ use super::IcalComponent; use super::IcalVCalendar; use super::IcalTime; use super::IcalTimeZone; +use super::IcalDuration; use ical; pub struct IcalVEvent { @@ -62,6 +63,17 @@ impl IcalVEvent { } } + pub fn get_duration(&self) -> Option<IcalDuration> { + unsafe { + let duration = ical::icalcomponent_get_duration(self.ptr); + if ical::icaldurationtype_is_bad_duration(duration) == 0 { + Some(IcalDuration::from(duration)) + } else { + None + } + } + } + pub fn get_dtstart(&self) -> Option<IcalTime> { match self.instance_timestamp { Some(ref timestamp) => Some(timestamp.clone()), @@ -269,6 +281,15 @@ mod tests { } #[test] + fn test_get_duration() { + let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_MULTIDAY, None).unwrap(); + let event = cal.get_principal_event(); + + assert_eq!(Some(IcalDuration::from_seconds(10*24*60*60 + 18*60*60)), event.get_duration()); + } + + + #[test] fn test_get_description() { let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_ONE_MEETING, None).unwrap(); let event = cal.get_principal_event(); diff --git a/src/icalwrap/mod.rs b/src/icalwrap/mod.rs index b8b6fb9..e52aabe 100644 --- a/src/icalwrap/mod.rs +++ b/src/icalwrap/mod.rs @@ -1,9 +1,10 @@ -mod icalvcalendar; -mod icalvevent; -mod icalproperty; mod icalcomponent; +mod icalduration; +mod icalproperty; mod icaltime; mod icaltimezone; +mod icalvcalendar; +mod icalvevent; // libical does some weird, non-threadsafe things in timezone methods, notably // icaltime_convert_to_zone (which is also called in icaltime_as_timet_with_zone) @@ -15,10 +16,11 @@ lazy_static! { static ref TZ_MUTEX: Mutex<i32> = Mutex::new(0); } -pub use self::icalvcalendar::IcalVCalendar; -pub use self::icalvcalendar::IcalEventIter; -pub use self::icalvevent::IcalVEvent; -pub use self::icalproperty::IcalProperty; pub use self::icalcomponent::IcalComponent; +pub use self::icalduration::IcalDuration; +pub use self::icalproperty::IcalProperty; pub use self::icaltime::IcalTime; pub use self::icaltimezone::IcalTimeZone; +pub use self::icalvcalendar::IcalEventIter; +pub use self::icalvcalendar::IcalVCalendar; +pub use self::icalvevent::IcalVEvent; |