1mod download_acceleration;
2mod download_speed;
3mod file_size;
4
5use std::fmt::{self, Display};
6
7pub use download_acceleration::DownloadAcceleration;
8pub use download_speed::DownloadSpeed;
9pub use file_size::{FileSize, NonZeroFileSize};
10
11pub(crate) const SCALE: u128 = 1_000_000;
15pub(crate) const SCALE_I128: i128 = 1_000_000;
16
17pub trait FileSizeFormat: Sized {
21 fn get_si_parts(&self) -> (String, &'static str);
25
26 fn get_iec_parts(&self) -> (String, &'static str);
30
31 #[inline]
35 fn to_si_string(&self) -> String {
36 let (value, unit) = self.get_si_parts();
37 format!("{} {}", value, unit)
38 }
39
40 #[inline]
44 fn to_iec_string(&self) -> String {
45 let (value, unit) = self.get_iec_parts();
46 format!("{} {}", value, unit)
47 }
48
49 #[inline]
50 fn to_formatted(self, standard: SizeStandard) -> FormattedValue<Self> {
51 FormattedValue::new(self, standard)
52 }
53}
54
55pub struct FormattedValue<T: FileSizeFormat> {
56 value: T,
57 standard: SizeStandard,
58}
59
60impl<T: FileSizeFormat> FormattedValue<T> {
61 pub fn new(value: T, standard: SizeStandard) -> Self {
62 Self { value, standard }
63 }
64
65 pub fn get_value(&self) -> &T {
66 &self.value
67 }
68}
69
70impl<T: FileSizeFormat> Display for FormattedValue<T> {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 let display = match self.standard {
73 SizeStandard::SI => self.value.to_si_string(),
74 SizeStandard::IEC => self.value.to_iec_string(),
75 };
76 write!(f, "{}", display)
77 }
78}
79
80#[derive(Debug, Clone, Copy)]
84pub enum SizeStandard {
85 SI,
89 IEC,
93}
94
95pub(crate) fn format_parts_scaled(
103 mut scaled_value: u128,
104 base: u128,
105 units: &'static [&'static str],
106) -> (String, &'static str) {
107 let mut unit_index = 0;
108 let base_scaled = base * SCALE;
109
110 while scaled_value >= base_scaled && unit_index < units.len() - 1 {
111 scaled_value = scaled_value * SCALE / base_scaled;
113 unit_index += 1;
114 }
115
116 let formatted_value = format_scaled_value(scaled_value);
117 (formatted_value, units[unit_index])
118}
119
120pub(crate) fn format_parts_scaled_signed(
124 scaled_value: i128,
125 base: u128,
126 units: &'static [&'static str],
127) -> (String, &'static str) {
128 let is_negative = scaled_value < 0;
129 let abs_value = scaled_value.unsigned_abs();
130
131 let (formatted, unit) = format_parts_scaled(abs_value, base, units);
132
133 if is_negative {
134 (format!("-{}", formatted), unit)
135 } else {
136 (formatted, unit)
137 }
138}
139
140#[inline]
148pub(crate) fn format_scaled_value(scaled_value: u128) -> String {
149 let integer_part = scaled_value / SCALE;
151 let fractional_part = scaled_value % SCALE;
152
153 if integer_part < 10 {
154 let hundredths = (fractional_part + 5000) / 10000; let hundredths = if hundredths >= 100 {
158 return format!("{:.2}", (integer_part + 1) as f64);
160 } else {
161 hundredths
162 };
163 format!("{}.{:02}", integer_part, hundredths)
164 } else {
165 let tenths = (fractional_part + 50000) / 100000; if tenths >= 10 {
168 format!("{}.0", integer_part + 1)
169 } else {
170 format!("{}.{}", integer_part, tenths)
171 }
172 }
173}