diff options
| author | Edward Barnard | 2017-04-20 12:04:59 +0100 |
|---|---|---|
| committer | Edward Barnard | 2017-04-20 12:04:59 +0100 |
| commit | 2e7bd78be40b04ff12379b6aeb739f7172ab11c9 (patch) | |
| tree | 86d5548413c4684170fdf318cb11cf9aa7834adb /src | |
| parent | ef418ab58970d396e9c8daf7a86d6a410ad11beb (diff) | |
| download | rust-plist-2e7bd78be40b04ff12379b6aeb739f7172ab11c9.tar.bz2 | |
Use a custom date type.
Diffstat (limited to 'src')
| -rw-r--r-- | src/binary/reader.rs | 31 | ||||
| -rw-r--r-- | src/date.rs | 67 | ||||
| -rw-r--r-- | src/lib.rs | 5 | ||||
| -rw-r--r-- | src/plist.rs | 24 | ||||
| -rw-r--r-- | src/serde/de.rs | 2 | ||||
| -rw-r--r-- | src/xml/reader.rs | 15 | ||||
| -rw-r--r-- | src/xml/writer.rs | 5 |
7 files changed, 94 insertions, 55 deletions
diff --git a/src/binary/reader.rs b/src/binary/reader.rs index d9bf667..1f1a00b 100644 --- a/src/binary/reader.rs +++ b/src/binary/reader.rs @@ -1,10 +1,9 @@ use byteorder::{BigEndian, ReadBytesExt}; -use chrono::{Duration, TimeZone, UTC}; use std::io::{Read, Seek, SeekFrom}; use std::mem; use std::string::{FromUtf8Error, FromUtf16Error}; -use {Error, Result, PlistEvent, u64_to_usize}; +use {Date, Error, Result, PlistEvent, u64_to_usize}; impl From<FromUtf8Error> for Error { fn from(_: FromUtf8Error) -> Error { @@ -215,28 +214,10 @@ impl<R: Read + Seek> EventReader<R> { } (0x2, 3) => Some(PlistEvent::RealValue(try!(self.reader.read_f64::<BigEndian>()))), (0x2, _) => return Err(Error::InvalidData), // odd length float - (0x3, 3) => {; - // Date - // Seconds since 1/1/2001 00:00:00. - let timestamp = try!(self.reader.read_f64::<BigEndian>()); - - let millis = timestamp * 1_000.0; - // Chrono's Duration can only millisecond values between ::std::i64::MIN and - // ::std::i64::MAX. - if millis > ::std::i64::MAX as f64 || millis < ::std::i64::MIN as f64 { - return Err(Error::InvalidData); - } - - let whole_millis = millis.floor(); - let submilli_nanos = ((millis - whole_millis) * 1_000_000.0).floor(); - - let dur = Duration::milliseconds(whole_millis as i64); - let dur = dur + Duration::nanoseconds(submilli_nanos as i64); - - let plist_epoch = UTC.ymd(2001, 1, 1).and_hms(0, 0, 0); - let date = try!(plist_epoch.checked_add(dur).ok_or(Error::InvalidData)); - - Some(PlistEvent::DateValue(date)) + (0x3, 3) => { + // Date. Seconds since 1/1/2001 00:00:00. + let secs = try!(self.reader.read_f64::<BigEndian>()); + Some(PlistEvent::DateValue(Date::from_seconds_since_plist_epoch(secs)?)) } (0x4, n) => { // Data @@ -354,7 +335,7 @@ mod tests { StringValue("Height".to_owned()), RealValue(1.60), StringValue("Birthdate".to_owned()), - DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06)), + DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06).into()), StringValue("Author".to_owned()), StringValue("William Shakespeare".to_owned()), StringValue("Data".to_owned()), diff --git a/src/date.rs b/src/date.rs new file mode 100644 index 0000000..b7c9914 --- /dev/null +++ b/src/date.rs @@ -0,0 +1,67 @@ +use chrono::{DateTime, Duration, TimeZone, UTC}; +use std::fmt; +use std::str::FromStr; + +use {Error, Result}; + +#[derive(Clone, Debug, PartialEq)] +pub struct Date { + inner: DateTime<UTC> +} + +impl Date { + pub fn from_seconds_since_plist_epoch(timestamp: f64) -> Result<Date> { + // Seconds since 1/1/2001 00:00:00. + + let millis = timestamp * 1_000.0; + // Chrono's Duration can only millisecond values between ::std::i64::MIN and + // ::std::i64::MAX. + if millis > ::std::i64::MAX as f64 || millis < ::std::i64::MIN as f64 { + return Err(Error::InvalidData); + } + + let whole_millis = millis.floor(); + let submilli_nanos = ((millis - whole_millis) * 1_000_000.0).floor(); + + let dur = Duration::milliseconds(whole_millis as i64); + let dur = dur + Duration::nanoseconds(submilli_nanos as i64); + + let plist_epoch = UTC.ymd(2001, 1, 1).and_hms(0, 0, 0); + let date = try!(plist_epoch.checked_add(dur).ok_or(Error::InvalidData)); + + Ok(Date { + inner: date + }) + } +} + +impl From<DateTime<UTC>> for Date { + fn from(date: DateTime<UTC>) -> Self { + Date { + inner: date + } + } +} + +impl Into<DateTime<UTC>> for Date { + fn into(self) -> DateTime<UTC> { + self.inner + } +} + +impl fmt::Display for Date { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.inner) + } +} + +impl FromStr for Date { + type Err = (); + + fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> { + let date = DateTime::parse_from_rfc3339(&s).map_err(|_| ())?; + Ok(Date { + inner: date.with_timezone(&UTC) + }) + } +} @@ -58,8 +58,10 @@ pub mod binary; pub mod xml; mod builder; +mod date; mod plist; +pub use date::Date; pub use plist::Plist; // Optional serde module @@ -69,7 +71,6 @@ extern crate serde as serde_base; #[cfg(feature = "serde")] pub mod serde; -use chrono::{DateTime, UTC}; use std::fmt; use std::io::{Read, Seek, SeekFrom}; use std::io::Error as IoError; @@ -100,7 +101,7 @@ pub enum PlistEvent { BooleanValue(bool), DataValue(Vec<u8>), - DateValue(DateTime<UTC>), + DateValue(Date), IntegerValue(i64), RealValue(f64), StringValue(String), diff --git a/src/plist.rs b/src/plist.rs index 313cc12..f84de6f 100644 --- a/src/plist.rs +++ b/src/plist.rs @@ -1,10 +1,9 @@ -use chrono::{DateTime, UTC}; use rustc_serialize::base64::{STANDARD, ToBase64}; use rustc_serialize::json::Json as RustcJson; use std::collections::BTreeMap; use std::io::{Read, Seek}; -use {builder, EventReader, PlistEvent, Result}; +use {builder, Date, EventReader, PlistEvent, Result}; #[derive(Clone, Debug, PartialEq)] pub enum Plist { @@ -12,7 +11,7 @@ pub enum Plist { Dictionary(BTreeMap<String, Plist>), Boolean(bool), Data(Vec<u8>), - Date(DateTime<UTC>), + Date(Date), Real(f64), Integer(i64), String(String), @@ -76,7 +75,7 @@ impl Plist { } Plist::Boolean(value) => RustcJson::Boolean(value), Plist::Data(value) => RustcJson::String(value.to_base64(STANDARD)), - Plist::Date(value) => RustcJson::String(value.to_rfc3339()), + Plist::Date(value) => RustcJson::String(value.to_string()), Plist::Real(value) => RustcJson::F64(value), Plist::Integer(value) => RustcJson::I64(value), Plist::String(value) => RustcJson::String(value), @@ -151,9 +150,9 @@ impl Plist { /// If the `Plist` is a Date, returns the associated DateTime. /// Returns None otherwise. - pub fn as_date(&self) -> Option<DateTime<UTC>> { + pub fn as_date(&self) -> Option<&Date> { match self { - &Plist::Date(date) => Some(date), + &Plist::Date(ref date) => Some(date), _ => None, } } @@ -222,14 +221,14 @@ impl<'a> From<&'a bool> for Plist { } } -impl From<DateTime<UTC>> for Plist { - fn from(from: DateTime<UTC>) -> Plist { +impl From<Date> for Plist { + fn from(from: Date) -> Plist { Plist::Date(from) } } -impl<'a> From<&'a DateTime<UTC>> for Plist { - fn from(from: &'a DateTime<UTC>) -> Plist { +impl<'a> From<&'a Date> for Plist { + fn from(from: &'a Date) -> Plist { Plist::Date(from.clone()) } } @@ -362,6 +361,7 @@ mod tests { fn test_plist_access() { use std::collections::BTreeMap; use chrono::*; + use super::Date; let vec = vec![Plist::Real(0.0)]; let mut array = Plist::Array(vec.clone()); @@ -381,8 +381,8 @@ mod tests { assert_eq!(Plist::Data(slice.to_vec()).into_data(), Some(slice.to_vec())); - let date: DateTime<UTC> = UTC::now(); - assert_eq!(Plist::Date(date).as_date(), Some(date)); + let date: Date = UTC::now().into(); + assert_eq!(Plist::Date(date.clone()).as_date(), Some(&date)); assert_eq!(Plist::Real(0.0).as_real(), Some(0.0)); assert_eq!(Plist::Integer(1).as_integer(), Some(1)); diff --git a/src/serde/de.rs b/src/serde/de.rs index 0f4ffa4..74abe87 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -85,7 +85,7 @@ impl<'a, I> de::Deserializer for &'a mut Deserializer<I> PlistEvent::BooleanValue(v) => visitor.visit_bool(v), PlistEvent::DataValue(v) => visitor.visit_byte_buf(v), - PlistEvent::DateValue(v) => visitor.visit_string(v.to_rfc3339()), + PlistEvent::DateValue(v) => visitor.visit_string(v.to_string()), PlistEvent::IntegerValue(v) if v.is_positive() => visitor.visit_u64(v as u64), PlistEvent::IntegerValue(v) => visitor.visit_i64(v as i64), PlistEvent::RealValue(v) => visitor.visit_f64(v), diff --git a/src/xml/reader.rs b/src/xml/reader.rs index 6af89b0..00b3bc4 100644 --- a/src/xml/reader.rs +++ b/src/xml/reader.rs @@ -1,17 +1,9 @@ -use chrono::{DateTime, UTC}; -use chrono::format::ParseError as ChronoParseError; use rustc_serialize::base64::FromBase64; use std::io::Read; use std::str::FromStr; use xml_rs::reader::{EventReader as XmlEventReader, ParserConfig, XmlEvent}; -use {Error, Result, PlistEvent}; - -impl From<ChronoParseError> for Error { - fn from(_: ChronoParseError) -> Error { - Error::InvalidData - } -} +use {Date, Error, Result, PlistEvent}; pub struct EventReader<R: Read> { xml_reader: XmlEventReader<R>, @@ -83,8 +75,7 @@ impl<R: Read> EventReader<R> { } "date" => { return Some(self.read_content(|s| { - let date = try!(DateTime::parse_from_rfc3339(&s)); - Ok(PlistEvent::DateValue(date.with_timezone(&UTC))) + Ok(PlistEvent::DateValue(Date::from_str(&s).map_err(|_| Error::InvalidData)?)) })) } "integer" => { @@ -187,7 +178,7 @@ mod tests { StringValue("Data".to_owned()), DataValue(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]), StringValue("Birthdate".to_owned()), - DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06)), + DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06).into()), StringValue("Blank".to_owned()), StringValue("".to_owned()), EndDictionary]; diff --git a/src/xml/writer.rs b/src/xml/writer.rs index 9018e2d..02c57db 100644 --- a/src/xml/writer.rs +++ b/src/xml/writer.rs @@ -166,8 +166,7 @@ impl<W: Write> PlistEventWriter for EventWriter<W> { try!(self.write_element_and_value("data", &base64_data)); } PlistEvent::DateValue(ref value) => { - let date = format!("{:?}", value); - try!(self.write_element_and_value("date", &date)); + try!(self.write_element_and_value("date", &value.to_string())); } PlistEvent::IntegerValue(ref value) => { try!(self.write_element_and_value("integer", &value.to_string())) @@ -212,7 +211,7 @@ mod tests { StringValue("Data".to_owned()), DataValue(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]), StringValue("Birthdate".to_owned()), - DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06)), + DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06).into()), EndDictionary]; let mut cursor = Cursor::new(Vec::new()); |
