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); } }