Skip to content

Commit

Permalink
replace String with ::chrono::DateTime<::chrono::FixedOffset>
Browse files Browse the repository at this point in the history
  • Loading branch information
DCjanus committed Jul 31, 2018
1 parent 02f325a commit 013ea4b
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 40 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ target/
**/*.rs.bk
Cargo.lock
.vscode/
.idea/
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ quick-xml = "0.12"
derive_builder = "0.5"
serde = { version = "1.0", optional = true, features = ["derive"] }
failure = "0.1.1"
chrono = "0.4.5"
40 changes: 25 additions & 15 deletions src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ use link::Link;
use person::Person;
use source::Source;
use toxml::{ToXml, WriterExt};
use util::atom_text;
use util::{atom_datetime, atom_text, default_fixed_datetime, FixedDateTime};

/// Represents an entry in an Atom feed
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, Default, Clone, PartialEq, Builder)]
#[derive(Debug, Clone, PartialEq, Builder)]
#[builder(setter(into), default)]
pub struct Entry {
/// A human-readable title for the entry.
title: String,
/// A universally unique and permanent URI.
id: String,
/// The last time the entry was modified.
updated: String,
updated: FixedDateTime,
/// The authors of the feed.
authors: Vec<Person>,
/// The categories that the entry belongs to.
Expand All @@ -38,7 +38,7 @@ pub struct Entry {
/// The Web pages related to the entry.
links: Vec<Link>,
/// The time of the initial creation or first availability of the entry.
published: Option<String>,
published: Option<FixedDateTime>,
/// Information about rights held in and over the entry.
rights: Option<String>,
/// The source information if an entry is copied from one feed into another feed.
Expand Down Expand Up @@ -127,8 +127,8 @@ impl Entry {
/// entry.set_updated("2017-06-03T15:15:44-05:00");
/// assert_eq!(entry.updated(), "2017-06-03T15:15:44-05:00");
/// ```
pub fn updated(&self) -> &str {
self.updated.as_str()
pub fn updated(&self) -> &FixedDateTime {
&self.updated
}

/// Set the last time that this entry was modified.
Expand All @@ -142,8 +142,8 @@ impl Entry {
/// entry.set_updated("2017-06-03T15:15:44-05:00");
/// ```
pub fn set_updated<V>(&mut self, updated: V)
where
V: Into<String>,
where
V: Into<FixedDateTime>,
{
self.updated = updated.into();
}
Expand Down Expand Up @@ -287,8 +287,8 @@ impl Entry {
/// entry.set_published("2017-06-01T15:15:44-05:00".to_string());
/// assert_eq!(entry.published(), Some("2017-06-01T15:15:44-05:00"));
/// ```
pub fn published(&self) -> Option<&str> {
self.published.as_ref().map(|s| s.as_str())
pub fn published(&self) -> Option<&FixedDateTime> {
self.published.as_ref()
}

/// Set the time that this entry was initially created or first made available.
Expand All @@ -303,7 +303,7 @@ impl Entry {
/// ```
pub fn set_published<V>(&mut self, published: V)
where
V: Into<Option<String>>,
V: Into<Option<FixedDateTime>>,
{
self.published = published.into();
}
Expand Down Expand Up @@ -496,7 +496,7 @@ impl FromXml for Entry {
match element.name() {
b"id" => entry.id = atom_text(reader)?.unwrap_or_default(),
b"title" => entry.title = atom_text(reader)?.unwrap_or_default(),
b"updated" => entry.updated = atom_text(reader)?.unwrap_or_default(),
b"updated" => entry.updated = atom_datetime(reader)?.unwrap_or_else(default_fixed_datetime),
b"author" => {
entry
.authors
Expand All @@ -517,7 +517,7 @@ impl FromXml for Entry {
.links
.push(Link::from_xml(reader, element.attributes())?)
}
b"published" => entry.published = atom_text(reader)?,
b"published" => entry.published = atom_datetime(reader)?,
b"rights" => entry.rights = atom_text(reader)?,
b"source" => {
entry.source = Some(Source::from_xml(reader, element.attributes())?)
Expand Down Expand Up @@ -560,15 +560,15 @@ impl ToXml for Entry {
.write_event(Event::Start(BytesStart::borrowed(name, name.len())))?;
writer.write_text_element(b"title", &*self.title)?;
writer.write_text_element(b"id", &*self.id)?;
writer.write_text_element(b"updated", &*self.updated)?;
writer.write_text_element(b"updated", &*self.updated.to_rfc3339())?;
writer.write_objects_named(&self.authors, "author")?;
writer.write_objects(&self.categories)?;
writer
.write_objects_named(&self.contributors, "contributor")?;
writer.write_objects(&self.links)?;

if let Some(ref published) = self.published {
writer.write_text_element(b"published", &**published)?;
writer.write_text_element(b"published", &published.to_rfc3339())?;
}

if let Some(ref rights) = self.rights {
Expand Down Expand Up @@ -598,3 +598,13 @@ impl ToXml for Entry {
Ok(())
}
}

#[allow(unconditional_recursion)]
impl Default for Entry {
fn default() -> Self {
Entry {
updated: default_fixed_datetime(),
..Default::default()
}
}
}
5 changes: 3 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::error::Error as StdError;
use std::fmt;
use std::str::Utf8Error;

use quick_xml::Error as XmlError;
Expand All @@ -19,6 +17,9 @@ pub enum Error {
/// Unexpected end of input.
#[fail(display = "unexpected end of input")]
Eof,
/// The format of the timestamp is wrong.
#[fail(display = "timestamps must be formatted by RFC3339, rather than {}", _0)]
WrongDatetime(String),
}

impl From<XmlError> for Error {
Expand Down
34 changes: 20 additions & 14 deletions src/feed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,19 @@ use generator::Generator;
use link::Link;
use person::Person;
use toxml::{ToXml, WriterExt};
use util::{atom_text, atom_any_text};
use util::{atom_any_text, atom_datetime, atom_text, default_fixed_datetime, FixedDateTime};

/// Represents an Atom feed
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, Default, Clone, PartialEq, Builder)]
#[derive(Debug, Clone, PartialEq, Builder)]
#[builder(setter(into), default)]
pub struct Feed {
/// A human-readable title for the feed.
title: String,
/// A universally unique and permanent URI.
id: String,
/// The last time the feed was modified in a significant way.
updated: String,
updated: FixedDateTime,
/// The authors of the feed.
authors: Vec<Person>,
/// The categories that the feed belongs to.
Expand Down Expand Up @@ -205,8 +204,8 @@ impl Feed {
/// feed.set_updated("2017-06-03T15:15:44-05:00");
/// assert_eq!(feed.updated(), "2017-06-03T15:15:44-05:00");
/// ```
pub fn updated(&self) -> &str {
self.updated.as_str()
pub fn updated(&self) -> &FixedDateTime {
&self.updated
}

/// Set the last time that this feed was modified.
Expand All @@ -220,8 +219,8 @@ impl Feed {
/// feed.set_updated("2017-06-03T15:15:44-05:00");
/// ```
pub fn set_updated<V>(&mut self, updated: V)
where
V: Into<String>,
where
V: Into<FixedDateTime>,
{
self.updated = updated.into();
}
Expand Down Expand Up @@ -642,7 +641,7 @@ impl FromXml for Feed {
match element.name() {
b"title" => feed.title = atom_any_text(reader, element.attributes())?.unwrap_or_default(),
b"id" => feed.id = atom_text(reader)?.unwrap_or_default(),
b"updated" => feed.updated = atom_text(reader)?.unwrap_or_default(),
b"updated" => feed.updated = atom_datetime(reader)?.unwrap_or_else(default_fixed_datetime),
b"author" => {
feed.authors
.push(Person::from_xml(reader, element.attributes())?)
Expand Down Expand Up @@ -702,10 +701,7 @@ impl ToXml for Feed {
fn to_xml<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), XmlError> {
let name = b"feed";
let mut element = BytesStart::borrowed(name, name.len());
element.push_attribute((
"xmlns".as_bytes(),
"http://www.w3.org/2005/Atom".as_bytes(),
));
element.push_attribute(("xmlns", "http://www.w3.org/2005/Atom"));

for (ns, uri) in &self.namespaces {
element.push_attribute((format!("xmlns:{}", ns).as_bytes(), uri.as_bytes()));
Expand All @@ -714,7 +710,7 @@ impl ToXml for Feed {
writer.write_event(Event::Start(element))?;
writer.write_text_element(b"title", &*self.title)?;
writer.write_text_element(b"id", &*self.id)?;
writer.write_text_element(b"updated", &*self.updated)?;
writer.write_text_element(b"updated", &*self.updated.to_rfc3339())?;
writer.write_objects_named(&self.authors, "author")?;
writer.write_objects(&self.categories)?;
writer
Expand Down Expand Up @@ -771,3 +767,13 @@ impl ToString for Feed {
String::from_utf8(buf).unwrap()
}
}

#[allow(unconditional_recursion)]
impl Default for Feed {
fn default() -> Self {
Feed {
updated: default_fixed_datetime(),
..Default::default()
}
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ extern crate failure;

extern crate quick_xml;

extern crate chrono;

mod feed;
mod category;
mod content;
Expand Down
28 changes: 19 additions & 9 deletions src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ use generator::Generator;
use link::Link;
use person::Person;
use toxml::{ToXml, WriterExt};
use util::atom_text;
use util::{atom_datetime, atom_text, default_fixed_datetime, FixedDateTime};

/// Represents the source of an Atom entry
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, Default, Clone, PartialEq, Builder)]
#[derive(Debug, Clone, PartialEq, Builder)]
#[builder(setter(into), default)]
pub struct Source {
/// A human-readable title for the feed.
title: String,
/// A universally unique and permanent URI.
id: String,
/// The last time the feed was modified in a significant way.
updated: String,
updated: FixedDateTime,
/// The authors of the feed.
authors: Vec<Person>,
/// The categories that the feed belongs to.
Expand Down Expand Up @@ -122,8 +122,8 @@ impl Source {
/// source.set_updated("2017-06-03T15:15:44-05:00");
/// assert_eq!(source.updated(), "2017-06-03T15:15:44-05:00");
/// ```
pub fn updated(&self) -> &str {
self.updated.as_str()
pub fn updated(&self) -> &FixedDateTime {
&self.updated
}

/// Set the last time that the source feed was modified.
Expand All @@ -137,8 +137,8 @@ impl Source {
/// source.set_updated("2017-06-03T15:15:44-05:00");
/// ```
pub fn set_updated<V>(&mut self, updated: V)
where
V: Into<String>,
where
V: Into<FixedDateTime>,
{
self.updated = updated.into();
}
Expand Down Expand Up @@ -443,7 +443,7 @@ impl FromXml for Source {
match element.name() {
b"id" => source.id = atom_text(reader)?.unwrap_or_default(),
b"title" => source.title = atom_text(reader)?.unwrap_or_default(),
b"updated" => source.updated = atom_text(reader)?.unwrap_or_default(),
b"updated" => source.updated = atom_datetime(reader)?.unwrap_or_else(default_fixed_datetime),
b"author" => {
source
.authors
Expand Down Expand Up @@ -494,7 +494,7 @@ impl ToXml for Source {
.write_event(Event::Start(BytesStart::borrowed(name, name.len())))?;
writer.write_text_element(b"title", &*self.title)?;
writer.write_text_element(b"id", &*self.id)?;
writer.write_text_element(b"updated", &*self.updated)?;
writer.write_text_element(b"updated", &self.updated.to_rfc3339())?;
writer.write_objects_named(&self.authors, "author")?;
writer.write_objects(&self.categories)?;
writer
Expand Down Expand Up @@ -527,3 +527,13 @@ impl ToXml for Source {
Ok(())
}
}

#[allow(unconditional_recursion)]
impl Default for Source {
fn default() -> Self {
Source {
updated: default_fixed_datetime(),
..Default::default()
}
}
}
19 changes: 19 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ use quick_xml::events::attributes::{Attribute, Attributes};
use quick_xml::Reader;

use error::Error;
use std::str::FromStr;

pub type FixedDateTime = ::chrono::DateTime<::chrono::FixedOffset>;

pub fn default_fixed_datetime() -> FixedDateTime {
FixedDateTime::from_str("1970-01-01T00:00:00Z").unwrap()
}

fn non_empty(string: String) -> Option<String> {
if !string.is_empty() {
Expand Down Expand Up @@ -141,3 +148,15 @@ pub fn atom_any_text<B: BufRead>(reader: &mut Reader<B>, mut atts: Attributes) -
_ => atom_text(reader)
}
}

pub fn atom_datetime<B: BufRead>(reader: &mut Reader<B>) -> Result<Option<FixedDateTime>, Error> {
if let Some(datetime_text) = atom_text(reader)? {
let parse_result = FixedDateTime::parse_from_rfc3339(&datetime_text);
match parse_result {
Err(_) => Err(Error::WrongDatetime(datetime_text)),
Ok(datetime) => Ok(Some(datetime)),
}
} else {
Ok(None)
}
}

0 comments on commit 013ea4b

Please sign in to comment.