bandwidth/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]
2
3//! Bandwidth Speed quantification.
4//!
5//! # Examples:
6//!
7//! There are multiple ways to create a new [`Bandwidth`]:
8//!
9//! ```
10//! # use bandwidth::Bandwidth;
11//! let five_gbps = Bandwidth::from_gbps(5);
12//! assert_eq!(five_gbps, Bandwidth::from_mbps(5_000));
13//! assert_eq!(five_gbps, Bandwidth::from_kbps(5_000_000));
14//! assert_eq!(five_gbps, Bandwidth::from_bps(5_000_000_000));
15//!
16//! let ten_gbps = Bandwidth::from_gbps(10);
17//! let seven_bps = Bandwidth::from_bps(7);
18//! let total = ten_gbps + seven_bps;
19//! assert_eq!(total, Bandwidth::new(10, 7));
20//! ```
21
22use core::fmt::{self, Write};
23use core::iter::Sum;
24use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
25#[cfg(feature = "serde")]
26use serde::{Deserialize, Serialize};
27
28const BPS_PER_GBPS: u32 = 1_000_000_000;
29const BPS_PER_MBPS: u32 = 1_000_000;
30const BPS_PER_KBPS: u32 = 1_000;
31const MBPS_PER_GBPS: u64 = 1_000;
32const KBPS_PER_GBPS: u64 = 1_000_000;
33
34#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
35#[repr(transparent)]
36#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
37struct BitPerSec(u32);
38
39/// A `Bandwidth` type to represent a link's bandwidth(to describe how many bits can be sent
40/// on the link per second), typically used for network.
41///
42/// Each `Bandwidth` is composed of a whole number of gbps(gigabits per second) and a fractional part
43/// represented in bps(bits per second). The fractional part should always in the range `[0, 1_000_000_000)`.
44///
45/// [`Bandwidth`]s implement many common traits, including [`Add`], [`Sub`], and other
46/// [`ops`] traits. It implements [`Default`] by returning a zero-speed `Bandwidth`.
47///
48/// - gbps = gigabits per second
49/// - mbps = megabits per second
50/// - kbps = kilobits per second
51/// - bps = bits per second
52///
53/// # Examples
54///
55/// ```
56/// use bandwidth::Bandwidth;
57///
58/// let five_gbps = Bandwidth::new(5, 0);
59/// let five_gbps_and_five_bps = five_gbps + Bandwidth::new(0, 5);
60///
61/// assert_eq!(five_gbps_and_five_bps.as_gbps(), 5);
62/// assert_eq!(five_gbps_and_five_bps.subgbps_bps(), 5);
63///
64/// let ten_mbps = Bandwidth::from_mbps(10);
65/// ```
66#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
67#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
68pub struct Bandwidth {
69 gbps: u64,
70 bps: BitPerSec, // Always 0 <= bps < BPS_PER_GBPS
71}
72
73impl Bandwidth {
74 /// The maximum bandwidth speed.
75 ///
76 /// # Examples
77 ///
78 /// ```
79 /// use bandwidth::Bandwidth;
80 ///
81 /// assert_eq!(Bandwidth::MAX, Bandwidth::new(u64::MAX, 1_000_000_000 - 1));
82 /// ```
83 pub const MAX: Bandwidth = Bandwidth::new(u64::MAX, BPS_PER_GBPS - 1);
84
85 /// A zero bandwidth speed.
86 ///
87 /// # Examples
88 ///
89 /// ```
90 /// use bandwidth::Bandwidth;
91 ///
92 /// let bw = Bandwidth::ZERO;
93 /// assert!(bw.is_zero());
94 /// assert_eq!(bw.as_bps(), 0);
95 /// ```
96 pub const ZERO: Bandwidth = Bandwidth::new(0, 0);
97
98 #[inline]
99 pub const fn new(gbps: u64, bps: u32) -> Bandwidth {
100 let gbps = match gbps.checked_add((bps / BPS_PER_GBPS) as u64) {
101 Some(gbps) => gbps,
102 None => panic!("overflow in Bandwidth::new"),
103 };
104 let bps = bps % BPS_PER_GBPS;
105 Bandwidth {
106 gbps,
107 bps: BitPerSec(bps),
108 }
109 }
110
111 /// Creates a new `Bandwidth` from the specified number of `gigabits per second`.
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use bandwidth::Bandwidth;
117 ///
118 /// let Bandwidth = Bandwidth::from_gbps(5);
119 ///
120 /// assert_eq!(5, Bandwidth.as_gbps());
121 /// assert_eq!(0, Bandwidth.subgbps_bps());
122 /// ```
123
124 #[inline]
125
126 pub const fn from_gbps(gbps: u64) -> Bandwidth {
127 Bandwidth::new(gbps, 0)
128 }
129
130 /// Creates a new `Bandwidth` from the specified number of `megabits per second`.
131 ///
132 /// # Examples
133 ///
134 /// ```
135 /// use bandwidth::Bandwidth;
136 ///
137 /// let Bandwidth = Bandwidth::from_mbps(2569);
138 ///
139 /// assert_eq!(2, Bandwidth.as_gbps());
140 /// assert_eq!(569_000_000, Bandwidth.subgbps_bps());
141 /// ```
142
143 #[inline]
144
145 pub const fn from_mbps(mbps: u64) -> Bandwidth {
146 Bandwidth::new(
147 mbps / MBPS_PER_GBPS,
148 ((mbps % MBPS_PER_GBPS) as u32) * BPS_PER_MBPS,
149 )
150 }
151
152 /// Creates a new `Bandwidth` from the specified number of `kilobits per second`.
153 ///
154 /// # Examples
155 ///
156 /// ```
157 /// use bandwidth::Bandwidth;
158 ///
159 /// let Bandwidth = Bandwidth::from_kbps(1_000_002);
160 ///
161 /// assert_eq!(1, Bandwidth.as_gbps());
162 /// assert_eq!(2000, Bandwidth.subgbps_bps());
163 /// ```
164
165 #[inline]
166
167 pub const fn from_kbps(kbps: u64) -> Bandwidth {
168 Bandwidth::new(
169 kbps / KBPS_PER_GBPS,
170 ((kbps % KBPS_PER_GBPS) as u32) * BPS_PER_KBPS,
171 )
172 }
173
174 /// Creates a new `Bandwidth` from the specified number of `bits per second`.
175 ///
176 /// # Examples
177 ///
178 /// ```
179 /// use bandwidth::Bandwidth;
180 ///
181 /// let Bandwidth = Bandwidth::from_bps(1_000_000_123);
182 ///
183 /// assert_eq!(1, Bandwidth.as_gbps());
184 /// assert_eq!(123, Bandwidth.subgbps_bps());
185 /// ```
186
187 #[inline]
188
189 pub const fn from_bps(bps: u64) -> Bandwidth {
190 Bandwidth::new(
191 bps / (BPS_PER_GBPS as u64),
192 (bps % (BPS_PER_GBPS as u64)) as u32,
193 )
194 }
195
196 /// Returns true if this `Bandwidth` has zero speed.
197 ///
198 /// # Examples
199 ///
200 /// ```
201 /// use bandwidth::Bandwidth;
202 ///
203 /// assert!(Bandwidth::ZERO.is_zero());
204 /// assert!(Bandwidth::new(0, 0).is_zero());
205 /// assert!(Bandwidth::from_bps(0).is_zero());
206 /// assert!(Bandwidth::from_gbps(0).is_zero());
207 ///
208 /// assert!(!Bandwidth::new(1, 1).is_zero());
209 /// assert!(!Bandwidth::from_bps(1).is_zero());
210 /// assert!(!Bandwidth::from_gbps(1).is_zero());
211 /// ```
212
213 #[inline]
214 pub const fn is_zero(&self) -> bool {
215 self.gbps == 0 && self.bps.0 == 0
216 }
217
218 /// Returns the number of _whole_ gbps contained by this `Bandwidth`.
219 ///
220 /// The returned value does not include the fractional(bps) part of the
221 /// Bandwidth, which can be obtained using [`subgbps_bps`].
222 ///
223 /// # Examples
224 ///
225 /// ```
226 /// use bandwidth::Bandwidth;
227 ///
228 /// let Bandwidth = Bandwidth::new(5, 730023852);
229 /// assert_eq!(Bandwidth.as_gbps(), 5);
230 /// ```
231 ///
232 /// To determine the total number of gbps represented by the `Bandwidth`
233 /// including the fractional part, use [`as_gbps_f64`] or [`as_gbps_f32`]
234 ///
235 /// [`as_gbps_f64`]: Bandwidth::as_gbps_f64
236 /// [`as_gbps_f32`]: Bandwidth::as_gbps_f32
237 /// [`subgbps_bps`]: Bandwidth::subgbps_bps
238
239 #[inline]
240 pub const fn as_gbps(&self) -> u64 {
241 self.gbps
242 }
243
244 /// Returns the fractional part of this `Bandwidth`, in whole mbps.
245 ///
246 /// This method does **not** return the speed of the Bandwidth when
247 /// represented by mbps. The returned number always represents a
248 /// fractional portion of a gbps (i.e., it is less than one thousand).
249 ///
250 /// # Examples
251 ///
252 /// ```
253 /// use bandwidth::Bandwidth;
254 ///
255 /// let Bandwidth = Bandwidth::from_mbps(5432);
256 /// assert_eq!(Bandwidth.as_gbps(), 5);
257 /// assert_eq!(Bandwidth.subgbps_mbps(), 432);
258 /// ```
259
260 #[inline]
261 pub const fn subgbps_mbps(&self) -> u32 {
262 self.bps.0 / BPS_PER_MBPS
263 }
264
265 /// Returns the fractional part of this `Bandwidth`, in whole kbps.
266 ///
267 /// This method does **not** return the speed of the Bandwidth when
268 /// represented by kbps. The returned number always represents a
269 /// fractional portion of a gbps (i.e., it is less than one million).
270 ///
271 /// # Examples
272 ///
273 /// ```
274 /// use bandwidth::Bandwidth;
275 ///
276 /// let Bandwidth = Bandwidth::from_kbps(1_234_567);
277 /// assert_eq!(Bandwidth.as_gbps(), 1);
278 /// assert_eq!(Bandwidth.subgbps_kbps(), 234_567);
279 /// ```
280
281 #[inline]
282 pub const fn subgbps_kbps(&self) -> u32 {
283 self.bps.0 / BPS_PER_KBPS
284 }
285
286 /// Returns the fractional part of this `Bandwidth`, in bps.
287 ///
288 /// This method does **not** return the speed of the Bandwidth when
289 /// represented by bps. The returned number always represents a
290 /// fractional portion of a gbps (i.e., it is less than one billion).
291 ///
292 /// # Examples
293 ///
294 /// ```
295 /// use bandwidth::Bandwidth;
296 ///
297 /// let Bandwidth = Bandwidth::from_mbps(5010);
298 /// assert_eq!(Bandwidth.as_gbps(), 5);
299 /// assert_eq!(Bandwidth.subgbps_bps(), 10_000_000);
300 /// ```
301
302 #[inline]
303 pub const fn subgbps_bps(&self) -> u32 {
304 self.bps.0
305 }
306
307 /// Returns the total number of whole mbps contained by this `Bandwidth`.
308 ///
309 /// # Examples
310 ///
311 /// ```
312 /// use bandwidth::Bandwidth;
313 ///
314 /// let Bandwidth = Bandwidth::new(5, 730023852);
315 /// assert_eq!(Bandwidth.as_mbps(), 5730);
316 /// ```
317
318 #[inline]
319 pub const fn as_mbps(&self) -> u128 {
320 self.gbps as u128 * MBPS_PER_GBPS as u128 + (self.bps.0 / BPS_PER_MBPS) as u128
321 }
322
323 /// Returns the total number of whole kbps contained by this `Bandwidth`.
324 ///
325 /// # Examples
326 ///
327 /// ```
328 /// use bandwidth::Bandwidth;
329 ///
330 /// let Bandwidth = Bandwidth::new(5, 730023852);
331 /// assert_eq!(Bandwidth.as_kbps(), 5730023);
332 /// ```
333
334 #[inline]
335 pub const fn as_kbps(&self) -> u128 {
336 self.gbps as u128 * KBPS_PER_GBPS as u128 + (self.bps.0 / BPS_PER_KBPS) as u128
337 }
338
339 /// Returns the total number of bps contained by this `Bandwidth`.
340 ///
341 /// # Examples
342 ///
343 /// ```
344 /// use bandwidth::Bandwidth;
345 ///
346 /// let Bandwidth = Bandwidth::new(5, 730023852);
347 /// assert_eq!(Bandwidth.as_bps(), 5730023852);
348 /// ```
349
350 #[inline]
351 pub const fn as_bps(&self) -> u128 {
352 self.gbps as u128 * BPS_PER_GBPS as u128 + self.bps.0 as u128
353 }
354
355 /// Checked `Bandwidth` addition. Computes `self + other`, returning [`None`]
356 /// if overflow occurred.
357 ///
358 /// # Examples
359 ///
360 /// Basic usage:
361 ///
362 /// ```
363 /// use bandwidth::Bandwidth;
364 ///
365 /// assert_eq!(Bandwidth::new(0, 0).checked_add(Bandwidth::new(0, 1)), Some(Bandwidth::new(0, 1)));
366 /// assert_eq!(Bandwidth::new(1, 0).checked_add(Bandwidth::new(u64::MAX, 0)), None);
367 /// ```
368 #[inline]
369 pub const fn checked_add(self, rhs: Bandwidth) -> Option<Bandwidth> {
370 if let Some(mut gbps) = self.gbps.checked_add(rhs.gbps) {
371 let mut bps = self.bps.0 + rhs.bps.0;
372 if bps >= BPS_PER_GBPS {
373 bps -= BPS_PER_GBPS;
374 if let Some(new_gbps) = gbps.checked_add(1) {
375 gbps = new_gbps;
376 } else {
377 return None;
378 }
379 }
380 debug_assert!(bps < BPS_PER_GBPS);
381 Some(Bandwidth::new(gbps, bps))
382 } else {
383 None
384 }
385 }
386
387 /// Saturating `Bandwidth` addition. Computes `self + other`, returning [`Bandwidth::MAX`]
388 /// if overflow occurred.
389 ///
390 /// # Examples
391 ///
392 /// ```
393 /// use bandwidth::Bandwidth;
394 ///
395 /// assert_eq!(Bandwidth::new(0, 0).saturating_add(Bandwidth::new(0, 1)), Bandwidth::new(0, 1));
396 /// assert_eq!(Bandwidth::new(1, 0).saturating_add(Bandwidth::new(u64::MAX, 0)), Bandwidth::MAX);
397 /// ```
398 #[inline]
399 pub const fn saturating_add(self, rhs: Bandwidth) -> Bandwidth {
400 match self.checked_add(rhs) {
401 Some(res) => res,
402 None => Bandwidth::MAX,
403 }
404 }
405
406 /// Checked `Bandwidth` subtraction. Computes `self - other`, returning [`None`]
407 /// if the result would be negative or if overflow occurred.
408 ///
409 /// # Examples
410 ///
411 /// Basic usage:
412 ///
413 /// ```
414 /// use bandwidth::Bandwidth;
415 ///
416 /// assert_eq!(Bandwidth::new(0, 1).checked_sub(Bandwidth::new(0, 0)), Some(Bandwidth::new(0, 1)));
417 /// assert_eq!(Bandwidth::new(0, 0).checked_sub(Bandwidth::new(0, 1)), None);
418 /// ```
419 #[inline]
420 pub const fn checked_sub(self, rhs: Bandwidth) -> Option<Bandwidth> {
421 if let Some(mut gbps) = self.gbps.checked_sub(rhs.gbps) {
422 let bps = if self.bps.0 >= rhs.bps.0 {
423 self.bps.0 - rhs.bps.0
424 } else if let Some(sub_gbps) = gbps.checked_sub(1) {
425 gbps = sub_gbps;
426 self.bps.0 + BPS_PER_GBPS - rhs.bps.0
427 } else {
428 return None;
429 };
430 debug_assert!(bps < BPS_PER_GBPS);
431 Some(Bandwidth::new(gbps, bps))
432 } else {
433 None
434 }
435 }
436
437 /// Saturating `Bandwidth` subtraction. Computes `self - other`, returning [`Bandwidth::ZERO`]
438 /// if the result would be negative or if overflow occurred.
439 ///
440 /// # Examples
441 ///
442 /// ```
443 /// use bandwidth::Bandwidth;
444 ///
445 /// assert_eq!(Bandwidth::new(0, 1).saturating_sub(Bandwidth::new(0, 0)), Bandwidth::new(0, 1));
446 /// assert_eq!(Bandwidth::new(0, 0).saturating_sub(Bandwidth::new(0, 1)), Bandwidth::ZERO);
447 /// ```
448 #[inline]
449 pub const fn saturating_sub(self, rhs: Bandwidth) -> Bandwidth {
450 match self.checked_sub(rhs) {
451 Some(res) => res,
452 None => Bandwidth::ZERO,
453 }
454 }
455
456 /// Checked `Bandwidth` multiplication. Computes `self * other`, returning
457 /// [`None`] if overflow occurred.
458 ///
459 /// # Examples
460 ///
461 /// Basic usage:
462 ///
463 /// ```
464 /// use bandwidth::Bandwidth;
465 ///
466 /// assert_eq!(Bandwidth::new(0, 500_000_001).checked_mul(2), Some(Bandwidth::new(1, 2)));
467 /// assert_eq!(Bandwidth::new(u64::MAX - 1, 0).checked_mul(2), None);
468 /// ```
469 #[inline]
470 pub const fn checked_mul(self, rhs: u32) -> Option<Bandwidth> {
471 // Multiply bps as u64, because it cannot overflow that way.
472 let total_bps = self.bps.0 as u64 * rhs as u64;
473 let extra_gbps = total_bps / (BPS_PER_GBPS as u64);
474 let bps = (total_bps % (BPS_PER_GBPS as u64)) as u32;
475 if let Some(s) = self.gbps.checked_mul(rhs as u64) {
476 if let Some(gbps) = s.checked_add(extra_gbps) {
477 debug_assert!(bps < BPS_PER_GBPS);
478 return Some(Bandwidth::new(gbps, bps));
479 }
480 }
481 None
482 }
483
484 /// Saturating `Bandwidth` multiplication. Computes `self * other`, returning
485 /// [`Bandwidth::MAX`] if overflow occurred.
486 ///
487 /// # Examples
488 ///
489 /// ```
490 /// use bandwidth::Bandwidth;
491 ///
492 /// assert_eq!(Bandwidth::new(0, 500_000_001).saturating_mul(2), Bandwidth::new(1, 2));
493 /// assert_eq!(Bandwidth::new(u64::MAX - 1, 0).saturating_mul(2), Bandwidth::MAX);
494 /// ```
495 #[inline]
496 pub const fn saturating_mul(self, rhs: u32) -> Bandwidth {
497 match self.checked_mul(rhs) {
498 Some(res) => res,
499 None => Bandwidth::MAX,
500 }
501 }
502
503 /// Checked `Bandwidth` division. Computes `self / other`, returning [`None`]
504 /// if `other == 0`.
505 ///
506 /// # Examples
507 ///
508 /// Basic usage:
509 ///
510 /// ```
511 /// use bandwidth::Bandwidth;
512 ///
513 /// assert_eq!(Bandwidth::new(2, 0).checked_div(2), Some(Bandwidth::new(1, 0)));
514 /// assert_eq!(Bandwidth::new(1, 0).checked_div(2), Some(Bandwidth::new(0, 500_000_000)));
515 /// assert_eq!(Bandwidth::new(2, 0).checked_div(0), None);
516 /// ```
517 #[inline]
518 pub const fn checked_div(self, rhs: u32) -> Option<Bandwidth> {
519 if rhs != 0 {
520 let gbps = self.gbps / (rhs as u64);
521 let carry = self.gbps - gbps * (rhs as u64);
522 let extra_bps = carry * (BPS_PER_GBPS as u64) / (rhs as u64);
523 let bps = self.bps.0 / rhs + (extra_bps as u32);
524 debug_assert!(bps < BPS_PER_GBPS);
525 Some(Bandwidth::new(gbps, bps))
526 } else {
527 None
528 }
529 }
530
531 /// Returns the number of gbps contained by this `Bandwidth` as `f64`.
532 ///
533 /// The returned value does include the fractional (bps) part of the Bandwidth.
534 ///
535 /// # Examples
536 /// ```
537 /// use bandwidth::Bandwidth;
538 ///
539 /// let bw = Bandwidth::new(2, 700_000_000);
540 /// assert_eq!(bw.as_gbps_f64(), 2.7);
541 /// ```
542 #[inline]
543 pub fn as_gbps_f64(&self) -> f64 {
544 (self.gbps as f64) + (self.bps.0 as f64) / (BPS_PER_GBPS as f64)
545 }
546
547 /// Returns the number of gbps contained by this `Bandwidth` as `f32`.
548 ///
549 /// The returned value does include the fractional (bps) part of the Bandwidth.
550 ///
551 /// # Examples
552 /// ```
553 /// use bandwidth::Bandwidth;
554 ///
555 /// let bw = Bandwidth::new(2, 700_000_000);
556 /// assert_eq!(bw.as_gbps_f32(), 2.7);
557 /// ```
558 #[inline]
559 pub fn as_gbps_f32(&self) -> f32 {
560 (self.gbps as f32) + (self.bps.0 as f32) / (BPS_PER_GBPS as f32)
561 }
562
563 /// Creates a new `Bandwidth` from the specified number of gbps represented
564 /// as `f64`.
565 ///
566 /// # Panics
567 /// This constructor will panic if `gbps` is negative, overflows `Bandwidth` or not finite.
568 ///
569 /// # Examples
570 /// ```
571 /// use bandwidth::Bandwidth;
572 ///
573 /// let res = Bandwidth::from_gbps_f64(0.0);
574 /// assert_eq!(res, Bandwidth::new(0, 0));
575 /// let res = Bandwidth::from_gbps_f64(1e-20);
576 /// assert_eq!(res, Bandwidth::new(0, 0));
577 /// let res = Bandwidth::from_gbps_f64(4.2e-7);
578 /// assert_eq!(res, Bandwidth::new(0, 420));
579 /// let res = Bandwidth::from_gbps_f64(2.7);
580 /// assert_eq!(res, Bandwidth::new(2, 700_000_000));
581 /// let res = Bandwidth::from_gbps_f64(3e10);
582 /// assert_eq!(res, Bandwidth::new(30_000_000_000, 0));
583 /// // subnormal float
584 /// let res = Bandwidth::from_gbps_f64(f64::from_bits(1));
585 /// assert_eq!(res, Bandwidth::new(0, 0));
586 /// // conversion uses rounding
587 /// let res = Bandwidth::from_gbps_f64(0.999e-9);
588 /// assert_eq!(res, Bandwidth::new(0, 1));
589 /// ```
590 #[inline]
591 pub fn from_gbps_f64(gbps: f64) -> Bandwidth {
592 match Bandwidth::try_from_gbps_f64(gbps) {
593 Ok(v) => v,
594 Err(e) => panic!("{}", e.description()),
595 }
596 }
597
598 /// Creates a new `Bandwidth` from the specified number of gbps represented
599 /// as `f32`.
600 ///
601 /// # Panics
602 /// This constructor will panic if `gbps` is negative, overflows `Bandwidth` or not finite.
603 ///
604 /// # Examples
605 /// ```
606 /// use bandwidth::Bandwidth;
607 ///
608 /// let res = Bandwidth::from_gbps_f32(0.0);
609 /// assert_eq!(res, Bandwidth::new(0, 0));
610 /// let res = Bandwidth::from_gbps_f32(1e-20);
611 /// assert_eq!(res, Bandwidth::new(0, 0));
612 /// let res = Bandwidth::from_gbps_f32(4.2e-7);
613 /// assert_eq!(res, Bandwidth::new(0, 420));
614 /// let res = Bandwidth::from_gbps_f32(2.7);
615 /// assert_eq!(res, Bandwidth::new(2, 700_000_048));
616 /// let res = Bandwidth::from_gbps_f32(3e10);
617 /// assert_eq!(res, Bandwidth::new(30_000_001_024, 0));
618 /// // subnormal float
619 /// let res = Bandwidth::from_gbps_f32(f32::from_bits(1));
620 /// assert_eq!(res, Bandwidth::new(0, 0));
621 /// // conversion uses rounding
622 /// let res = Bandwidth::from_gbps_f32(0.999e-9);
623 /// assert_eq!(res, Bandwidth::new(0, 1));
624 /// ```
625 #[inline]
626 pub fn from_gbps_f32(gbps: f32) -> Bandwidth {
627 match Bandwidth::try_from_gbps_f32(gbps) {
628 Ok(v) => v,
629 Err(e) => panic!("{}", e.description()),
630 }
631 }
632
633 /// Multiplies `Bandwidth` by `f64`.
634 ///
635 /// # Panics
636 /// This method will panic if result is negative, overflows `Bandwidth` or not finite.
637 ///
638 /// # Examples
639 /// ```
640 /// use bandwidth::Bandwidth;
641 ///
642 /// let bw = Bandwidth::new(2, 700_000_000);
643 /// assert_eq!(bw.mul_f64(3.14), Bandwidth::new(8, 478_000_000));
644 /// assert_eq!(bw.mul_f64(3.14e5), Bandwidth::new(847_800, 0));
645 /// ```
646 #[inline]
647 pub fn mul_f64(self, rhs: f64) -> Bandwidth {
648 Bandwidth::from_gbps_f64(rhs * self.as_gbps_f64())
649 }
650
651 /// Multiplies `Bandwidth` by `f32`.
652 ///
653 /// # Panics
654 /// This method will panic if result is negative, overflows `Bandwidth` or not finite.
655 ///
656 /// # Examples
657 /// ```
658 /// use bandwidth::Bandwidth;
659 ///
660 /// let bw = Bandwidth::new(2, 700_000_000);
661 /// assert_eq!(bw.mul_f32(3.14), Bandwidth::new(8, 478_000_641));
662 /// assert_eq!(bw.mul_f32(3.14e5), Bandwidth::new(847800, 0));
663 /// ```
664 #[inline]
665 pub fn mul_f32(self, rhs: f32) -> Bandwidth {
666 Bandwidth::from_gbps_f32(rhs * self.as_gbps_f32())
667 }
668
669 /// Divide `Bandwidth` by `f64`.
670 ///
671 /// # Panics
672 /// This method will panic if result is negative, overflows `Bandwidth` or not finite.
673 ///
674 /// # Examples
675 /// ```
676 /// use bandwidth::Bandwidth;
677 ///
678 /// let bw = Bandwidth::new(2, 700_000_000);
679 /// assert_eq!(bw.div_f64(3.14), Bandwidth::new(0, 859_872_611));
680 /// assert_eq!(bw.div_f64(3.14e5), Bandwidth::new(0, 8_599));
681 /// ```
682 #[inline]
683 pub fn div_f64(self, rhs: f64) -> Bandwidth {
684 Bandwidth::from_gbps_f64(self.as_gbps_f64() / rhs)
685 }
686
687 /// Divide `Bandwidth` by `f32`.
688 ///
689 /// # Panics
690 /// This method will panic if result is negative, overflows `Bandwidth` or not finite.
691 ///
692 /// # Examples
693 /// ```
694 /// use bandwidth::Bandwidth;
695 ///
696 /// let bw = Bandwidth::new(2, 700_000_000);
697 /// // note that due to rounding errors result is slightly
698 /// // different from 0.859_872_611
699 /// assert_eq!(bw.div_f32(3.14), Bandwidth::new(0, 859_872_580));
700 /// assert_eq!(bw.div_f32(3.14e5), Bandwidth::new(0, 8_599));
701 /// ```
702 #[inline]
703 pub fn div_f32(self, rhs: f32) -> Bandwidth {
704 Bandwidth::from_gbps_f32(self.as_gbps_f32() / rhs)
705 }
706
707 /// Divide `Bandwidth` by `Bandwidth` and return `f64`.
708 ///
709 /// # Examples
710 /// ```
711 /// use bandwidth::Bandwidth;
712 ///
713 /// let bw1 = Bandwidth::new(2, 700_000_000);
714 /// let bw2 = Bandwidth::new(5, 400_000_000);
715 /// assert_eq!(bw1.div_bandwidth_f64(bw2), 0.5);
716 /// ```
717 #[inline]
718 pub fn div_bandwidth_f64(self, rhs: Bandwidth) -> f64 {
719 self.as_gbps_f64() / rhs.as_gbps_f64()
720 }
721
722 /// Divide `Bandwidth` by `Bandwidth` and return `f32`.
723 ///
724 /// # Examples
725 /// ```
726 /// use bandwidth::Bandwidth;
727 ///
728 /// let bw1 = Bandwidth::new(2, 700_000_000);
729 /// let bw2 = Bandwidth::new(5, 400_000_000);
730 /// assert_eq!(bw1.div_bandwidth_f32(bw2), 0.5);
731 /// ```
732 #[inline]
733 pub fn div_bandwidth_f32(self, rhs: Bandwidth) -> f32 {
734 self.as_gbps_f32() / rhs.as_gbps_f32()
735 }
736}
737
738impl Add for Bandwidth {
739 type Output = Bandwidth;
740
741 fn add(self, rhs: Bandwidth) -> Bandwidth {
742 self.checked_add(rhs)
743 .expect("overflow when adding Bandwidths")
744 }
745}
746
747impl AddAssign for Bandwidth {
748 fn add_assign(&mut self, rhs: Bandwidth) {
749 *self = *self + rhs;
750 }
751}
752
753impl Sub for Bandwidth {
754 type Output = Bandwidth;
755
756 fn sub(self, rhs: Bandwidth) -> Bandwidth {
757 self.checked_sub(rhs)
758 .expect("overflow when subtracting Bandwidths")
759 }
760}
761
762impl SubAssign for Bandwidth {
763 fn sub_assign(&mut self, rhs: Bandwidth) {
764 *self = *self - rhs;
765 }
766}
767
768impl Mul<u32> for Bandwidth {
769 type Output = Bandwidth;
770
771 fn mul(self, rhs: u32) -> Bandwidth {
772 self.checked_mul(rhs)
773 .expect("overflow when multiplying Bandwidth by scalar")
774 }
775}
776
777impl Mul<Bandwidth> for u32 {
778 type Output = Bandwidth;
779
780 fn mul(self, rhs: Bandwidth) -> Bandwidth {
781 rhs * self
782 }
783}
784
785impl MulAssign<u32> for Bandwidth {
786 fn mul_assign(&mut self, rhs: u32) {
787 *self = *self * rhs;
788 }
789}
790
791impl Div<u32> for Bandwidth {
792 type Output = Bandwidth;
793
794 fn div(self, rhs: u32) -> Bandwidth {
795 self.checked_div(rhs)
796 .expect("divide by zero error when dividing Bandwidth by scalar")
797 }
798}
799
800impl DivAssign<u32> for Bandwidth {
801 fn div_assign(&mut self, rhs: u32) {
802 *self = *self / rhs;
803 }
804}
805
806macro_rules! sum_Bandwidths {
807 ($iter:expr) => {{
808 let mut total_gbps: u64 = 0;
809 let mut total_bps: u64 = 0;
810
811 for entry in $iter {
812 total_gbps = total_gbps
813 .checked_add(entry.gbps)
814 .expect("overflow in iter::sum over bandwidths");
815 total_bps = match total_bps.checked_add(entry.bps.0 as u64) {
816 Some(n) => n,
817 None => {
818 total_gbps = total_gbps
819 .checked_add(total_bps / BPS_PER_GBPS as u64)
820 .expect("overflow in iter::sum over bandwidths");
821 (total_bps % BPS_PER_GBPS as u64) + entry.bps.0 as u64
822 }
823 };
824 }
825 total_gbps = total_gbps
826 .checked_add(total_bps / BPS_PER_GBPS as u64)
827 .expect("overflow in iter::sum over bandwidths");
828 total_bps %= BPS_PER_GBPS as u64;
829 Bandwidth::new(total_gbps, total_bps as u32)
830 }};
831}
832
833impl Sum for Bandwidth {
834 fn sum<I: Iterator<Item = Bandwidth>>(iter: I) -> Bandwidth {
835 sum_Bandwidths!(iter)
836 }
837}
838
839impl<'a> Sum<&'a Bandwidth> for Bandwidth {
840 fn sum<I: Iterator<Item = &'a Bandwidth>>(iter: I) -> Bandwidth {
841 sum_Bandwidths!(iter)
842 }
843}
844
845/// An error which can be returned when converting a floating-point value of gbps
846/// into a [`Bandwidth`].
847///
848/// This error is used as the error type for [`Bandwidth::try_from_gbps_f32`] and
849/// [`Bandwidth::try_from_gbps_f64`].
850///
851/// # Example
852///
853/// ```
854/// use bandwidth::Bandwidth;
855///
856/// if let Err(e) = Bandwidth::try_from_gbps_f32(-1.0) {
857/// println!("Failed conversion to Bandwidth: {e}");
858/// }
859/// ```
860#[derive(Debug, Clone, PartialEq, Eq)]
861pub struct TryFromFloatGbpsError {
862 kind: TryFromFloatGbpsErrorKind,
863}
864
865impl TryFromFloatGbpsError {
866 const fn description(&self) -> &'static str {
867 match self.kind {
868 TryFromFloatGbpsErrorKind::Negative => {
869 "can not convert float gbps to Bandwidth: value is negative"
870 }
871 TryFromFloatGbpsErrorKind::OverflowOrNan => {
872 "can not convert float gbps to Bandwidth: value is either too big or NaN"
873 }
874 }
875 }
876}
877
878impl fmt::Display for TryFromFloatGbpsError {
879 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
880 self.description().fmt(f)
881 }
882}
883
884#[derive(Debug, Clone, PartialEq, Eq)]
885enum TryFromFloatGbpsErrorKind {
886 // Value is negative.
887 Negative,
888 // Value is either too big to be represented as `Bandwidth` or `NaN`.
889 OverflowOrNan,
890}
891
892macro_rules! try_from_gbps {
893 (
894 gbps = $gbps: expr,
895 mantissa_bits = $mant_bits: literal,
896 exponent_bits = $exp_bits: literal,
897 offset = $offset: literal,
898 bits_ty = $bits_ty:ty,
899 double_ty = $double_ty:ty,
900 ) => {{
901 const MIN_EXP: i16 = 1 - (1i16 << $exp_bits) / 2;
902 const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1;
903 const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1;
904
905 if $gbps < 0.0 {
906 return Err(TryFromFloatGbpsError {
907 kind: TryFromFloatGbpsErrorKind::Negative,
908 });
909 }
910
911 let bits = $gbps.to_bits();
912 let mant = (bits & MANT_MASK) | (MANT_MASK + 1);
913 let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP;
914
915 let (gbps, bps) = if exp < -31 {
916 // the input represents less than 1ns and can not be rounded to it
917 (0u64, 0u32)
918 } else if exp < 0 {
919 // the input is less than 1 second
920 let t = <$double_ty>::from(mant) << ($offset + exp);
921 let bps_offset = $mant_bits + $offset;
922 let bps_tmp = u128::from(BPS_PER_GBPS) * u128::from(t);
923 let bps = (bps_tmp >> bps_offset) as u32;
924
925 let rem_mask = (1 << bps_offset) - 1;
926 let rem_msb_mask = 1 << (bps_offset - 1);
927 let rem = bps_tmp & rem_mask;
928 let is_tie = rem == rem_msb_mask;
929 let is_even = (bps & 1) == 0;
930 let rem_msb = bps_tmp & rem_msb_mask == 0;
931 let add_bps = !(rem_msb || (is_even && is_tie));
932
933 let bps = bps + add_bps as u32;
934 if ($mant_bits == 23) || (bps != BPS_PER_GBPS) {
935 (0, bps)
936 } else {
937 (1, 0)
938 }
939 } else if exp < $mant_bits {
940 let gbps = u64::from(mant >> ($mant_bits - exp));
941 let t = <$double_ty>::from((mant << exp) & MANT_MASK);
942 let bps_offset = $mant_bits;
943 let bps_tmp = <$double_ty>::from(BPS_PER_GBPS) * t;
944 let bps = (bps_tmp >> bps_offset) as u32;
945
946 let rem_mask = (1 << bps_offset) - 1;
947 let rem_msb_mask = 1 << (bps_offset - 1);
948 let rem = bps_tmp & rem_mask;
949 let is_tie = rem == rem_msb_mask;
950 let is_even = (bps & 1) == 0;
951 let rem_msb = bps_tmp & rem_msb_mask == 0;
952 let add_bps = !(rem_msb || (is_even && is_tie));
953
954 let bps = bps + add_bps as u32;
955 if ($mant_bits == 23) || (bps != BPS_PER_GBPS) {
956 (gbps, bps)
957 } else {
958 (gbps + 1, 0)
959 }
960 } else if exp < 64 {
961 // the input has no fractional part
962 let gbps = u64::from(mant) << (exp - $mant_bits);
963 (gbps, 0)
964 } else {
965 return Err(TryFromFloatGbpsError {
966 kind: TryFromFloatGbpsErrorKind::OverflowOrNan,
967 });
968 };
969
970 Ok(Bandwidth::new(gbps, bps))
971 }};
972}
973
974impl Bandwidth {
975 /// The checked version of [`from_gbps_f32`].
976 ///
977 /// [`from_gbps_f32`]: Bandwidth::from_gbps_f32
978 ///
979 /// This constructor will return an `Err` if `gbps` is negative, overflows `Bandwidth` or not finite.
980 ///
981 /// # Examples
982 /// ```
983 /// use bandwidth::Bandwidth;
984 ///
985 /// let res = Bandwidth::try_from_gbps_f32(0.0);
986 /// assert_eq!(res, Ok(Bandwidth::new(0, 0)));
987 /// let res = Bandwidth::try_from_gbps_f32(1e-20);
988 /// assert_eq!(res, Ok(Bandwidth::new(0, 0)));
989 /// let res = Bandwidth::try_from_gbps_f32(4.2e-7);
990 /// assert_eq!(res, Ok(Bandwidth::new(0, 420)));
991 /// let res = Bandwidth::try_from_gbps_f32(2.7);
992 /// assert_eq!(res, Ok(Bandwidth::new(2, 700_000_048)));
993 /// let res = Bandwidth::try_from_gbps_f32(3e10);
994 /// assert_eq!(res, Ok(Bandwidth::new(30_000_001_024, 0)));
995 /// // subnormal float:
996 /// let res = Bandwidth::try_from_gbps_f32(f32::from_bits(1));
997 /// assert_eq!(res, Ok(Bandwidth::new(0, 0)));
998 ///
999 /// let res = Bandwidth::try_from_gbps_f32(-5.0);
1000 /// assert!(res.is_err());
1001 /// let res = Bandwidth::try_from_gbps_f32(f32::NAN);
1002 /// assert!(res.is_err());
1003 /// let res = Bandwidth::try_from_gbps_f32(2e19);
1004 /// assert!(res.is_err());
1005 ///
1006 /// // the conversion uses rounding with tie resolution to even
1007 /// let res = Bandwidth::try_from_gbps_f32(0.999e-9);
1008 /// assert_eq!(res, Ok(Bandwidth::new(0, 1)));
1009 ///
1010 /// // this float represents exactly 976562.5e-9
1011 /// let val = f32::from_bits(0x3A80_0000);
1012 /// let res = Bandwidth::try_from_gbps_f32(val);
1013 /// assert_eq!(res, Ok(Bandwidth::new(0, 976_562)));
1014 ///
1015 /// // this float represents exactly 2929687.5e-9
1016 /// let val = f32::from_bits(0x3B40_0000);
1017 /// let res = Bandwidth::try_from_gbps_f32(val);
1018 /// assert_eq!(res, Ok(Bandwidth::new(0, 2_929_688)));
1019 ///
1020 /// // this float represents exactly 1.000_976_562_5
1021 /// let val = f32::from_bits(0x3F802000);
1022 /// let res = Bandwidth::try_from_gbps_f32(val);
1023 /// assert_eq!(res, Ok(Bandwidth::new(1, 976_562)));
1024 ///
1025 /// // this float represents exactly 1.002_929_687_5
1026 /// let val = f32::from_bits(0x3F806000);
1027 /// let res = Bandwidth::try_from_gbps_f32(val);
1028 /// assert_eq!(res, Ok(Bandwidth::new(1, 2_929_688)));
1029 /// ```
1030 #[inline]
1031 pub fn try_from_gbps_f32(gbps: f32) -> Result<Bandwidth, TryFromFloatGbpsError> {
1032 try_from_gbps!(
1033 gbps = gbps,
1034 mantissa_bits = 23,
1035 exponent_bits = 8,
1036 offset = 41,
1037 bits_ty = u32,
1038 double_ty = u64,
1039 )
1040 }
1041
1042 /// The checked version of [`from_gbps_f64`].
1043 ///
1044 /// [`from_gbps_f64`]: Bandwidth::from_gbps_f64
1045 ///
1046 /// This constructor will return an `Err` if `secs` is negative, overflows `Bandwidth` or not finite.
1047 ///
1048 /// # Examples
1049 /// ```
1050 /// use bandwidth::Bandwidth;
1051 ///
1052 /// let res = Bandwidth::try_from_gbps_f64(0.0);
1053 /// assert_eq!(res, Ok(Bandwidth::new(0, 0)));
1054 /// let res = Bandwidth::try_from_gbps_f64(1e-20);
1055 /// assert_eq!(res, Ok(Bandwidth::new(0, 0)));
1056 /// let res = Bandwidth::try_from_gbps_f64(4.2e-7);
1057 /// assert_eq!(res, Ok(Bandwidth::new(0, 420)));
1058 /// let res = Bandwidth::try_from_gbps_f64(2.7);
1059 /// assert_eq!(res, Ok(Bandwidth::new(2, 700_000_000)));
1060 /// let res = Bandwidth::try_from_gbps_f64(3e10);
1061 /// assert_eq!(res, Ok(Bandwidth::new(30_000_000_000, 0)));
1062 /// // subnormal float
1063 /// let res = Bandwidth::try_from_gbps_f64(f64::from_bits(1));
1064 /// assert_eq!(res, Ok(Bandwidth::new(0, 0)));
1065 ///
1066 /// let res = Bandwidth::try_from_gbps_f64(-5.0);
1067 /// assert!(res.is_err());
1068 /// let res = Bandwidth::try_from_gbps_f64(f64::NAN);
1069 /// assert!(res.is_err());
1070 /// let res = Bandwidth::try_from_gbps_f64(2e19);
1071 /// assert!(res.is_err());
1072 ///
1073 /// // the conversion uses rounding with tie resolution to even
1074 /// let res = Bandwidth::try_from_gbps_f64(0.999e-9);
1075 /// assert_eq!(res, Ok(Bandwidth::new(0, 1)));
1076 /// let res = Bandwidth::try_from_gbps_f64(0.999_999_999_499);
1077 /// assert_eq!(res, Ok(Bandwidth::new(0, 999_999_999)));
1078 /// let res = Bandwidth::try_from_gbps_f64(0.999_999_999_501);
1079 /// assert_eq!(res, Ok(Bandwidth::new(1, 0)));
1080 /// let res = Bandwidth::try_from_gbps_f64(42.999_999_999_499);
1081 /// assert_eq!(res, Ok(Bandwidth::new(42, 999_999_999)));
1082 /// let res = Bandwidth::try_from_gbps_f64(42.999_999_999_501);
1083 /// assert_eq!(res, Ok(Bandwidth::new(43, 0)));
1084 ///
1085 /// // this float represents exactly 976562.5e-9
1086 /// let val = f64::from_bits(0x3F50_0000_0000_0000);
1087 /// let res = Bandwidth::try_from_gbps_f64(val);
1088 /// assert_eq!(res, Ok(Bandwidth::new(0, 976_562)));
1089 ///
1090 /// // this float represents exactly 2929687.5e-9
1091 /// let val = f64::from_bits(0x3F68_0000_0000_0000);
1092 /// let res = Bandwidth::try_from_gbps_f64(val);
1093 /// assert_eq!(res, Ok(Bandwidth::new(0, 2_929_688)));
1094 ///
1095 /// // this float represents exactly 1.000_976_562_5
1096 /// let val = f64::from_bits(0x3FF0_0400_0000_0000);
1097 /// let res = Bandwidth::try_from_gbps_f64(val);
1098 /// assert_eq!(res, Ok(Bandwidth::new(1, 976_562)));
1099 ///
1100 /// // this float represents exactly 1.002_929_687_5
1101 /// let val = f64::from_bits(0x3_FF00_C000_0000_000);
1102 /// let res = Bandwidth::try_from_gbps_f64(val);
1103 /// assert_eq!(res, Ok(Bandwidth::new(1, 2_929_688)));
1104 /// ```
1105 #[inline]
1106 pub fn try_from_gbps_f64(gbps: f64) -> Result<Bandwidth, TryFromFloatGbpsError> {
1107 try_from_gbps!(
1108 gbps = gbps,
1109 mantissa_bits = 52,
1110 exponent_bits = 11,
1111 offset = 44,
1112 bits_ty = u64,
1113 double_ty = u128,
1114 )
1115 }
1116}
1117
1118#[rustversion::before(1.67)]
1119impl fmt::Debug for Bandwidth {
1120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1121 /// Formats a floating point number in decimal notation.
1122 ///
1123 /// The number is given as the `integer_part` and a fractional part.
1124 /// The value of the fractional part is `fractional_part / divisor`. So
1125 /// `integer_part` = 3, `fractional_part` = 12 and `divisor` = 100
1126 /// represents the number `3.012`. Trailing zeros are omitted.
1127 ///
1128 /// `divisor` must not be above 100_000_000. It also should be a power
1129 /// of 10, everything else doesn't make sense. `fractional_part` has
1130 /// to be less than `10 * divisor`!
1131 ///
1132 /// This function is copied from older rust stable version since
1133 /// `checked_ilog10` is just stabled in 1.67
1134 fn fmt_decimal(
1135 f: &mut fmt::Formatter<'_>,
1136 mut integer_part: u64,
1137 mut fractional_part: u32,
1138 mut divisor: u32,
1139 ) -> fmt::Result {
1140 // Encode the fractional part into a temporary buffer. The buffer
1141 // only need to hold 9 elements, because `fractional_part` has to
1142 // be smaller than 10^9. The buffer is prefilled with '0' digits
1143 // to simplify the code below.
1144 let mut buf = [b'0'; 9];
1145
1146 // The next digit is written at this position
1147 let mut pos = 0;
1148
1149 // We keep writing digits into the buffer while there are non-zero
1150 // digits left and we haven't written enough digits yet.
1151 while fractional_part > 0 && pos < f.precision().unwrap_or(9) {
1152 // Write new digit into the buffer
1153 buf[pos] = b'0' + (fractional_part / divisor) as u8;
1154
1155 fractional_part %= divisor;
1156 divisor /= 10;
1157 pos += 1;
1158 }
1159
1160 // If a precision < 9 was specified, there may be some non-zero
1161 // digits left that weren't written into the buffer. In that case we
1162 // need to perform rounding to match the semantics of printing
1163 // normal floating point numbers. However, we only need to do work
1164 // when rounding up. This happens if the first digit of the
1165 // remaining ones is >= 5.
1166 if fractional_part > 0 && fractional_part >= divisor * 5 {
1167 // Round up the number contained in the buffer. We go through
1168 // the buffer backwards and keep track of the carry.
1169 let mut rev_pos = pos;
1170 let mut carry = true;
1171 while carry && rev_pos > 0 {
1172 rev_pos -= 1;
1173
1174 // If the digit in the buffer is not '9', we just need to
1175 // increment it and can stop then (since we don't have a
1176 // carry anymore). Otherwise, we set it to '0' (overflow)
1177 // and continue.
1178 if buf[rev_pos] < b'9' {
1179 buf[rev_pos] += 1;
1180 carry = false;
1181 } else {
1182 buf[rev_pos] = b'0';
1183 }
1184 }
1185
1186 // If we still have the carry bit set, that means that we set
1187 // the whole buffer to '0's and need to increment the integer
1188 // part.
1189 if carry {
1190 integer_part += 1;
1191 }
1192 }
1193
1194 // Determine the end of the buffer: if precision is set, we just
1195 // use as many digits from the buffer (capped to 9). If it isn't
1196 // set, we only use all digits up to the last non-zero one.
1197 let end = f.precision().map(|p| core::cmp::min(p, 9)).unwrap_or(pos);
1198
1199 // If we haven't emitted a single fractional digit and the precision
1200 // wasn't set to a non-zero value, we don't print the decimal point.
1201 if end == 0 {
1202 write!(f, "{}", integer_part)
1203 } else {
1204 // SAFETY: We are only writing ASCII digits into the buffer and it was
1205 // initialized with '0's, so it contains valid UTF8.
1206 let s = unsafe { core::str::from_utf8_unchecked(&buf[..end]) };
1207
1208 // If the user request a precision > 9, we pad '0's at the end.
1209 let w = f.precision().unwrap_or(pos);
1210 write!(f, "{}.{:0<width$}", integer_part, s, width = w)
1211 }
1212 }
1213
1214 // Print leading '+' sign if requested
1215 if f.sign_plus() {
1216 write!(f, "+")?;
1217 }
1218
1219 if self.gbps > 0 {
1220 fmt_decimal(f, self.gbps, self.bps.0, BPS_PER_GBPS / 10)?;
1221 f.write_str("gbps")
1222 } else if self.bps.0 >= BPS_PER_MBPS {
1223 fmt_decimal(
1224 f,
1225 (self.bps.0 / BPS_PER_MBPS) as u64,
1226 self.bps.0 % BPS_PER_MBPS,
1227 BPS_PER_MBPS / 10,
1228 )?;
1229 f.write_str("mbps")
1230 } else if self.bps.0 >= BPS_PER_KBPS {
1231 fmt_decimal(
1232 f,
1233 (self.bps.0 / BPS_PER_KBPS) as u64,
1234 self.bps.0 % BPS_PER_KBPS,
1235 BPS_PER_KBPS / 10,
1236 )?;
1237 f.write_str("kbps")
1238 } else {
1239 fmt_decimal(f, self.bps.0 as u64, 0, 1)?;
1240 f.write_str("bps")
1241 }
1242 }
1243}
1244
1245#[rustversion::since(1.67)]
1246impl fmt::Debug for Bandwidth {
1247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1248 /// Formats a floating point number in decimal notation.
1249 ///
1250 /// The number is given as the `integer_part` and a fractional part.
1251 /// The value of the fractional part is `fractional_part / divisor`. So
1252 /// `integer_part` = 3, `fractional_part` = 12 and `divisor` = 100
1253 /// represents the number `3.012`. Trailing zeros are omitted.
1254 ///
1255 /// `divisor` must not be above 100_000_000. It also should be a power
1256 /// of 10, everything else doesn't make sense. `fractional_part` has
1257 /// to be less than `10 * divisor`!
1258 ///
1259 /// A prefix and postfix may be added. The whole thing is padded
1260 /// to the formatter's `width`, if specified.
1261 fn fmt_decimal(
1262 f: &mut fmt::Formatter<'_>,
1263 integer_part: u64,
1264 mut fractional_part: u32,
1265 mut divisor: u32,
1266 prefix: &str,
1267 postfix: &str,
1268 ) -> fmt::Result {
1269 // Encode the fractional part into a temporary buffer. The buffer
1270 // only need to hold 9 elements, because `fractional_part` has to
1271 // be smaller than 10^9. The buffer is prefilled with '0' digits
1272 // to simplify the code below.
1273 let mut buf = [b'0'; 9];
1274
1275 // The next digit is written at this position
1276 let mut pos = 0;
1277
1278 // We keep writing digits into the buffer while there are non-zero
1279 // digits left and we haven't written enough digits yet.
1280 while fractional_part > 0 && pos < f.precision().unwrap_or(9) {
1281 // Write new digit into the buffer
1282 buf[pos] = b'0' + (fractional_part / divisor) as u8;
1283
1284 fractional_part %= divisor;
1285 divisor /= 10;
1286 pos += 1;
1287 }
1288
1289 // If a precision < 9 was specified, there may be some non-zero
1290 // digits left that weren't written into the buffer. In that case we
1291 // need to perform rounding to match the semantics of printing
1292 // normal floating point numbers. However, we only need to do work
1293 // when rounding up. This happens if the first digit of the
1294 // remaining ones is >= 5.
1295 let integer_part = if fractional_part > 0 && fractional_part >= divisor * 5 {
1296 // Round up the number contained in the buffer. We go through
1297 // the buffer backwards and keep track of the carry.
1298 let mut rev_pos = pos;
1299 let mut carry = true;
1300 while carry && rev_pos > 0 {
1301 rev_pos -= 1;
1302
1303 // If the digit in the buffer is not '9', we just need to
1304 // increment it and can stop then (since we don't have a
1305 // carry anymore). Otherwise, we set it to '0' (overflow)
1306 // and continue.
1307 if buf[rev_pos] < b'9' {
1308 buf[rev_pos] += 1;
1309 carry = false;
1310 } else {
1311 buf[rev_pos] = b'0';
1312 }
1313 }
1314
1315 // If we still have the carry bit set, that means that we set
1316 // the whole buffer to '0's and need to increment the integer
1317 // part.
1318 if carry {
1319 // If `integer_part == u64::MAX` and precision < 9, any
1320 // carry of the overflow during rounding of the
1321 // `fractional_part` into the `integer_part` will cause the
1322 // `integer_part` itself to overflow. Avoid this by using an
1323 // `Option<u64>`, with `None` representing `u64::MAX + 1`.
1324 integer_part.checked_add(1)
1325 } else {
1326 Some(integer_part)
1327 }
1328 } else {
1329 Some(integer_part)
1330 };
1331
1332 // Determine the end of the buffer: if precision is set, we just
1333 // use as many digits from the buffer (capped to 9). If it isn't
1334 // set, we only use all digits up to the last non-zero one.
1335 let end = f.precision().map(|p| core::cmp::min(p, 9)).unwrap_or(pos);
1336
1337 // This closure emits the formatted duration without emitting any
1338 // padding (padding is calculated below).
1339 let emit_without_padding = |f: &mut fmt::Formatter<'_>| {
1340 if let Some(integer_part) = integer_part {
1341 write!(f, "{prefix}{integer_part}")?;
1342 } else {
1343 // u64::MAX + 1 == 18446744073709551616
1344 write!(f, "{prefix}18446744073709551616")?;
1345 }
1346
1347 // Write the decimal point and the fractional part (if any).
1348 if end > 0 {
1349 // SAFETY: We are only writing ASCII digits into the buffer and
1350 // it was initialized with '0's, so it contains valid UTF8.
1351 let s = unsafe { core::str::from_utf8_unchecked(&buf[..end]) };
1352
1353 // If the user request a precision > 9, we pad '0's at the end.
1354 let w = f.precision().unwrap_or(pos);
1355 write!(f, ".{s:0<w$}")?;
1356 }
1357
1358 write!(f, "{postfix}")
1359 };
1360
1361 match f.width() {
1362 None => {
1363 // No `width` specified. There's no need to calculate the
1364 // length of the output in this case, just emit it.
1365 emit_without_padding(f)
1366 }
1367 Some(requested_w) => {
1368 // A `width` was specified. Calculate the actual width of
1369 // the output in order to calculate the required padding.
1370 // It consists of 4 parts:
1371 // 1. The prefix: is either "+" or "", so we can just use len().
1372 // 2. The postfix: can be "µs" so we have to count UTF8 characters.
1373 let mut actual_w = prefix.len() + postfix.chars().count();
1374 // 3. The integer part:
1375 if let Some(integer_part) = integer_part {
1376 if let Some(log) = integer_part.checked_ilog10() {
1377 // integer_part is > 0, so has length log10(x)+1
1378 actual_w += 1 + log as usize;
1379 } else {
1380 // integer_part is 0, so has length 1.
1381 actual_w += 1;
1382 }
1383 } else {
1384 // integer_part is u64::MAX + 1, so has length 20
1385 actual_w += 20;
1386 }
1387 // 4. The fractional part (if any):
1388 if end > 0 {
1389 let frac_part_w = f.precision().unwrap_or(pos);
1390 actual_w += 1 + frac_part_w;
1391 }
1392
1393 if requested_w <= actual_w {
1394 // Output is already longer than `width`, so don't pad.
1395 emit_without_padding(f)
1396 } else {
1397 // We need to add padding.
1398 let post_padding_len = requested_w - actual_w;
1399 emit_without_padding(f)?;
1400 for _ in 0..post_padding_len {
1401 f.write_char(f.fill())?;
1402 }
1403 Ok(())
1404 }
1405 }
1406 }
1407 }
1408
1409 // Print leading '+' sign if requested
1410 let prefix = if f.sign_plus() { "+" } else { "" };
1411
1412 if self.gbps > 0 {
1413 fmt_decimal(f, self.gbps, self.bps.0, BPS_PER_GBPS / 10, prefix, "gbps")
1414 } else if self.bps.0 >= BPS_PER_MBPS {
1415 fmt_decimal(
1416 f,
1417 (self.bps.0 / BPS_PER_MBPS) as u64,
1418 self.bps.0 % BPS_PER_MBPS,
1419 BPS_PER_MBPS / 10,
1420 prefix,
1421 "mbps",
1422 )
1423 } else if self.bps.0 >= BPS_PER_KBPS {
1424 fmt_decimal(
1425 f,
1426 (self.bps.0 / BPS_PER_KBPS) as u64,
1427 self.bps.0 % BPS_PER_KBPS,
1428 BPS_PER_KBPS / 10,
1429 prefix,
1430 "kbps",
1431 )
1432 } else {
1433 fmt_decimal(f, self.bps.0 as u64, 0, 1, prefix, "bps")
1434 }
1435 }
1436}