Create closure to do sorting.

This commit is contained in:
Allen Hsu 2019-09-13 10:08:24 +10:00 committed by Abin Simon
parent 2603261a4a
commit 874d07f89d
2 changed files with 75 additions and 122 deletions

View file

@ -118,7 +118,8 @@ impl Core {
}
fn sort(&self, metas: &mut Vec<Meta>) {
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 {

View file

@ -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<dyn Fn(&Meta, &Meta) -> 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);
}
}