ferroui_base/utilities/
byte_size_helper.rs1use super::CultureInfo;
2use crate::data::converters::composite_format::{format_with, FormatArg};
3
4const FORMAT_TEMPLATE_SEPARATED: &str = "{0}{1:0.#} {2}";
5const FORMAT_TEMPLATE: &str = "{0}{1:0.#}{2}";
6
7const PREFIXES: [&str; 9] = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
8
9pub struct ByteSizeHelper;
11
12impl ByteSizeHelper {
13 pub fn to_string(bytes: u64, separate: bool) -> String {
20 let culture = CultureInfo::current_culture();
21
22 if bytes == 0 {
23 let template = if separate { FORMAT_TEMPLATE_SEPARATED } else { FORMAT_TEMPLATE };
24 return format_with(template, &[FormatArg::Null, FormatArg::I32(0), FormatArg::Str(PREFIXES[0])], &culture)
25 .expect("the size format is valid");
26 }
27
28 let abs_size = (bytes as f64).abs();
29 let fp_power = abs_size.ln() / 1000f64.ln();
30 let int_power = fp_power as i32;
31 let i_unit = if int_power >= PREFIXES.len() as i32 { PREFIXES.len() - 1 } else { int_power as usize };
32 let norm_size = abs_size / 1000f64.powi(i_unit as i32);
33
34 format_with(FORMAT_TEMPLATE, &[FormatArg::Null, FormatArg::F64(norm_size), FormatArg::Str(PREFIXES[i_unit])], &culture)
36 .expect("the size format is valid")
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
44
45 #[test]
46 fn zero_honours_the_separator() {
47 assert_eq!("0 B", ByteSizeHelper::to_string(0, true));
48 assert_eq!("0B", ByteSizeHelper::to_string(0, false));
49 }
50
51 #[test]
52 fn non_zero_sizes_use_decimal_units_without_separator() {
53 assert_eq!("999B", ByteSizeHelper::to_string(999, true));
54 assert_eq!("1KB", ByteSizeHelper::to_string(1000, true));
55 assert_eq!("1.5KB", ByteSizeHelper::to_string(1500, false));
56 assert_eq!("2.5MB", ByteSizeHelper::to_string(2_500_000, true));
57 assert_eq!("18.4EB", ByteSizeHelper::to_string(u64::MAX, true));
58 }
59}