From 9461769bccef9e77e89b684a4d3231d4f5f0aa38 Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Fri, 21 Sep 2018 09:40:52 +0200 Subject: [PATCH] Parse date only once for pages --- Cargo.lock | 1 + components/content/Cargo.toml | 2 +- components/content/src/page.rs | 10 ++++------ components/content/src/sorting.rs | 7 ++++--- components/front_matter/src/page.rs | 26 ++++++++++++++++++++++---- 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad7144ba..f2d6d6bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,6 +250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/components/content/Cargo.toml b/components/content/Cargo.toml index ca8cffed..fffe8601 100644 --- a/components/content/Cargo.toml +++ b/components/content/Cargo.toml @@ -8,7 +8,7 @@ tera = "0.11" serde = "1" slug = "0.1" rayon = "1" -chrono = "0.4" +chrono = { version = "0.4", features = ["serde"] } errors = { path = "../errors" } config = { path = "../config" } diff --git a/components/content/src/page.rs b/components/content/src/page.rs index 9be00d53..e9fd5ac7 100644 --- a/components/content/src/page.rs +++ b/components/content/src/page.rs @@ -3,7 +3,6 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::result::Result as StdResult; -use chrono::Datelike; use tera::{Tera, Context as TeraContext}; use serde::ser::{SerializeStruct, self}; use slug::slugify; @@ -263,11 +262,10 @@ impl ser::Serialize for Page { state.serialize_field("title", &self.meta.title)?; state.serialize_field("description", &self.meta.description)?; state.serialize_field("date", &self.meta.date)?; - if let Some(chrono_datetime) = self.meta.date() { - let d = chrono_datetime.date(); - state.serialize_field("year", &d.year())?; - state.serialize_field("month", &d.month())?; - state.serialize_field("day", &d.day())?; + if let Some(d) = self.meta.datetime_tuple { + state.serialize_field("year", &d.0)?; + state.serialize_field("month", &d.1)?; + state.serialize_field("day", &d.2)?; } else { state.serialize_field::>("year", &None)?; state.serialize_field::>("month", &None)?; diff --git a/components/content/src/sorting.rs b/components/content/src/sorting.rs index df3c3e82..94bec530 100644 --- a/components/content/src/sorting.rs +++ b/components/content/src/sorting.rs @@ -11,7 +11,7 @@ use front_matter::SortBy; /// To remove if `sort_pages` is changed to work on borrowed values /// This cannot be used in `sort_pages` currently as it takes &&Page instead of &Page pub fn sort_pages_by_date(a: &&Page, b: &&Page) -> Ordering { - let ord = b.meta.date().unwrap().cmp(&a.meta.date().unwrap()); + let ord = b.meta.datetime.unwrap().cmp(&a.meta.datetime.unwrap()); if ord == Ordering::Equal { a.permalink.cmp(&b.permalink) } else { @@ -33,7 +33,7 @@ pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { .into_par_iter() .partition(|page| { match sort_by { - SortBy::Date => page.meta.date.is_some(), + SortBy::Date => page.meta.datetime.is_some(), SortBy::Weight => page.meta.weight.is_some(), _ => unreachable!() } @@ -42,7 +42,7 @@ pub fn sort_pages(pages: Vec, sort_by: SortBy) -> (Vec, Vec) { match sort_by { SortBy::Date => { can_be_sorted.par_sort_unstable_by(|a, b| { - let ord = b.meta.date().unwrap().cmp(&a.meta.date().unwrap()); + let ord = b.meta.datetime.unwrap().cmp(&a.meta.datetime.unwrap()); if ord == Ordering::Equal { a.permalink.cmp(&b.permalink) } else { @@ -159,6 +159,7 @@ mod tests { fn create_page_with_date(date: &str) -> Page { let mut front_matter = PageFrontMatter::default(); front_matter.date = Some(date.to_string()); + front_matter.date_to_datetime(); Page::new("content/hello.md", front_matter) } diff --git a/components/front_matter/src/page.rs b/components/front_matter/src/page.rs index fd8ebc98..4aa19921 100644 --- a/components/front_matter/src/page.rs +++ b/components/front_matter/src/page.rs @@ -62,7 +62,7 @@ fn fix_toml_dates(table: Map) -> Value { /// The front matter of every page -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Deserialize)] #[serde(default)] pub struct PageFrontMatter { /// of the page @@ -72,6 +72,12 @@ pub struct PageFrontMatter { /// Date if we want to order pages (ie blog post) #[serde(default, deserialize_with = "from_toml_datetime")] pub date: Option<String>, + /// Chrono converted datetime + #[serde(default, skip_deserializing)] + pub datetime: Option<NaiveDateTime>, + /// The converted date into a (year, month, day) tuple + #[serde(default, skip_deserializing)] + pub datetime_tuple: Option<(i32, u32, u32)>, /// Whether this page is a draft and should be ignored for pagination etc pub draft: bool, /// The page slug. Will be used instead of the filename if present @@ -124,12 +130,16 @@ impl PageFrontMatter { Value::Object(o) => o, _ => unreachable!("Got something other than a table in page extra"), }; + + f.date_to_datetime(); + Ok(f) } /// Converts the TOML datetime to a Chrono naive datetime - pub fn date(&self) -> Option<NaiveDateTime> { - if let Some(ref d) = self.date { + /// Also grabs the year/month/day tuple that will be used in serialization + pub fn date_to_datetime(&mut self) { + self.datetime = if let Some(ref d) = self.date { if d.contains('T') { DateTime::parse_from_rfc3339(&d).ok().and_then(|s| Some(s.naive_local())) } else { @@ -137,7 +147,13 @@ impl PageFrontMatter { } } else { None - } + }; + + self.datetime_tuple = if let Some(ref dt) = self.datetime { + Some((dt.year(), dt.month(), dt.day())) + } else { + None + }; } pub fn order(&self) -> usize { @@ -155,6 +171,8 @@ impl Default for PageFrontMatter { title: None, description: None, date: None, + datetime: None, + datetime_tuple: None, draft: false, slug: None, path: None,