diff --git a/Cargo.lock b/Cargo.lock index bb9aeb4cf..c0130f0b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -735,7 +735,6 @@ dependencies = [ "tempfile", "test-strategy", "time", - "ubyte", "xz2", "zip", "zstd", @@ -1188,12 +1187,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "ubyte" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c81f0dae7d286ad0d9366d7679a77934cfc3cf3a8d67e82669794412b2368fe6" - [[package]] name = "unarray" version = "0.1.4" diff --git a/Cargo.toml b/Cargo.toml index 0297c882a..2f2b8fd07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,6 @@ snap = "1.1.0" tar = "0.4.40" tempfile = "3.8.0" time = { version = "0.3.28", default-features = false } -ubyte = { version = "0.10.3", default-features = false } xz2 = "0.1.7" zip = { version = "0.6.6", default-features = false, features = ["time"] } zstd = { version = "0.12.4", default-features = false } diff --git a/src/archive/tar.rs b/src/archive/tar.rs index 54f144f95..d37628819 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -10,13 +10,12 @@ use std::{ use fs_err as fs; use same_file::Handle; -use ubyte::ToByteUnit; use crate::{ error::FinalError, info, list::FileInArchive, - utils::{self, EscapedPathDisplay, FileVisibilityPolicy}, + utils::{self, Bytes, EscapedPathDisplay, FileVisibilityPolicy}, warning, }; @@ -41,7 +40,7 @@ pub fn unpack_archive(reader: Box, output_folder: &Path, quiet: bool) inaccessible, "{:?} extracted. ({})", utils::strip_cur_dir(&output_folder.join(file.path()?)), - file.size().bytes(), + Bytes::new(file.size()), ); files_unpacked += 1; diff --git a/src/archive/zip.rs b/src/archive/zip.rs index 47d73637b..60cc440db 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -14,7 +14,6 @@ use filetime::{set_file_mtime, FileTime}; use fs_err as fs; use same_file::Handle; use time::OffsetDateTime; -use ubyte::ToByteUnit; use zip::{self, read::ZipFile, DateTime, ZipArchive}; use crate::{ @@ -22,7 +21,7 @@ use crate::{ info, list::FileInArchive, utils::{ - self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir, + self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir, Bytes, EscapedPathDisplay, FileVisibilityPolicy, }, warning, @@ -74,7 +73,7 @@ where inaccessible, "{:?} extracted. ({})", file_path.display(), - file.size().bytes() + Bytes::new(file.size()), ); } diff --git a/src/utils/formatting.rs b/src/utils/formatting.rs index 7a409e5e9..fac5c1126 100644 --- a/src/utils/formatting.rs +++ b/src/utils/formatting.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, fmt::Display, path::Path}; +use std::{borrow::Cow, cmp, fmt::Display, path::Path}; use crate::CURRENT_DIRECTORY; @@ -86,3 +86,81 @@ pub fn nice_directory_display(path: &Path) -> Cow { to_utf(path) } } + +/// Struct useful to printing bytes as kB, MB, GB, etc. +pub struct Bytes(f64); + +impl Bytes { + const UNIT_PREFIXES: [&'static str; 6] = ["", "ki", "Mi", "Gi", "Ti", "Pi"]; + + /// Create a new Bytes. + pub fn new(bytes: u64) -> Self { + Self(bytes as f64) + } +} + +impl std::fmt::Display for Bytes { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let &Self(num) = self; + + debug_assert!(num >= 0.0); + if num < 1_f64 { + return write!(f, "{} B", num); + } + + let delimiter = 1000_f64; + let exponent = cmp::min((num.ln() / 6.90775).floor() as i32, 4); + + write!( + f, + "{:.2} {}B", + num / delimiter.powi(exponent), + Bytes::UNIT_PREFIXES[exponent as usize] + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_pretty_bytes_formatting() { + fn format_bytes(bytes: u64) -> String { + format!("{}", Bytes::new(bytes)) + } + let b = 1; + let kb = b * 1000; + let mb = kb * 1000; + let gb = mb * 1000; + + assert_eq!("0 B", format_bytes(0)); // This is weird + assert_eq!("1.00 B", format_bytes(b)); + assert_eq!("999.00 B", format_bytes(b * 999)); + assert_eq!("12.00 MiB", format_bytes(mb * 12)); + assert_eq!("123.00 MiB", format_bytes(mb * 123)); + assert_eq!("5.50 MiB", format_bytes(mb * 5 + kb * 500)); + assert_eq!("7.54 GiB", format_bytes(gb * 7 + 540 * mb)); + assert_eq!("1.20 TiB", format_bytes(gb * 1200)); + + // bytes + assert_eq!("234.00 B", format_bytes(234)); + assert_eq!("999.00 B", format_bytes(999)); + // kilobytes + assert_eq!("2.23 kiB", format_bytes(2234)); + assert_eq!("62.50 kiB", format_bytes(62500)); + assert_eq!("329.99 kiB", format_bytes(329990)); + // megabytes + assert_eq!("2.75 MiB", format_bytes(2750000)); + assert_eq!("55.00 MiB", format_bytes(55000000)); + assert_eq!("987.65 MiB", format_bytes(987654321)); + // gigabytes + assert_eq!("5.28 GiB", format_bytes(5280000000)); + assert_eq!("95.20 GiB", format_bytes(95200000000)); + assert_eq!("302.00 GiB", format_bytes(302000000000)); + assert_eq!("302.99 GiB", format_bytes(302990000000)); + // Weird aproximation cases: + assert_eq!("999.90 GiB", format_bytes(999900000000)); + assert_eq!("1.00 TiB", format_bytes(999990000000)); + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 42630bf5d..b6ea08e50 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -10,7 +10,9 @@ mod fs; mod question; pub use file_visibility::FileVisibilityPolicy; -pub use formatting::{nice_directory_display, pretty_format_list_of_paths, strip_cur_dir, to_utf, EscapedPathDisplay}; +pub use formatting::{ + nice_directory_display, pretty_format_list_of_paths, strip_cur_dir, to_utf, Bytes, EscapedPathDisplay, +}; pub use fs::{ cd_into_same_dir_as, clear_path, create_dir_if_non_existent, is_symlink, remove_file_or_dir, try_infer_extension, };