1 | use libm::{fabs, modf};
|
2 |
|
3 | use crate::{scales, utils::f64_eq, BaseUnit, FormatSizeOptions, Kilo, ToF64, Unsigned};
|
4 |
|
5 | pub struct ISizeFormatter<T: ToF64, O: AsRef<FormatSizeOptions>> {
|
6 | value: T,
|
7 | options: O,
|
8 | }
|
9 |
|
10 | impl<V: ToF64, O: AsRef<FormatSizeOptions>> ISizeFormatter<V, O> {
|
11 | pub fn new(value: V, options: O) -> Self {
|
12 | ISizeFormatter { value, options }
|
13 | }
|
14 | }
|
15 |
|
16 | impl<T: ToF64, O: AsRef<FormatSizeOptions>> core::fmt::Display for ISizeFormatter<T, O> {
|
17 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
18 | let opts = self.options.as_ref();
|
19 | let divider = opts.kilo.value();
|
20 |
|
21 | let mut size: f64 = self.value.to_f64();
|
22 | let mut scale_idx = 0;
|
23 |
|
24 | if let Some(val) = opts.fixed_at {
|
25 | while scale_idx != val as usize {
|
26 | size /= divider;
|
27 | scale_idx += 1;
|
28 | }
|
29 | } else {
|
30 | while fabs(size) >= divider {
|
31 | size /= divider;
|
32 | scale_idx += 1;
|
33 | }
|
34 | }
|
35 |
|
36 | let mut scale = match (opts.units, opts.long_units, opts.base_unit) {
|
37 | (Kilo::Decimal, false, BaseUnit::Byte) => scales::SCALE_DECIMAL[scale_idx],
|
38 | (Kilo::Decimal, true, BaseUnit::Byte) => scales::SCALE_DECIMAL_LONG[scale_idx],
|
39 | (Kilo::Binary, false, BaseUnit::Byte) => scales::SCALE_BINARY[scale_idx],
|
40 | (Kilo::Binary, true, BaseUnit::Byte) => scales::SCALE_BINARY_LONG[scale_idx],
|
41 | (Kilo::Decimal, false, BaseUnit::Bit) => scales::SCALE_DECIMAL_BIT[scale_idx],
|
42 | (Kilo::Decimal, true, BaseUnit::Bit) => scales::SCALE_DECIMAL_BIT_LONG[scale_idx],
|
43 | (Kilo::Binary, false, BaseUnit::Bit) => scales::SCALE_BINARY_BIT[scale_idx],
|
44 | (Kilo::Binary, true, BaseUnit::Bit) => scales::SCALE_BINARY_BIT_LONG[scale_idx],
|
45 | };
|
46 |
|
47 | // Remove "s" from the scale if the size is 1.x
|
48 | let (fpart, ipart) = modf(size);
|
49 | if f64_eq(ipart, 1.0)
|
50 | && (opts.long_units || (opts.base_unit == BaseUnit::Bit && scale_idx == 0))
|
51 | {
|
52 | scale = &scale[0..scale.len() - 1];
|
53 | }
|
54 |
|
55 | let places = if f64_eq(fpart, 0.0) {
|
56 | opts.decimal_zeroes
|
57 | } else {
|
58 | opts.decimal_places
|
59 | };
|
60 |
|
61 | let space = if opts.space_after_value { " " } else { "" };
|
62 |
|
63 | write!(f, " {:.*}{}{}{}" , places, size, space, scale, opts.suffix)
|
64 | }
|
65 | }
|
66 |
|
67 | impl<'a, U: ToF64 + Unsigned + Copy, O: AsRef<FormatSizeOptions>> From<&'a SizeFormatter<U, O>>
|
68 | for ISizeFormatter<U, &'a O>
|
69 | {
|
70 | fn from(source: &'a SizeFormatter<U, O>) -> Self {
|
71 | ISizeFormatter {
|
72 | value: source.value,
|
73 | options: &source.options,
|
74 | }
|
75 | }
|
76 | }
|
77 |
|
78 | pub struct SizeFormatter<T: ToF64 + Unsigned, O: AsRef<FormatSizeOptions>> {
|
79 | value: T,
|
80 | options: O,
|
81 | }
|
82 |
|
83 | impl<V: ToF64 + Unsigned, O: AsRef<FormatSizeOptions>> SizeFormatter<V, O> {
|
84 | pub fn new(value: V, options: O) -> Self {
|
85 | SizeFormatter { value, options }
|
86 | }
|
87 | }
|
88 |
|
89 | impl<T: ToF64 + Unsigned + Copy, O: AsRef<FormatSizeOptions> + Copy> core::fmt::Display
|
90 | for SizeFormatter<T, O>
|
91 | {
|
92 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
93 | write!(f, " {}" , ISizeFormatter::from(self))
|
94 | }
|
95 | }
|
96 | |