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());  | 
