You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

225 lines
6.6KB

  1. use std::cmp::Ordering;
  2. use rayon::prelude::*;
  3. use slotmap::Key;
  4. use chrono::NaiveDateTime;
  5. use content::Page;
  6. // Used by the RSS feed
  7. pub fn sort_actual_pages_by_date(a: &&Page, b: &&Page) -> Ordering {
  8. let ord = b.meta.datetime.unwrap().cmp(&a.meta.datetime.unwrap());
  9. if ord == Ordering::Equal {
  10. a.permalink.cmp(&b.permalink)
  11. } else {
  12. ord
  13. }
  14. }
  15. // TODO: unify both sort_ functions
  16. // TODO: add back sorting tests
  17. pub fn sort_pages_by_date(pages: Vec<(&Key, Option<NaiveDateTime>, &str)>) -> (Vec<Key>, Vec<Key>) {
  18. let (mut can_be_sorted, cannot_be_sorted): (Vec<_>, Vec<_>) = pages
  19. .into_par_iter()
  20. .partition(|page| page.1.is_some());
  21. can_be_sorted
  22. .par_sort_unstable_by(|a, b| {
  23. let ord = b.1.unwrap().cmp(&a.1.unwrap());
  24. if ord == Ordering::Equal {
  25. a.2.cmp(&b.2)
  26. } else {
  27. ord
  28. }
  29. });
  30. (can_be_sorted.iter().map(|p| *p.0).collect(), cannot_be_sorted.iter().map(|p| *p.0).collect())
  31. }
  32. pub fn sort_pages_by_weight(pages: Vec<(&Key, Option<usize>, &str)>) -> (Vec<Key>, Vec<Key>) {
  33. let (mut can_be_sorted, cannot_be_sorted): (Vec<_>, Vec<_>) = pages
  34. .into_par_iter()
  35. .partition(|page| page.1.is_some());
  36. can_be_sorted
  37. .par_sort_unstable_by(|a, b| {
  38. let ord = a.1.unwrap().cmp(&b.1.unwrap());
  39. if ord == Ordering::Equal {
  40. a.2.cmp(&b.2)
  41. } else {
  42. ord
  43. }
  44. });
  45. (can_be_sorted.iter().map(|p| *p.0).collect(), cannot_be_sorted.iter().map(|p| *p.0).collect())
  46. }
  47. pub fn find_siblings(sorted: Vec<(&Key, bool)>) -> Vec<(Key, Option<Key>, Option<Key>)> {
  48. let mut res = Vec::with_capacity(sorted.len());
  49. let length = sorted.len();
  50. for (i, (key, is_draft)) in sorted.iter().enumerate() {
  51. if *is_draft {
  52. res.push((**key, None, None));
  53. continue;
  54. }
  55. let mut with_siblings = (**key, None, None);
  56. if i > 0 {
  57. let mut j = i;
  58. loop {
  59. if j == 0 {
  60. break;
  61. }
  62. j -= 1;
  63. if sorted[j].1 {
  64. continue;
  65. }
  66. // lighter / later
  67. with_siblings.1 = Some(*sorted[j].0);
  68. break;
  69. }
  70. }
  71. if i < length - 1 {
  72. let mut j = i;
  73. loop {
  74. if j == length - 1 {
  75. break;
  76. }
  77. j += 1;
  78. if sorted[j].1 {
  79. continue;
  80. }
  81. // heavier/earlier
  82. with_siblings.2 = Some(*sorted[j].0);
  83. break;
  84. }
  85. }
  86. res.push(with_siblings);
  87. }
  88. res
  89. }
  90. #[cfg(test)]
  91. mod tests {
  92. use slotmap::DenseSlotMap;
  93. use front_matter::{PageFrontMatter};
  94. use content::Page;
  95. use super::{sort_pages_by_date, sort_pages_by_weight, find_siblings};
  96. fn create_page_with_date(date: &str) -> Page {
  97. let mut front_matter = PageFrontMatter::default();
  98. front_matter.date = Some(date.to_string());
  99. front_matter.date_to_datetime();
  100. Page::new("content/hello.md", front_matter)
  101. }
  102. fn create_page_with_weight(weight: usize) -> Page {
  103. let mut front_matter = PageFrontMatter::default();
  104. front_matter.weight = Some(weight);
  105. Page::new("content/hello.md", front_matter)
  106. }
  107. #[test]
  108. fn can_sort_by_dates() {
  109. let mut dense = DenseSlotMap::new();
  110. let page1 = create_page_with_date("2018-01-01");
  111. let key1 = dense.insert(page1.clone());
  112. let page2 = create_page_with_date("2017-01-01");
  113. let key2 = dense.insert(page2.clone());
  114. let page3 = create_page_with_date("2019-01-01");
  115. let key3 = dense.insert(page3.clone());
  116. let input = vec![
  117. (&key1, page1.meta.datetime, page1.permalink.as_ref()),
  118. (&key2, page2.meta.datetime, page2.permalink.as_ref()),
  119. (&key3, page3.meta.datetime, page3.permalink.as_ref()),
  120. ];
  121. let (pages, _) = sort_pages_by_date(input);
  122. // Should be sorted by date
  123. assert_eq!(pages[0], key3);
  124. assert_eq!(pages[1], key1);
  125. assert_eq!(pages[2], key2);
  126. }
  127. #[test]
  128. fn can_sort_by_weight() {
  129. let mut dense = DenseSlotMap::new();
  130. let page1 = create_page_with_weight(2);
  131. let key1 = dense.insert(page1.clone());
  132. let page2 = create_page_with_weight(3);
  133. let key2 = dense.insert(page2.clone());
  134. let page3 = create_page_with_weight(1);
  135. let key3 = dense.insert(page3.clone());
  136. let input = vec![
  137. (&key1, page1.meta.weight, page1.permalink.as_ref()),
  138. (&key2, page2.meta.weight, page2.permalink.as_ref()),
  139. (&key3, page3.meta.weight, page3.permalink.as_ref()),
  140. ];
  141. let (pages, _) = sort_pages_by_weight(input);
  142. // Should be sorted by weight
  143. assert_eq!(pages[0], key3);
  144. assert_eq!(pages[1], key1);
  145. assert_eq!(pages[2], key2);
  146. }
  147. #[test]
  148. fn ignore_page_with_missing_field() {
  149. let mut dense = DenseSlotMap::new();
  150. let page1 = create_page_with_weight(2);
  151. let key1 = dense.insert(page1.clone());
  152. let page2 = create_page_with_weight(3);
  153. let key2 = dense.insert(page2.clone());
  154. let page3 = create_page_with_date("2019-01-01");
  155. let key3 = dense.insert(page3.clone());
  156. let input = vec![
  157. (&key1, page1.meta.weight, page1.permalink.as_ref()),
  158. (&key2, page2.meta.weight, page2.permalink.as_ref()),
  159. (&key3, page3.meta.weight, page3.permalink.as_ref()),
  160. ];
  161. let (pages,unsorted) = sort_pages_by_weight(input);
  162. assert_eq!(pages.len(), 2);
  163. assert_eq!(unsorted.len(), 1);
  164. }
  165. #[test]
  166. fn can_find_siblings() {
  167. let mut dense = DenseSlotMap::new();
  168. let page1 = create_page_with_weight(1);
  169. let key1 = dense.insert(page1.clone());
  170. let page2 = create_page_with_weight(2);
  171. let key2 = dense.insert(page2.clone());
  172. let page3 = create_page_with_weight(3);
  173. let key3 = dense.insert(page3.clone());
  174. let input = vec![
  175. (&key1, page1.is_draft()),
  176. (&key2, page2.is_draft()),
  177. (&key3, page3.is_draft()),
  178. ];
  179. let pages = find_siblings(input);
  180. assert_eq!(pages[0].1, None);
  181. assert_eq!(pages[0].2, Some(key2));
  182. assert_eq!(pages[1].1, Some(key1));
  183. assert_eq!(pages[1].2, Some(key3));
  184. assert_eq!(pages[2].1, Some(key2));
  185. assert_eq!(pages[2].2, None);
  186. }
  187. }