byte_unit/bit/adjusted/
mod.rs

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