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 {
if flags.display_tree {
return by_name_with_files_first(a, b, flags);
}
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::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),
},
}
}
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_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 { .. }, _) => Ordering::Less,
(_, FileType::Directory { .. }) => 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 { .. }, _) => Ordering::Greater,
(_, FileType::Directory { .. }) => 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 { .. }, _) => Ordering::Less,
(_, FileType::Directory { .. }) => 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 { .. }, _) => Ordering::Greater,
(_, FileType::Directory { .. }) => Ordering::Less,
_ => by_date(a, b, flags),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::flags::Flags;
use std::fs::{create_dir, File};
use std::process::Command;
use tempdir::TempDir;
#[test]
fn test_sort_by_meta_by_name_with_dirs_first() {
let tmp_dir = TempDir::new("test_dir").expect("failed to create temp dir");
let path_a = tmp_dir.path().join("zzz");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
let path_z = tmp_dir.path().join("aaa");
create_dir(&path_z).expect("failed to create dir");
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
let mut flags = Flags::default();
flags.directory_order = DirOrderFlag::First;
assert_eq!(by_meta(&meta_a, &meta_z, flags), Ordering::Greater);
flags.sort_order = SortOrder::Reverse;
assert_eq!(by_meta(&meta_a, &meta_z, flags), Ordering::Greater);
}
#[test]
fn test_sort_by_meta_by_name_with_files_first() {
let tmp_dir = TempDir::new("test_dir").expect("failed to create temp dir");
let path_a = tmp_dir.path().join("zzz");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
let path_z = tmp_dir.path().join("aaa");
create_dir(&path_z).expect("failed to create dir");
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
let mut flags = Flags::default();
flags.directory_order = DirOrderFlag::Last;
assert_eq!(by_meta(&meta_a, &meta_z, flags), Ordering::Less);
assert_eq!(by_meta(&meta_a, &meta_z, flags), Ordering::Less);
}
#[test]
fn test_sort_by_meta_by_name_unordered() {
let tmp_dir = TempDir::new("test_dir").expect("failed to create temp dir");
let path_a = tmp_dir.path().join("aaa");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
let path_z = tmp_dir.path().join("zzz");
create_dir(&path_z).expect("failed to create dir");
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
let mut flags = Flags::default();
flags.directory_order = DirOrderFlag::None;
assert_eq!(by_meta(&meta_a, &meta_z, flags), Ordering::Less);
flags.sort_order = SortOrder::Reverse;
assert_eq!(by_meta(&meta_a, &meta_z, flags), Ordering::Greater);
}
#[test]
fn test_sort_by_meta_by_name_unordered_2() {
let tmp_dir = TempDir::new("test_dir").expect("failed to create temp dir");
let path_a = tmp_dir.path().join("zzz");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
let path_z = tmp_dir.path().join("aaa");
create_dir(&path_z).expect("failed to create dir");
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
let mut flags = Flags::default();
flags.directory_order = DirOrderFlag::None;
assert_eq!(by_meta(&meta_a, &meta_z, flags), Ordering::Greater);
flags.sort_order = SortOrder::Reverse;
assert_eq!(by_meta(&meta_a, &meta_z, flags), Ordering::Less);
}
#[test]
fn test_sort_by_meta_by_time() {
let tmp_dir = TempDir::new("test_dir").expect("failed to create temp dir");
let path_a = tmp_dir.path().join("aaa");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
let path_z = tmp_dir.path().join("zzz");
File::create(&path_z).expect("failed to create file");
let success = Command::new("touch")
.arg("-t")
.arg("198511160000")
.arg(&path_z)
.status()
.unwrap()
.success();
assert_eq!(true, success, "failed to exec mkfifo");
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
let mut flags = Flags::default();
flags.sort_by = SortFlag::Time;
assert_eq!(by_meta(&meta_a, &meta_z, flags), Ordering::Less);
flags.sort_order = SortOrder::Reverse;
assert_eq!(by_meta(&meta_a, &meta_z, flags), Ordering::Greater);
}
}