1mod pretty_bytes_lib;
7pub use crate::pretty_bytes_lib::PrettyBytesOptions;
9use crate::pretty_bytes_lib::{PrettyBytesOptionWithDefault, BIT_UNITS, BYTE_UNITS};
11use std::cmp;
12
13pub fn pretty_bytes(bytes: u64, options: Option<PrettyBytesOptions>) -> String {
53 let options_with_default = set_default_options(options);
54
55 let delimiter = if options_with_default.use_1024_instead_of_1000 {
56 1024_f64
57 } else {
58 1000_f64
59 };
60
61 let units = if options_with_default.use_1024_instead_of_1000 {
62 BIT_UNITS
63 } else {
64 BYTE_UNITS
65 };
66
67 let max_units_index = units.len() - 1;
68 let index = get_unit_index(bytes as f64, delimiter, max_units_index as i32);
69 let pretty_bytes = get_string(
70 bytes as f64,
71 delimiter,
72 index,
73 options_with_default.number_of_decimal,
74 options_with_default.remove_zero_decimal,
75 );
76 let unit = units[index as usize];
77 format!("{} {}", pretty_bytes, unit)
78}
79
80fn get_unit_index(bytes: f64, delimiter: f64, max_units_index: i32) -> i32 {
81 let mut bytes_log = (bytes as f64).ln();
86 if bytes_log < 0.0 {
87 bytes_log = 0.0;
88 }
89 cmp::min(
90 (bytes_log / delimiter.ln()).floor() as i32,
91 max_units_index as i32,
92 )
93}
94
95fn get_string(
96 bytes: f64,
97 delimiter: f64,
98 index: i32,
99 number_of_decimal: usize,
100 remove_zero_decimal: bool,
101) -> String {
102 let result = bytes as f64 / delimiter.powi(index);
103 let mut number_of_decimal_applied = number_of_decimal;
104 if remove_zero_decimal {
105 let result_without_decimal = result as i64 as f64;
106 if result_without_decimal == result {
107 number_of_decimal_applied = 0;
108 }
109 }
110 format!("{:.1$}", result, number_of_decimal_applied)
111}
112
113fn set_default_options(user_options: Option<PrettyBytesOptions>) -> PrettyBytesOptionWithDefault {
114 let output_format = user_options.unwrap_or(PrettyBytesOptions {
116 use_1024_instead_of_1000: None,
117 number_of_decimal: None,
118 remove_zero_decimal: None,
119 });
120
121 PrettyBytesOptionWithDefault {
123 use_1024_instead_of_1000: output_format.use_1024_instead_of_1000.unwrap_or(true),
124 number_of_decimal: output_format.number_of_decimal.unwrap_or(2),
125 remove_zero_decimal: output_format.remove_zero_decimal.unwrap_or(false),
126 }
127}
128#[cfg(test)]
129mod test_set_default_options {
130 use super::*;
131
132 #[test]
133 fn test_set_default_options_no_option() {
134 let result = set_default_options(None);
135 assert_eq!(result.number_of_decimal, 2, "Number of decimal");
136 assert_eq!(result.use_1024_instead_of_1000, true, "Default 1024");
137 assert_eq!(result.remove_zero_decimal, false, "Remove zero decimal");
138 }
139 #[test]
140 fn test_set_default_options_use_user_option() {
141 let result = set_default_options(Some(PrettyBytesOptions {
142 number_of_decimal: Some(5),
143 use_1024_instead_of_1000: Some(false),
144 remove_zero_decimal: Some(false),
145 }));
146 assert_eq!(result.number_of_decimal, 5, "Number of decimal");
147 assert_eq!(result.use_1024_instead_of_1000, false, "Default 1024");
148 assert_eq!(result.remove_zero_decimal, false, "Remove zero decimal");
149 }
150}
151#[cfg(test)]
152mod test_get_unit_index {
153 use super::*;
154 #[test]
155 fn test_get_unit_0() {
156 let result = get_unit_index(0_f64, 1024_f64, 9);
157 assert_eq!(result, 0)
158 }
159 #[test]
160 fn test_get_unit_1024_index_1023() {
161 let result = get_unit_index(1023_f64, 1024_f64, 9);
162 assert_eq!(result, 0)
163 }
164 #[test]
165 fn test_get_unit_1024_index_1024() {
166 let result = get_unit_index(1024_f64, 1024_f64, 9);
167 assert_eq!(result, 1)
168 }
169 #[test]
170 fn test_get_unit_1000_index_999() {
171 let result = get_unit_index(999_f64, 1000_f64, 9);
172 assert_eq!(result, 0)
173 }
174 #[test]
175 fn test_get_unit_1000_index_1000() {
176 let result = get_unit_index(1000_f64, 1000_f64, 9);
177 assert_eq!(result, 1)
178 }
179 #[test]
180 fn test_get_unit_1024_index_1mb() {
181 let result = get_unit_index(1024_f64 * 1024_f64 * 1024_f64, 1024_f64, 9);
182 assert_eq!(result, 3)
183 }
184}
185
186#[cfg(test)]
187mod test_get_string {
188 use super::*;
189
190 #[test]
191 fn test_get_string_bytes() {
192 let result = get_string(1023_f64, 1024_f64, 0, 2, false);
193 assert_eq!(result, "1023.00")
194 }
195 #[test]
196 fn test_get_string_bytes_remove_decimal() {
197 let result = get_string(1023_f64, 1024_f64, 0, 2, true);
198 assert_eq!(result, "1023")
199 }
200 #[test]
201 fn test_get_string_kilobytes() {
202 let result = get_string(1024_f64, 1024_f64, 1, 2, false);
203 assert_eq!(result, "1.00")
204 }
205 #[test]
206 fn test_get_string_kilobytes2() {
207 let result = get_string(1024_f64 * 1024_f64 * 9_f64 + 123_f64, 1024_f64, 1, 3, true);
208 assert_eq!(result, "9216.120")
209 }
210 #[test]
211 fn test_get_string_kilobytes3() {
212 let result = get_string(1024_f64 * 1024_f64 * 9_f64 + 123_f64, 1000_f64, 1, 3, true);
213 assert_eq!(result, "9437.307")
214 }
215 #[test]
216 fn test_get_string_kilobytes_remove_decimal() {
217 let result = get_string(1024_f64, 1024_f64, 1, 2, true);
218 assert_eq!(result, "1")
219 }
220 #[test]
221 fn test_get_string_kilobytes_no_even() {
222 let result = get_string(1100_f64, 1024_f64, 1, 2, false);
223 assert_eq!(result, "1.07")
224 }
225 #[test]
226 fn test_get_string_kilobytes_no_even_remove_decimal() {
227 let result = get_string(1100_f64, 1024_f64, 1, 2, true);
228 assert_eq!(result, "1.07")
229 }
230 #[test]
231 fn test_get_string_kilobytes_no_even_more_decimal() {
232 let result = get_string(1100_f64, 1024_f64, 1, 3, false);
233 assert_eq!(result, "1.074")
234 }
235 #[test]
236 fn test_get_string_kilobytes_no_even_more_decimal_remove_decimal() {
237 let result = get_string(1100_f64, 1024_f64, 1, 3, true);
238 assert_eq!(result, "1.074")
239 }
240}