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}