aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEdward Barnard2017-04-20 12:04:59 +0100
committerEdward Barnard2017-04-20 12:04:59 +0100
commit2e7bd78be40b04ff12379b6aeb739f7172ab11c9 (patch)
tree86d5548413c4684170fdf318cb11cf9aa7834adb /src
parentef418ab58970d396e9c8daf7a86d6a410ad11beb (diff)
downloadrust-plist-2e7bd78be40b04ff12379b6aeb739f7172ab11c9.tar.bz2
Use a custom date type.
Diffstat (limited to 'src')
-rw-r--r--src/binary/reader.rs31
-rw-r--r--src/date.rs67
-rw-r--r--src/lib.rs5
-rw-r--r--src/plist.rs24
-rw-r--r--src/serde/de.rs2
-rw-r--r--src/xml/reader.rs15
-rw-r--r--src/xml/writer.rs5
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)
+ })
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 1fc293d..8a72ad3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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());