mod args;
mod enumerations;
mod excel;
mod structures;
cfg_if::cfg_if! {
if #[cfg(feature = "walkdir")] {
mod with_walkdir;
pub use with_walkdir::get_all_files;
} else {
mod with_jwalk;
pub use with_jwalk::get_all_files;
}
}
pub use self::{
args::Arguments,
enumerations::algo::{Algorithm, PathBufExtension},
structures::file_info::{FileExtension, FileInfo},
structures::group_info::{GroupExtension, GroupInfo},
structures::key_info::Key,
structures::path_info::PathInfo,
structures::total_info::TotalInfo,
};
pub use excel::write_xlsx;
use serde::Serializer;
use std::{
fs::{self, File},
path::{Path, PathBuf},
process::Command,
str,
};
pub type MyError = Box<dyn std::error::Error + Send + Sync>;
pub type MyResult<T> = Result<T, MyError>;
const STACK_SIZE: usize = 64 * 1024 * 1024;
const SEPARATOR: char = '.'; pub const CSV_FILENAME: &str = "fdf.csv";
pub const XLSX_FILENAME: &str = "fdf.xlsx";
pub fn set_env_variables() {
std::env::set_var("RUST_MIN_STACK", STACK_SIZE.to_string());
}
pub fn open_file<P>(path: &P) -> MyResult<File>
where
P: AsRef<Path> + std::fmt::Debug,
{
let file: File = match fs::OpenOptions::new()
.read(true)
.write(false) .create(false) .open(path)
{
Ok(file) => file,
Err(error) => {
eprintln!("Failed to open file {path:?}");
eprintln!("Perhaps some temporary files no longer exist!");
eprintln!("Or lack of permission to read this file!");
panic!("{error}");
}
};
Ok(file)
}
pub fn get_path(arguments: &Arguments) -> MyResult<PathBuf> {
let path: PathBuf = match &arguments.input_dir {
Some(path) => path.to_owned(),
None => PathBuf::from("."),
};
if arguments.full_path {
Ok(fs::canonicalize(path)?) } else {
Ok(path) }
}
pub fn my_print(buffer: &[u8]) -> MyResult<()> {
let print_msg = match str::from_utf8(buffer) {
Ok(valid_uft8) => valid_uft8,
Err(error) => {
eprintln!("fn my_print()");
eprintln!("Invalid UTF-8 sequence!");
panic!("{error}");
}
};
print!("{print_msg}");
Ok(())
}
pub fn clear_terminal_screen() {
if cfg!(target_os = "windows") {
Command::new("cmd")
.args(["/c", "cls"])
.spawn()
.expect("cls command failed to start")
.wait()
.expect("failed to wait");
} else {
Command::new("tput") .arg("reset")
.spawn()
.expect("tput command failed to start")
.wait()
.expect("failed to wait");
};
}
pub fn split_and_insert(integer: usize, insert: char) -> String {
let group_size = 3;
let integer_str = integer.to_string();
if integer <= 999 {
return integer_str;
}
let string_splitted: String = integer_str
.chars()
.enumerate()
.flat_map(|(i, c)| {
if (integer_str.len() - i) % group_size == 0 && i > 0 {
Some(insert)
} else {
None
}
.into_iter()
.chain(std::iter::once(c))
})
.collect::<String>();
string_splitted
}
pub fn add_thousands_separator<S>(size: &usize, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_str(&format!("{} bytes", &split_and_insert(*size, SEPARATOR)))
}
#[cfg(test)]
mod test_lib {
use super::*;
#[test]
fn split_integer_into_groups() {
let mut result: Vec<String> = Vec::new();
for integer in [
0, 1, 12, 999, 1000, 1001, 1234, 12345, 123456, 1234567, 12345678,
] {
let integer_splitted: String = split_and_insert(integer, '_');
println!("integer: {integer:<8} ; with thousands sep: {integer_splitted}");
result.push(integer_splitted);
}
let valid = vec![
"0",
"1",
"12",
"999",
"1_000",
"1_001",
"1_234",
"12_345",
"123_456",
"1_234_567",
"12_345_678",
];
assert_eq!(valid, result);
}
}