From 874d07f89d938268ee5d896d8ff6833797a57390 Mon Sep 17 00:00:00 2001
From: Allen Hsu <0allen.hsu@gmail.com>
Date: Fri, 13 Sep 2019 10:08:24 +1000
Subject: [PATCH] Create closure to do sorting.
---
src/core.rs | 3 +-
src/sort.rs | 194 ++++++++++++++++++++--------------------------------
2 files changed, 75 insertions(+), 122 deletions(-)
diff --git a/src/core.rs b/src/core.rs
index c188e2d..03d3ae8 100644
--- a/src/core.rs
+++ b/src/core.rs
@@ -118,7 +118,8 @@ impl Core {
}
fn sort(&self, metas: &mut Vec) {
- metas.sort_unstable_by(|a, b| sort::by_meta(a, b, &self.flags));
+ let sorter = sort::create_sorter(&self.flags);
+ metas.sort_unstable_by(|a, b| (sorter)(a, b));
for meta in metas {
if let Some(ref mut content) = meta.content {
diff --git a/src/sort.rs b/src/sort.rs
index 4ab6005..cee9cc5 100644
--- a/src/sort.rs
+++ b/src/sort.rs
@@ -2,126 +2,65 @@ use crate::flags::{DirOrderFlag, Flags, SortFlag, SortOrder};
use crate::meta::{FileType, Meta};
use std::cmp::Ordering;
-pub fn by_meta(a: &Meta, b: &Meta, flags: &Flags) -> Ordering {
- match flags.sort_by {
- SortFlag::Name => match flags.directory_order {
- DirOrderFlag::First => by_name_with_dirs_first(a, b, &flags),
- DirOrderFlag::None => by_name(a, b, &flags),
- DirOrderFlag::Last => by_name_with_files_first(a, b, &flags),
- },
- SortFlag::Size => match flags.directory_order {
- DirOrderFlag::First => by_size_with_dirs_first(a, b, &flags),
- DirOrderFlag::None => by_size(a, b, &flags),
- DirOrderFlag::Last => by_size_with_files_first(a, b, &flags),
- },
- SortFlag::Time => match flags.directory_order {
- DirOrderFlag::First => by_date_with_dirs_first(a, b, &flags),
- DirOrderFlag::None => by_date(a, b, &flags),
- DirOrderFlag::Last => by_date_with_files_first(a, b, &flags),
- },
- }
+pub type Sorter = Box Ordering>;
+
+pub fn create_sorter(flags: &Flags) -> Sorter {
+ let mut sorters: Vec<(SortOrder, Sorter)> = vec![];
+ match flags.directory_order {
+ DirOrderFlag::First => {
+ sorters.push((SortOrder::Default, Box::new(with_dirs_first)));
+ }
+ DirOrderFlag::Last => {
+ sorters.push((SortOrder::Reverse, Box::new(with_dirs_first)));
+ }
+ DirOrderFlag::None => {}
+ };
+ let other_sort = match flags.sort_by {
+ SortFlag::Name => by_name,
+ SortFlag::Size => by_size,
+ SortFlag::Time => by_date,
+ };
+ sorters.push((flags.sort_order, Box::new(other_sort)));
+
+ Box::new(move |a, b| {
+ for (direction, sorter) in sorters.iter() {
+ match (sorter)(a, b) {
+ Ordering::Equal => continue,
+ ordering => {
+ return match direction {
+ SortOrder::Reverse => ordering.reverse(),
+ SortOrder::Default => ordering,
+ }
+ }
+ }
+ }
+ Ordering::Equal
+ })
}
-fn by_size(a: &Meta, b: &Meta, flags: &Flags) -> Ordering {
- if flags.sort_order == SortOrder::Default {
- b.size.get_bytes().cmp(&a.size.get_bytes())
- } else {
- a.size.get_bytes().cmp(&b.size.get_bytes())
- }
-}
-
-fn by_size_with_dirs_first(a: &Meta, b: &Meta, flags: &Flags) -> Ordering {
+fn with_dirs_first(a: &Meta, b: &Meta) -> Ordering {
match (a.file_type, b.file_type) {
- (FileType::Directory { .. }, FileType::Directory { .. }) => by_size(a, b, &flags),
- (FileType::Directory { .. }, FileType::SymLink { is_dir: true }) => by_size(a, b, &flags),
- (FileType::SymLink { is_dir: true }, FileType::Directory { .. }) => by_size(a, b, &flags),
+ (FileType::Directory { .. }, FileType::Directory { .. }) => Ordering::Equal,
+ (FileType::Directory { .. }, FileType::SymLink { is_dir: true }) => Ordering::Equal,
+ (FileType::SymLink { is_dir: true }, FileType::Directory { .. }) => Ordering::Equal,
(FileType::Directory { .. }, _) => Ordering::Less,
(_, FileType::Directory { .. }) => Ordering::Greater,
(FileType::SymLink { is_dir: true }, _) => Ordering::Less,
(_, FileType::SymLink { is_dir: true }) => Ordering::Greater,
- _ => by_size(a, b, &flags),
+ _ => Ordering::Equal,
}
}
-fn by_size_with_files_first(a: &Meta, b: &Meta, flags: &Flags) -> Ordering {
- match (a.file_type, b.file_type) {
- (FileType::Directory { .. }, FileType::Directory { .. }) => by_size(a, b, &flags),
- (FileType::Directory { .. }, FileType::SymLink { is_dir: true }) => by_size(a, b, &flags),
- (FileType::SymLink { is_dir: true }, FileType::Directory { .. }) => by_size(a, b, &flags),
- (FileType::Directory { .. }, _) => Ordering::Greater,
- (_, FileType::Directory { .. }) => Ordering::Less,
- (FileType::SymLink { is_dir: true }, _) => Ordering::Greater,
- (_, FileType::SymLink { is_dir: true }) => Ordering::Less,
- _ => by_size(a, b, &flags),
- }
+fn by_size(a: &Meta, b: &Meta) -> Ordering {
+ b.size.get_bytes().cmp(&a.size.get_bytes())
}
-fn by_name(a: &Meta, b: &Meta, flags: &Flags) -> Ordering {
- if flags.sort_order == SortOrder::Default {
- a.name.cmp(&b.name)
- } else {
- b.name.cmp(&a.name)
- }
+fn by_name(a: &Meta, b: &Meta) -> Ordering {
+ a.name.cmp(&b.name)
}
-fn by_name_with_dirs_first(a: &Meta, b: &Meta, flags: &Flags) -> Ordering {
- match (a.file_type, b.file_type) {
- (FileType::Directory { .. }, FileType::Directory { .. }) => by_name(a, b, &flags),
- (FileType::Directory { .. }, FileType::SymLink { is_dir: true }) => by_name(a, b, &flags),
- (FileType::SymLink { is_dir: true }, FileType::Directory { .. }) => by_name(a, b, &flags),
- (FileType::Directory { .. }, _) => Ordering::Less,
- (_, FileType::Directory { .. }) => Ordering::Greater,
- (FileType::SymLink { is_dir: true }, _) => Ordering::Less,
- (_, FileType::SymLink { is_dir: true }) => Ordering::Greater,
- _ => by_name(a, b, &flags),
- }
-}
-
-fn by_name_with_files_first(a: &Meta, b: &Meta, flags: &Flags) -> Ordering {
- match (a.file_type, b.file_type) {
- (FileType::Directory { .. }, FileType::Directory { .. }) => by_name(a, b, &flags),
- (FileType::Directory { .. }, FileType::SymLink { is_dir: true }) => by_name(a, b, &flags),
- (FileType::SymLink { is_dir: true }, FileType::Directory { .. }) => by_name(a, b, &flags),
- (FileType::Directory { .. }, _) => Ordering::Greater,
- (_, FileType::Directory { .. }) => Ordering::Less,
- (FileType::SymLink { is_dir: true }, _) => Ordering::Greater,
- (_, FileType::SymLink { is_dir: true }) => Ordering::Less,
- _ => by_name(a, b, &flags),
- }
-}
-
-fn by_date(a: &Meta, b: &Meta, flags: &Flags) -> Ordering {
- if flags.sort_order == SortOrder::Default {
- b.date.cmp(&a.date).then(a.name.cmp(&b.name))
- } else {
- a.date.cmp(&b.date).then(b.name.cmp(&a.name))
- }
-}
-
-fn by_date_with_dirs_first(a: &Meta, b: &Meta, flags: &Flags) -> Ordering {
- match (a.file_type, b.file_type) {
- (FileType::Directory { .. }, FileType::Directory { .. }) => by_date(a, b, &flags),
- (FileType::Directory { .. }, FileType::SymLink { is_dir: true }) => by_date(a, b, &flags),
- (FileType::SymLink { is_dir: true }, FileType::Directory { .. }) => by_date(a, b, &flags),
- (FileType::Directory { .. }, _) => Ordering::Less,
- (_, FileType::Directory { .. }) => Ordering::Greater,
- (FileType::SymLink { is_dir: true }, _) => Ordering::Less,
- (_, FileType::SymLink { is_dir: true }) => Ordering::Greater,
- _ => by_date(a, b, &flags),
- }
-}
-
-fn by_date_with_files_first(a: &Meta, b: &Meta, flags: &Flags) -> Ordering {
- match (a.file_type, b.file_type) {
- (FileType::Directory { .. }, FileType::Directory { .. }) => by_date(a, b, &flags),
- (FileType::Directory { .. }, FileType::SymLink { is_dir: true }) => by_date(a, b, &flags),
- (FileType::SymLink { is_dir: true }, FileType::Directory { .. }) => by_date(a, b, &flags),
- (FileType::Directory { .. }, _) => Ordering::Greater,
- (_, FileType::Directory { .. }) => Ordering::Less,
- (FileType::SymLink { is_dir: true }, _) => Ordering::Greater,
- (_, FileType::SymLink { is_dir: true }) => Ordering::Less,
- _ => by_date(a, b, &flags),
- }
+fn by_date(a: &Meta, b: &Meta) -> Ordering {
+ b.date.cmp(&a.date).then(a.name.cmp(&b.name))
}
#[cfg(test)]
@@ -133,7 +72,7 @@ mod tests {
use tempfile::tempdir;
#[test]
- fn test_sort_by_meta_by_name_with_dirs_first() {
+ fn test_sort_create_sorter_by_name_with_dirs_first() {
let tmp_dir = tempdir().expect("failed to create temp dir");
// Create the file;
@@ -150,15 +89,18 @@ mod tests {
flags.directory_order = DirOrderFlag::First;
// Sort with the dirs first
- assert_eq!(by_meta(&meta_a, &meta_z, &flags), Ordering::Greater);
+ let sorter = create_sorter(&flags);
+ assert_eq!((sorter)(&meta_a, &meta_z), Ordering::Greater);
// Sort with the dirs first (the dirs stay first)
flags.sort_order = SortOrder::Reverse;
- assert_eq!(by_meta(&meta_a, &meta_z, &flags), Ordering::Greater);
+
+ let sorter = create_sorter(&flags);
+ assert_eq!((sorter)(&meta_a, &meta_z), Ordering::Greater);
}
#[test]
- fn test_sort_by_meta_by_name_with_files_first() {
+ fn test_sort_create_sorter_by_name_with_files_first() {
let tmp_dir = tempdir().expect("failed to create temp dir");
// Create the file;
@@ -175,14 +117,16 @@ mod tests {
flags.directory_order = DirOrderFlag::Last;
// Sort with file first
- assert_eq!(by_meta(&meta_a, &meta_z, &flags), Ordering::Less);
+ let sorter = create_sorter(&flags);
+ assert_eq!((sorter)(&meta_a, &meta_z), Ordering::Less);
// Sort with file first reversed (thie files stay first)
- assert_eq!(by_meta(&meta_a, &meta_z, &flags), Ordering::Less);
+ let sorter = create_sorter(&flags);
+ assert_eq!((sorter)(&meta_a, &meta_z), Ordering::Less);
}
#[test]
- fn test_sort_by_meta_by_name_unordered() {
+ fn test_sort_create_sorter_by_name_unordered() {
let tmp_dir = tempdir().expect("failed to create temp dir");
// Create the file;
@@ -199,15 +143,18 @@ mod tests {
flags.directory_order = DirOrderFlag::None;
// Sort by name unordered
- assert_eq!(by_meta(&meta_a, &meta_z, &flags), Ordering::Less);
+ let sorter = create_sorter(&flags);
+ assert_eq!((sorter)(&meta_a, &meta_z), Ordering::Less);
// Sort by name unordered
flags.sort_order = SortOrder::Reverse;
- assert_eq!(by_meta(&meta_a, &meta_z, &flags), Ordering::Greater);
+
+ let sorter = create_sorter(&flags);
+ assert_eq!((sorter)(&meta_a, &meta_z), Ordering::Greater);
}
#[test]
- fn test_sort_by_meta_by_name_unordered_2() {
+ fn test_sort_create_sorter_by_name_unordered_2() {
let tmp_dir = tempdir().expect("failed to create temp dir");
// Create the file;
@@ -224,15 +171,18 @@ mod tests {
flags.directory_order = DirOrderFlag::None;
// Sort by name unordered
- assert_eq!(by_meta(&meta_a, &meta_z, &flags), Ordering::Greater);
+ let sorter = create_sorter(&flags);
+ assert_eq!((sorter)(&meta_a, &meta_z), Ordering::Greater);
// Sort by name unordered reversed
flags.sort_order = SortOrder::Reverse;
- assert_eq!(by_meta(&meta_a, &meta_z, &flags), Ordering::Less);
+
+ let sorter = create_sorter(&flags);
+ assert_eq!((sorter)(&meta_a, &meta_z), Ordering::Less);
}
#[test]
- fn test_sort_by_meta_by_time() {
+ fn test_sort_create_sorter_by_time() {
let tmp_dir = tempdir().expect("failed to create temp dir");
// Create the file;
@@ -270,10 +220,12 @@ mod tests {
flags.sort_by = SortFlag::Time;
// Sort by time
- assert_eq!(by_meta(&meta_a, &meta_z, &flags), Ordering::Less);
+ let sorter = create_sorter(&flags);
+ assert_eq!((sorter)(&meta_a, &meta_z), Ordering::Less);
// Sort by time reversed
flags.sort_order = SortOrder::Reverse;
- assert_eq!(by_meta(&meta_a, &meta_z, &flags), Ordering::Greater);
+ let sorter = create_sorter(&flags);
+ assert_eq!((sorter)(&meta_a, &meta_z), Ordering::Greater);
}
}