byte_unit/bit/adjusted/
mod.rs

1mod built_in_traits;
2#[cfg(feature = "rocket")]
3mod rocket_traits;
4#[cfg(feature = "serde")]
5mod serde_traits;
6
7use core::{
8    cmp::Ordering,
9    fmt::{self, Alignment, Display, Formatter, Write},
10};
11
12use super::{Bit, Unit};
13use crate::{common::round_fractional_part_f64, UnitType};
14
15/// Generated from the [`Bit::get_adjusted_unit`](./struct.Bit.html#method.get_adjusted_unit) method or the the [`Bit::get_appropriate_unit`](./struct.Bit.html#method.get_appropriate_unit) method.
16///
17/// For accuracy representation, utilize the `Bit` struct.
18#[derive(Debug, Clone, Copy)]
19pub struct AdjustedBit {
20    pub(crate) value: f64,
21    pub(crate) unit:  Unit,
22}
23
24impl PartialEq for AdjustedBit {
25    #[inline]
26    fn eq(&self, other: &AdjustedBit) -> bool {
27        let s = self.get_bit();
28        let o = other.get_bit();
29
30        s.eq(&o)
31    }
32}
33
34impl Eq for AdjustedBit {}
35
36impl PartialOrd for AdjustedBit {
37    #[inline]
38    fn partial_cmp(&self, other: &AdjustedBit) -> Option<Ordering> {
39        Some(self.cmp(other))
40    }
41}
42
43impl Ord for AdjustedBit {
44    #[inline]
45    fn cmp(&self, other: &AdjustedBit) -> Ordering {
46        let s = self.get_bit();
47        let o = other.get_bit();
48
49        s.cmp(&o)
50    }
51}
52
53impl Display for AdjustedBit {
54    /// Formats the value using the given formatter.
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use byte_unit::{Bit, Unit};
60    ///
61    /// let bit = Bit::from_u64_with_unit(1555, Unit::Kbit).unwrap();
62    ///
63    /// let adjusted_bit = bit.get_adjusted_unit(Unit::Mbit);
64    ///
65    /// assert_eq!("1.555 Mb", adjusted_bit.to_string());
66    /// ```
67    ///
68    /// ```
69    /// use byte_unit::{Bit, UnitType};
70    ///
71    /// let bit = Bit::from_u64(10000);
72    ///
73    /// let adjusted_bit_based_2 = bit.get_appropriate_unit(UnitType::Binary);
74    /// let adjusted_bit_based_10 = bit.get_appropriate_unit(UnitType::Decimal);
75    ///
76    /// assert_eq!("9.765625 Kib", format!("{adjusted_bit_based_2}"));
77    /// assert_eq!("10 Kb", format!("{adjusted_bit_based_10}"));
78    ///
79    /// // with precision
80    /// assert_eq!("9.77 Kib", format!("{adjusted_bit_based_2:.2}"));
81    /// assert_eq!("10.00 Kb", format!("{adjusted_bit_based_10:.2}"));
82    ///
83    /// // without any unnecessary fractional part
84    /// assert_eq!("9.77 Kib", format!("{adjusted_bit_based_2:#.2}"));
85    /// assert_eq!("10 Kb", format!("{adjusted_bit_based_10:#.2}"));
86    ///
87    /// // with a width, left alignment
88    /// assert_eq!("9.77   Kib", format!("{adjusted_bit_based_2:10.2}"));
89    /// assert_eq!("10.00   Kb", format!("{adjusted_bit_based_10:10.2}"));
90    ///
91    /// // with a width, right alignment
92    /// assert_eq!("  9.77 Kib", format!("{adjusted_bit_based_2:>10.2}"));
93    /// assert_eq!("  10.00 Kb", format!("{adjusted_bit_based_10:>10.2}"));
94    ///
95    /// // with a width, right alignment, more spaces between the value and the unit
96    /// assert_eq!("  9.77 Kib", format!("{adjusted_bit_based_2:>+10.2}"));
97    /// assert_eq!(" 10.00  Kb", format!("{adjusted_bit_based_10:>+10.2}"));
98    ///
99    /// // no spaces between the value and the unit
100    /// assert_eq!("9.765625Kib", format!("{adjusted_bit_based_2:-}"));
101    /// assert_eq!("10Kb", format!("{adjusted_bit_based_10:-}"));
102    /// ```
103    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
104        let Self {
105            value,
106            unit,
107        } = self;
108        let handle_basic_precision = |precision: usize, f: &mut Formatter<'_>| -> fmt::Result {
109            if f.alternate() {
110                let value = round_fractional_part_f64(*value, precision);
111
112                f.write_fmt(format_args!("{value}"))
113            } else if matches!(unit, Unit::Bit | Unit::B) {
114                f.write_fmt(format_args!("{value}"))
115            } else {
116                f.write_fmt(format_args!("{value:.precision$}"))
117            }
118        };
119
120        let space_length = if f.sign_plus() {
121            4 - unit.as_str().len()
122        } else if f.sign_minus() {
123            0
124        } else {
125            1
126        };
127
128        if let Some(mut width) = f.width() {
129            let l = unit.as_str().len() + space_length;
130
131            if let Some(precision) = f.precision() {
132                if width > l + 1 {
133                    width -= l;
134
135                    let alignment = f.align().unwrap_or(Alignment::Left);
136
137                    if f.alternate() {
138                        let value = round_fractional_part_f64(*value, precision);
139
140                        match alignment {
141                            Alignment::Left | Alignment::Center => {
142                                f.write_fmt(format_args!("{value:<width$}"))?
143                            },
144                            Alignment::Right => f.write_fmt(format_args!("{value:>width$}"))?,
145                        }
146                    } else {
147                        match alignment {
148                            Alignment::Left | Alignment::Center => {
149                                f.write_fmt(format_args!("{value:<width$.precision$}"))?
150                            },
151                            Alignment::Right => {
152                                f.write_fmt(format_args!("{value:>width$.precision$}"))?
153                            },
154                        }
155                    }
156                } else {
157                    handle_basic_precision(precision, f)?;
158                }
159            } else if width > l + 1 {
160                width -= l;
161
162                let alignment = f.align().unwrap_or(Alignment::Left);
163
164                match alignment {
165                    Alignment::Left | Alignment::Center => {
166                        f.write_fmt(format_args!("{value:<width$}"))?
167                    },
168                    Alignment::Right => f.write_fmt(format_args!("{value:>width$}"))?,
169                }
170            } else {
171                f.write_fmt(format_args!("{value}"))?;
172            }
173        } else if let Some(precision) = f.precision() {
174            handle_basic_precision(precision, f)?;
175        } else {
176            f.write_fmt(format_args!("{value}"))?;
177        }
178
179        for _ in 0..space_length {
180            f.write_char(' ')?;
181        }
182
183        f.write_fmt(format_args!("{unit}"))
184    }
185}
186
187/// Methods for getting values.
188impl AdjustedBit {
189    /// Get the value.
190    #[inline]
191    pub const fn get_value(&self) -> f64 {
192        self.value
193    }
194
195    /// Get the unit.
196    #[inline]
197    pub const fn get_unit(&self) -> Unit {
198        self.unit
199    }
200
201    /// Create a new `Bit` instance from this `AdjustedBit` instance.
202    ///
203    /// # Examples
204    ///
205    /// ```
206    /// use byte_unit::{Bit, Unit};
207    ///
208    /// let bit = Bit::from_u64_with_unit(1555, Unit::Kbit).unwrap();
209    ///
210    /// let adjusted_bit = bit.get_adjusted_unit(Unit::Mbit);
211    ///
212    /// let bit_back = adjusted_bit.get_bit();
213    ///
214    /// assert_eq!(bit, bit_back);
215    /// ```
216    ///
217    /// # Points to Note
218    ///
219    /// * The result may not be logically equal to the original `Bit` instance due to the accuracy of floating-point numbers.
220    #[inline]
221    pub fn get_bit(&self) -> Bit {
222        Bit::from_f64_with_unit(self.value, self.unit).unwrap()
223    }
224}
225
226/// Associated functions for generating `AdjustedBit`.
227impl Bit {
228    /// Adjust the unit and value for this `Bit` instance.
229    ///
230    /// # Examples
231    ///
232    /// ```
233    /// use byte_unit::{AdjustedBit, Bit, Unit};
234    ///
235    /// let bit = Bit::parse_str("123Kib").unwrap();
236    ///
237    /// let adjusted_bit = bit.get_adjusted_unit(Unit::Kbit);
238    ///
239    /// assert_eq!("125.952 Kb", adjusted_bit.to_string());
240    /// ```
241    ///
242    /// ```
243    /// use byte_unit::{AdjustedBit, Bit, Unit};
244    ///
245    /// let bit = Bit::parse_str("50.84 Mb").unwrap();
246    ///
247    /// let adjusted_bit = bit.get_adjusted_unit(Unit::Mibit);
248    ///
249    /// assert_eq!("48.48480224609375 Mib", adjusted_bit.to_string());
250    /// ```
251    #[inline]
252    pub fn get_adjusted_unit(self, unit: Unit) -> AdjustedBit {
253        let bit_v = self.as_u128();
254
255        let value = match unit {
256            Unit::Bit => (bit_v << 3) as f64,
257            Unit::B => bit_v as f64,
258            _ => bit_v as f64 / unit.as_bits_u128() as f64,
259        };
260
261        AdjustedBit {
262            value,
263            unit,
264        }
265    }
266
267    /// Find the appropriate unit and value for this `Bit` instance.
268    ///
269    /// # Examples
270    ///
271    /// ```
272    /// use byte_unit::{Bit, UnitType};
273    ///
274    /// let bit = Bit::parse_str("123Kib").unwrap();
275    ///
276    /// let adjusted_bit = bit.get_appropriate_unit(UnitType::Decimal);
277    ///
278    /// assert_eq!("125.952 Kb", adjusted_bit.to_string());
279    /// ```
280    ///
281    /// ```
282    /// use byte_unit::{Bit, UnitType};
283    ///
284    /// let bit = Bit::parse_str("50.84 Mb").unwrap();
285    ///
286    /// let adjusted_bit = bit.get_appropriate_unit(UnitType::Binary);
287    ///
288    /// assert_eq!("48.48480224609375 Mib", adjusted_bit.to_string());
289    /// ```
290    pub fn get_appropriate_unit(&self, unit_type: UnitType) -> AdjustedBit {
291        let a = Unit::get_multiples_bits();
292
293        let (skip, step) = match unit_type {
294            UnitType::Binary => (0, 2),
295            UnitType::Decimal => (1, 2),
296            UnitType::Both => (0, 1),
297        };
298
299        let bits_v = self.as_u128();
300
301        for unit in a.iter().rev().skip(skip).step_by(step) {
302            if bits_v >= unit.as_bits_u128() {
303                return self.get_adjusted_unit(*unit);
304            }
305        }
306
307        self.get_adjusted_unit(Unit::B)
308    }
309}