|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- use std::cmp::Ordering;
-
- use chrono::NaiveDateTime;
- use rayon::prelude::*;
- use slotmap::Key;
-
- use content::Page;
-
- /// Used by the RSS feed
- /// There to not have to import sorting stuff in the site crate
- pub fn sort_actual_pages_by_date(a: &&Page, b: &&Page) -> Ordering {
- let ord = b.meta.datetime.unwrap().cmp(&a.meta.datetime.unwrap());
- if ord == Ordering::Equal {
- a.permalink.cmp(&b.permalink)
- } else {
- ord
- }
- }
-
- /// Takes a list of (page key, date, permalink) and sort them by dates if possible
- /// Pages without date will be put in the unsortable bucket
- /// The permalink is used to break ties
- pub fn sort_pages_by_date(pages: Vec<(&Key, Option<NaiveDateTime>, &str)>) -> (Vec<Key>, Vec<Key>) {
- let (mut can_be_sorted, cannot_be_sorted): (Vec<_>, Vec<_>) =
- pages.into_par_iter().partition(|page| page.1.is_some());
-
- can_be_sorted.par_sort_unstable_by(|a, b| {
- let ord = b.1.unwrap().cmp(&a.1.unwrap());
- if ord == Ordering::Equal {
- a.2.cmp(&b.2)
- } else {
- ord
- }
- });
-
- (can_be_sorted.iter().map(|p| *p.0).collect(), cannot_be_sorted.iter().map(|p| *p.0).collect())
- }
-
- /// Takes a list of (page key, weight, permalink) and sort them by weight if possible
- /// Pages without weight will be put in the unsortable bucket
- /// The permalink is used to break ties
- pub fn sort_pages_by_weight(pages: Vec<(&Key, Option<usize>, &str)>) -> (Vec<Key>, Vec<Key>) {
- let (mut can_be_sorted, cannot_be_sorted): (Vec<_>, Vec<_>) =
- pages.into_par_iter().partition(|page| page.1.is_some());
-
- can_be_sorted.par_sort_unstable_by(|a, b| {
- let ord = a.1.unwrap().cmp(&b.1.unwrap());
- if ord == Ordering::Equal {
- a.2.cmp(&b.2)
- } else {
- ord
- }
- });
-
- (can_be_sorted.iter().map(|p| *p.0).collect(), cannot_be_sorted.iter().map(|p| *p.0).collect())
- }
-
- /// Find the lighter/heavier and earlier/later pages for all pages having a date/weight
- /// and that are not drafts.
- pub fn find_siblings(sorted: Vec<(&Key, bool)>) -> Vec<(Key, Option<Key>, Option<Key>)> {
- let mut res = Vec::with_capacity(sorted.len());
- let length = sorted.len();
-
- for (i, (key, is_draft)) in sorted.iter().enumerate() {
- if *is_draft {
- res.push((**key, None, None));
- continue;
- }
- let mut with_siblings = (**key, None, None);
-
- if i > 0 {
- let mut j = i;
- loop {
- if j == 0 {
- break;
- }
-
- j -= 1;
-
- if sorted[j].1 {
- continue;
- }
- // lighter / later
- with_siblings.1 = Some(*sorted[j].0);
- break;
- }
- }
-
- if i < length - 1 {
- let mut j = i;
- loop {
- if j == length - 1 {
- break;
- }
-
- j += 1;
-
- if sorted[j].1 {
- continue;
- }
-
- // heavier/earlier
- with_siblings.2 = Some(*sorted[j].0);
- break;
- }
- }
- res.push(with_siblings);
- }
-
- res
- }
-
- #[cfg(test)]
- mod tests {
- use slotmap::DenseSlotMap;
- use std::path::PathBuf;
-
- use super::{find_siblings, sort_pages_by_date, sort_pages_by_weight};
- use content::Page;
- use front_matter::PageFrontMatter;
-
- 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, &PathBuf::new())
- }
-
- fn create_page_with_weight(weight: usize) -> Page {
- let mut front_matter = PageFrontMatter::default();
- front_matter.weight = Some(weight);
- Page::new("content/hello.md", front_matter, &PathBuf::new())
- }
-
- #[test]
- fn can_sort_by_dates() {
- let mut dense = DenseSlotMap::new();
- let page1 = create_page_with_date("2018-01-01");
- let key1 = dense.insert(page1.clone());
- let page2 = create_page_with_date("2017-01-01");
- let key2 = dense.insert(page2.clone());
- let page3 = create_page_with_date("2019-01-01");
- let key3 = dense.insert(page3.clone());
-
- let input = vec![
- (&key1, page1.meta.datetime, page1.permalink.as_ref()),
- (&key2, page2.meta.datetime, page2.permalink.as_ref()),
- (&key3, page3.meta.datetime, page3.permalink.as_ref()),
- ];
- let (pages, _) = sort_pages_by_date(input);
- // Should be sorted by date
- assert_eq!(pages[0], key3);
- assert_eq!(pages[1], key1);
- assert_eq!(pages[2], key2);
- }
-
- #[test]
- fn can_sort_by_weight() {
- let mut dense = DenseSlotMap::new();
- let page1 = create_page_with_weight(2);
- let key1 = dense.insert(page1.clone());
- let page2 = create_page_with_weight(3);
- let key2 = dense.insert(page2.clone());
- let page3 = create_page_with_weight(1);
- let key3 = dense.insert(page3.clone());
-
- let input = vec![
- (&key1, page1.meta.weight, page1.permalink.as_ref()),
- (&key2, page2.meta.weight, page2.permalink.as_ref()),
- (&key3, page3.meta.weight, page3.permalink.as_ref()),
- ];
- let (pages, _) = sort_pages_by_weight(input);
- // Should be sorted by weight
- assert_eq!(pages[0], key3);
- assert_eq!(pages[1], key1);
- assert_eq!(pages[2], key2);
- }
-
- #[test]
- fn ignore_page_with_missing_field() {
- let mut dense = DenseSlotMap::new();
- let page1 = create_page_with_weight(2);
- let key1 = dense.insert(page1.clone());
- let page2 = create_page_with_weight(3);
- let key2 = dense.insert(page2.clone());
- let page3 = create_page_with_date("2019-01-01");
- let key3 = dense.insert(page3.clone());
-
- let input = vec![
- (&key1, page1.meta.weight, page1.permalink.as_ref()),
- (&key2, page2.meta.weight, page2.permalink.as_ref()),
- (&key3, page3.meta.weight, page3.permalink.as_ref()),
- ];
-
- let (pages, unsorted) = sort_pages_by_weight(input);
- assert_eq!(pages.len(), 2);
- assert_eq!(unsorted.len(), 1);
- }
-
- #[test]
- fn can_find_siblings() {
- let mut dense = DenseSlotMap::new();
- let page1 = create_page_with_weight(1);
- let key1 = dense.insert(page1.clone());
- let page2 = create_page_with_weight(2);
- let key2 = dense.insert(page2.clone());
- let page3 = create_page_with_weight(3);
- let key3 = dense.insert(page3.clone());
-
- let input =
- vec![(&key1, page1.is_draft()), (&key2, page2.is_draft()), (&key3, page3.is_draft())];
-
- let pages = find_siblings(input);
-
- assert_eq!(pages[0].1, None);
- assert_eq!(pages[0].2, Some(key2));
-
- assert_eq!(pages[1].1, Some(key1));
- assert_eq!(pages[1].2, Some(key3));
-
- assert_eq!(pages[2].1, Some(key2));
- assert_eq!(pages[2].2, None);
- }
- }
|