1use core::fmt;
27
28use bandwidth::Bandwidth;
29
30#[cfg(feature = "serde")]
31pub mod serde;
32
33use crate::{item, Error, OverflowOp, Parser};
34
35#[derive(Debug, Clone)]
37pub struct FormattedBinaryBandwidth(Bandwidth);
38
39impl OverflowOp for u128 {
40 fn mul(self, other: Self) -> Result<Self, Error> {
41 self.checked_mul(other).ok_or(Error::NumberOverflow)
42 }
43 fn add(self, other: Self) -> Result<Self, Error> {
44 self.checked_add(other).ok_or(Error::NumberOverflow)
45 }
46}
47
48fn parse_binary_fraction(fraction: u64, fraction_cnt: u32, unit: u32) -> Result<u64, Error> {
52 let rounding = 10_u128.pow(fraction_cnt) >> 1;
53 let fraction = (fraction as u128)
54 .checked_shl(10 * unit)
55 .ok_or(Error::NumberOverflow)?;
56 Ok(((fraction + rounding) / 10u128.pow(fraction_cnt)) as u64)
57}
58
59impl Parser<'_> {
60 fn parse_binary_unit(
61 &mut self,
62 n: u64,
63 fraction: u64,
64 fraction_cnt: u32,
65 start: usize,
66 end: usize,
67 ) -> Result<(), Error> {
68 let unit = match &self.src[start..end] {
69 "Bps" | "Byte/s" | "B/s" | "ops" | "o/s" => 0,
70 "kiBps" | "KiBps" | "kiByte/s" | "KiByte/s" | "kiB/s" | "KiB/s" | "kiops" | "Kiops"
71 | "kio/s" | "Kio/s" => 1,
72 "MiBps" | "miBps" | "MiByte/s" | "miByte/s" | "MiB/s" | "miB/s" | "Miops" | "miops"
73 | "Mio/s" | "mio/s" => 2,
74 "GiBps" | "giBps" | "GiByte/s" | "giByte/s" | "GiB/s" | "giB/s" | "Giops" | "giops"
75 | "Gio/s" | "gio/s" => 3,
76 "TiBps" | "tiBps" | "TiByte/s" | "tiByte/s" | "TiB/s" | "tiB/s" | "Tiops" | "tiops"
77 | "Tio/s" | "tio/s" => 4,
78 _ => {
79 return Err(Error::UnknownBinaryUnit {
80 start,
81 end,
82 unit: self.src[start..end].to_string(),
83 value: n,
84 });
85 }
86 };
87 let bps = (n as u128)
88 .checked_shl(unit * 10)
89 .ok_or(Error::NumberOverflow)? .add(parse_binary_fraction(fraction, fraction_cnt, unit)? as u128)? .mul(8)?; let (gbps, bps) = ((bps / 1_000_000_000), (bps % 1_000_000_000) as u32);
93 let gbps = if gbps > u64::MAX as u128 {
94 return Err(Error::NumberOverflow);
95 } else {
96 gbps as u64
97 };
98 let new_bandwidth = Bandwidth::new(gbps, bps);
99 self.current += new_bandwidth;
100 Ok(())
101 }
102
103 fn parse_binary(mut self) -> Result<Bandwidth, Error> {
104 let mut n = self.parse_first_char()?.ok_or(Error::Empty)?;
105 let mut decimal = false;
106 let mut fraction: u64 = 0;
107 let mut fraction_cnt: u32 = 0;
108 'outer: loop {
109 let mut off = self.off();
110 while let Some(c) = self.iter.next() {
111 match c {
112 '0'..='9' => {
113 if decimal {
114 if fraction_cnt >= super::FRACTION_PART_LIMIT {
115 continue;
116 }
117 fraction = fraction
118 .checked_mul(10)
119 .and_then(|x| x.checked_add(c as u64 - '0' as u64))
120 .ok_or(Error::NumberOverflow)?;
121 fraction_cnt += 1;
122 } else {
123 n = n
124 .checked_mul(10)
125 .and_then(|x| x.checked_add(c as u64 - '0' as u64))
126 .ok_or(Error::NumberOverflow)?;
127 }
128 }
129 c if c.is_whitespace() => {}
130 '_' => {}
131 '.' => {
132 if decimal {
133 return Err(Error::InvalidCharacter(off));
134 }
135 decimal = true;
136 }
137 'a'..='z' | 'A'..='Z' | '/' => {
138 break;
139 }
140 _ => {
141 return Err(Error::InvalidCharacter(off));
142 }
143 }
144 off = self.off();
145 }
146 let start = off;
147 let mut off = self.off();
148 while let Some(c) = self.iter.next() {
149 match c {
150 '0'..='9' => {
151 self.parse_binary_unit(n, fraction, fraction_cnt, start, off)?;
152 n = c as u64 - '0' as u64;
153 fraction = 0;
154 decimal = false;
155 fraction_cnt = 0;
156 continue 'outer;
157 }
158 c if c.is_whitespace() => break,
159 'a'..='z' | 'A'..='Z' | '/' => {}
160 _ => {
161 return Err(Error::InvalidCharacter(off));
162 }
163 }
164 off = self.off();
165 }
166 self.parse_binary_unit(n, fraction, fraction_cnt, start, off)?;
167 n = match self.parse_first_char()? {
168 Some(n) => n,
169 None => return Ok(self.current),
170 };
171 fraction = 0;
172 decimal = false;
173 fraction_cnt = 0;
174 }
175 }
176}
177
178pub fn parse_binary_bandwidth(s: &str) -> Result<Bandwidth, Error> {
210 Parser::new(s).parse_binary()
211}
212
213pub fn format_binary_bandwidth(val: Bandwidth) -> FormattedBinaryBandwidth {
249 FormattedBinaryBandwidth(val)
250}
251
252#[derive(Copy, Clone)]
253#[repr(usize)]
254enum LargestBinaryUnit {
255 Bps = 0,
256 KiBps = 1,
257 MiBps = 2,
258 GiBps = 3,
259 TiBps = 4,
260}
261
262impl fmt::Display for LargestBinaryUnit {
263 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
264 match self {
265 LargestBinaryUnit::Bps => f.write_str("B/s"),
266 LargestBinaryUnit::KiBps => f.write_str("kiB/s"),
267 LargestBinaryUnit::MiBps => f.write_str("MiB/s"),
268 LargestBinaryUnit::GiBps => f.write_str("GiB/s"),
269 LargestBinaryUnit::TiBps => f.write_str("TiB/s"),
270 }
271 }
272}
273
274impl FormattedBinaryBandwidth {
275 pub fn fmt_integer(&self, f: &mut fmt::Formatter) -> fmt::Result {
279 let gbps = self.0.as_gbps();
280 let bps = self.0.subgbps_bps();
281
282 if gbps == 0 && bps == 0 {
283 f.write_str("0B/s")?;
284 return Ok(());
285 }
286
287 let total: u64 = gbps * 1_000_000_000 + bps as u64;
288 let total = (total + 4) / 8;
289
290 let tibps = (total / (1024 * 1024 * 1024 * 1024)) as u32;
291 let total = total % (1024 * 1024 * 1024 * 1024);
292
293 let gibps = (total / (1024 * 1024 * 1024)) as u32;
294 let total = total % (1024 * 1024 * 1024);
295
296 let mibps = (total / (1024 * 1024)) as u32;
297 let total = total % (1024 * 1024);
298
299 let kibps = (total / 1024) as u32;
300 let bps = (total % 1024) as u32;
301
302 let started = &mut false;
303 item(f, started, "TiB/s", tibps)?;
304 item(f, started, "GiB/s", gibps)?;
305 item(f, started, "MiB/s", mibps)?;
306 item(f, started, "kiB/s", kibps)?;
307 item(f, started, "B/s", bps)?;
308 Ok(())
309 }
310
311 pub fn fmt_decimal(&self, f: &mut fmt::Formatter) -> fmt::Result {
315 let gbps = self.0.as_gbps();
316 let bps = self.0.subgbps_bps();
317
318 if gbps == 0 && bps == 0 {
319 f.write_str("0B/s")?;
320 return Ok(());
321 }
322
323 let total: u64 = gbps * 1_000_000_000 + bps as u64;
324 let total = (total + 4) / 8;
325
326 let tibps = (total / (1024 * 1024 * 1024 * 1024)) as u32;
327 let total = total % (1024 * 1024 * 1024 * 1024);
328
329 let gibps = (total / (1024 * 1024 * 1024)) as u32;
330 let total = total % (1024 * 1024 * 1024);
331
332 let mibps = (total / (1024 * 1024)) as u32;
333 let total = total % (1024 * 1024);
334
335 let kibps = (total / 1024) as u32;
336 let bps = (total % 1024) as u32;
337
338 let largest_unit = if tibps > 0 {
339 LargestBinaryUnit::TiBps
340 } else if gibps > 0 {
341 LargestBinaryUnit::GiBps
342 } else if mibps > 0 {
343 LargestBinaryUnit::MiBps
344 } else if kibps > 0 {
345 LargestBinaryUnit::KiBps
346 } else {
347 LargestBinaryUnit::Bps
348 };
349
350 let values = [bps, kibps, mibps, gibps, tibps];
351 let index = largest_unit as usize;
352
353 let mut value = values[index];
354
355 let mut reminder = 0;
356 let mut i = index;
357 while i > 0 {
358 reminder *= 1024;
359 reminder += values[i - 1] as u64;
360 i -= 1;
361 }
362 let mut zeros = index * 3;
363 let reminder = (reminder as u128) * 1000_u128.pow(index as u32);
364 let rounding = if index == 0 { 0 } else { 1 << (index * 10 - 1) };
365 let loss = reminder % (1 << (index * 10));
366 let mut reminder = (reminder + rounding) >> (index * 10);
367 if loss == rounding && reminder % 2 == 1 {
368 reminder -= 1;
369 }
370 if let Some(precision) = f.precision() {
371 let mut rounding_direction = 0;
373 while precision < zeros {
374 let loss = reminder % 10;
375 reminder /= 10;
376 match loss {
377 0 => {
378 }
380 1..5 => {
381 rounding_direction = -1;
383 }
384 5 => {
385 if rounding_direction == 0 {
386 if reminder % 2 == 1 {
388 reminder += 1;
389 rounding_direction = 1;
390 } else {
391 rounding_direction = -1
392 }
393 } else if rounding_direction == -1 {
394 reminder += 1;
397 rounding_direction = 1;
398 } else {
399 rounding_direction = -1;
401 }
402 }
403 6..10 => {
404 reminder += 1;
406 rounding_direction = 1;
407 }
408 _ => unreachable!("The reminder of a divition by 10 is always between 0 and 9"),
409 }
410 zeros -= 1;
411 }
412 if precision == 0 && reminder > 0 {
413 value += reminder as u32;
414 reminder = 0;
415 }
416 } else if reminder != 0 {
417 while reminder % 10 == 0 {
418 reminder /= 10;
419 zeros -= 1;
420 }
421 } else {
422 zeros = 0;
423 }
424 write!(f, "{value}")?;
425 if zeros != 0 || reminder != 0 {
426 write!(f, ".{reminder:0zeros$}", zeros = zeros)?;
427 }
428 write!(f, "{}", largest_unit)
429 }
430}
431
432impl fmt::Display for FormattedBinaryBandwidth {
433 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
434 #[cfg(not(feature = "display-integer"))]
435 self.fmt_decimal(f)?;
436 #[cfg(feature = "display-integer")]
437 self.fmt_integer(f)?;
438 Ok(())
439 }
440}
441
442impl core::ops::Deref for FormattedBinaryBandwidth {
443 type Target = Bandwidth;
444
445 fn deref(&self) -> &Bandwidth {
446 &self.0
447 }
448}
449
450impl core::ops::DerefMut for FormattedBinaryBandwidth {
451 fn deref_mut(&mut self) -> &mut Bandwidth {
452 &mut self.0
453 }
454}
455
456#[cfg(test)]
457mod tests {
458 use super::*;
459 use bandwidth::Bandwidth;
460
461 fn new_bandwidth(tebi: u16, gibi: u16, mibi: u16, kibi: u16, bytes: u16) -> Bandwidth {
462 const KI_B: u64 = 1024 * 8;
463 const MI_B: u64 = 1024 * KI_B;
464 const GI_B: u64 = 1024 * MI_B;
465 const TI_B: u64 = 1024 * GI_B;
466
467 let res: u64 = bytes as u64 * 8
468 + kibi as u64 * KI_B
469 + mibi as u64 * MI_B
470 + gibi as u64 * GI_B
471 + tebi as u64 * TI_B;
472 Bandwidth::new(res / 1_000_000_000, (res % 1_000_000_000) as u32)
473 }
474
475 #[test]
476 fn test_units() {
477 assert_eq!(
478 parse_binary_bandwidth("1Bps"),
479 Ok(new_bandwidth(0, 0, 0, 0, 1))
480 );
481 assert_eq!(
482 parse_binary_bandwidth("2Byte/s"),
483 Ok(new_bandwidth(0, 0, 0, 0, 2))
484 );
485 assert_eq!(
486 parse_binary_bandwidth("15B/s"),
487 Ok(new_bandwidth(0, 0, 0, 0, 15))
488 );
489 assert_eq!(
490 parse_binary_bandwidth("21ops"),
491 Ok(new_bandwidth(0, 0, 0, 0, 21))
492 );
493 assert_eq!(
494 parse_binary_bandwidth("22o/s"),
495 Ok(new_bandwidth(0, 0, 0, 0, 22))
496 );
497 assert_eq!(
498 parse_binary_bandwidth("51kiBps"),
499 Ok(new_bandwidth(0, 0, 0, 51, 0))
500 );
501 assert_eq!(
502 parse_binary_bandwidth("79KiBps"),
503 Ok(new_bandwidth(0, 0, 0, 79, 0))
504 );
505 assert_eq!(
506 parse_binary_bandwidth("81kiByte/s"),
507 Ok(new_bandwidth(0, 0, 0, 81, 0))
508 );
509 assert_eq!(
510 parse_binary_bandwidth("100KiByte/s"),
511 Ok(new_bandwidth(0, 0, 0, 100, 0))
512 );
513 assert_eq!(
514 parse_binary_bandwidth("150kiB/s"),
515 Ok(new_bandwidth(0, 0, 0, 150, 0))
516 );
517 assert_eq!(
518 parse_binary_bandwidth("410KiB/s"),
519 Ok(new_bandwidth(0, 0, 0, 410, 0))
520 );
521 assert_eq!(
522 parse_binary_bandwidth("251kiops"),
523 Ok(new_bandwidth(0, 0, 0, 251, 0))
524 );
525 assert_eq!(
526 parse_binary_bandwidth("279Kiops"),
527 Ok(new_bandwidth(0, 0, 0, 279, 0))
528 );
529 assert_eq!(
530 parse_binary_bandwidth("250kio/s"),
531 Ok(new_bandwidth(0, 0, 0, 250, 0))
532 );
533 assert_eq!(
534 parse_binary_bandwidth("210Kio/s"),
535 Ok(new_bandwidth(0, 0, 0, 210, 0))
536 );
537 assert_eq!(
538 parse_binary_bandwidth("12MiBps"),
539 Ok(new_bandwidth(0, 0, 12, 0, 0))
540 );
541 assert_eq!(
542 parse_binary_bandwidth("16miBps"),
543 Ok(new_bandwidth(0, 0, 16, 0, 0))
544 );
545 assert_eq!(
546 parse_binary_bandwidth("24MiByte/s"),
547 Ok(new_bandwidth(0, 0, 24, 0, 0))
548 );
549 assert_eq!(
550 parse_binary_bandwidth("36miByte/s"),
551 Ok(new_bandwidth(0, 0, 36, 0, 0))
552 );
553 assert_eq!(
554 parse_binary_bandwidth("48MiB/s"),
555 Ok(new_bandwidth(0, 0, 48, 0, 0))
556 );
557 assert_eq!(
558 parse_binary_bandwidth("96miB/s"),
559 Ok(new_bandwidth(0, 0, 96, 0, 0))
560 );
561 assert_eq!(
562 parse_binary_bandwidth("212Miops"),
563 Ok(new_bandwidth(0, 0, 212, 0, 0))
564 );
565 assert_eq!(
566 parse_binary_bandwidth("216miops"),
567 Ok(new_bandwidth(0, 0, 216, 0, 0))
568 );
569 assert_eq!(
570 parse_binary_bandwidth("248Mio/s"),
571 Ok(new_bandwidth(0, 0, 248, 0, 0))
572 );
573 assert_eq!(
574 parse_binary_bandwidth("296mio/s"),
575 Ok(new_bandwidth(0, 0, 296, 0, 0))
576 );
577 assert_eq!(
578 parse_binary_bandwidth("2GiBps"),
579 Ok(new_bandwidth(0, 2, 0, 0, 0))
580 );
581 assert_eq!(
582 parse_binary_bandwidth("4giBps"),
583 Ok(new_bandwidth(0, 4, 0, 0, 0))
584 );
585 assert_eq!(
586 parse_binary_bandwidth("6GiByte/s"),
587 Ok(new_bandwidth(0, 6, 0, 0, 0))
588 );
589 assert_eq!(
590 parse_binary_bandwidth("8giByte/s"),
591 Ok(new_bandwidth(0, 8, 0, 0, 0))
592 );
593 assert_eq!(
594 parse_binary_bandwidth("16GiB/s"),
595 Ok(new_bandwidth(0, 16, 0, 0, 0))
596 );
597 assert_eq!(
598 parse_binary_bandwidth("40giB/s"),
599 Ok(new_bandwidth(0, 40, 0, 0, 0))
600 );
601 assert_eq!(
602 parse_binary_bandwidth("202Giops"),
603 Ok(new_bandwidth(0, 202, 0, 0, 0))
604 );
605 assert_eq!(
606 parse_binary_bandwidth("204giops"),
607 Ok(new_bandwidth(0, 204, 0, 0, 0))
608 );
609 assert_eq!(
610 parse_binary_bandwidth("216Gio/s"),
611 Ok(new_bandwidth(0, 216, 0, 0, 0))
612 );
613 assert_eq!(
614 parse_binary_bandwidth("240gio/s"),
615 Ok(new_bandwidth(0, 240, 0, 0, 0))
616 );
617 assert_eq!(
618 parse_binary_bandwidth("1TiBps"),
619 Ok(new_bandwidth(1, 0, 0, 0, 0))
620 );
621 assert_eq!(
622 parse_binary_bandwidth("2tiBps"),
623 Ok(new_bandwidth(2, 0, 0, 0, 0))
624 );
625 assert_eq!(
626 parse_binary_bandwidth("4TiByte/s"),
627 Ok(new_bandwidth(4, 0, 0, 0, 0))
628 );
629 assert_eq!(
630 parse_binary_bandwidth("8tiByte/s"),
631 Ok(new_bandwidth(8, 0, 0, 0, 0))
632 );
633 assert_eq!(
634 parse_binary_bandwidth("16TiB/s"),
635 Ok(new_bandwidth(16, 0, 0, 0, 0))
636 );
637 assert_eq!(
638 parse_binary_bandwidth("32tiB/s"),
639 Ok(new_bandwidth(32, 0, 0, 0, 0))
640 );
641 assert_eq!(
642 parse_binary_bandwidth("201Tiops"),
643 Ok(new_bandwidth(201, 0, 0, 0, 0))
644 );
645 assert_eq!(
646 parse_binary_bandwidth("202tiops"),
647 Ok(new_bandwidth(202, 0, 0, 0, 0))
648 );
649 assert_eq!(
650 parse_binary_bandwidth("216Tio/s"),
651 Ok(new_bandwidth(216, 0, 0, 0, 0))
652 );
653 assert_eq!(
654 parse_binary_bandwidth("232tio/s"),
655 Ok(new_bandwidth(232, 0, 0, 0, 0))
656 );
657 }
658
659 #[test]
660 fn test_decimal() {
661 assert_eq!(
662 parse_binary_bandwidth("1.5Bps"),
663 Ok(new_bandwidth(0, 0, 0, 0, 2))
664 );
665 assert_eq!(
666 parse_binary_bandwidth("2.5Byte/s"),
667 Ok(new_bandwidth(0, 0, 0, 0, 3))
668 );
669 assert_eq!(
670 parse_binary_bandwidth("15.5B/s"),
671 Ok(new_bandwidth(0, 0, 0, 0, 16))
672 );
673 assert_eq!(
674 parse_binary_bandwidth("51.6kiBps"),
675 Ok(new_bandwidth(0, 0, 0, 51, 614))
676 );
677 assert_eq!(
678 parse_binary_bandwidth("79.78KiBps"),
679 Ok(new_bandwidth(0, 0, 0, 79, 799))
680 );
681 assert_eq!(
682 parse_binary_bandwidth("81.923kiByte/s"),
683 Ok(new_bandwidth(0, 0, 0, 81, 945))
684 );
685 assert_eq!(
686 parse_binary_bandwidth("100.1234KiByte/s"),
687 Ok(new_bandwidth(0, 0, 0, 100, 126))
688 );
689 assert_eq!(
690 parse_binary_bandwidth("150.12345kiB/s"),
691 Ok(new_bandwidth(0, 0, 0, 150, 126))
692 );
693 assert_eq!(
694 parse_binary_bandwidth("410.123456KiB/s"),
695 Ok(new_bandwidth(0, 0, 0, 410, 126))
696 );
697 assert_eq!(
698 parse_binary_bandwidth("12.123MiBps"),
699 Ok(new_bandwidth(0, 0, 12, 125, 975))
700 );
701 assert_eq!(
702 parse_binary_bandwidth("16.1234miBps"),
703 Ok(new_bandwidth(0, 0, 16, 126, 370))
704 );
705 assert_eq!(
706 parse_binary_bandwidth("24.12345MiByte/s"),
707 Ok(new_bandwidth(0, 0, 24, 126, 423))
708 );
709 assert_eq!(
710 parse_binary_bandwidth("36.123456miByte/s"),
711 Ok(new_bandwidth(0, 0, 36, 126, 429))
712 );
713 assert_eq!(
714 parse_binary_bandwidth("48.123MiB/s"),
715 Ok(new_bandwidth(0, 0, 48, 125, 975))
716 );
717 assert_eq!(
718 parse_binary_bandwidth("96.1234miB/s"),
719 Ok(new_bandwidth(0, 0, 96, 126, 370))
720 );
721 assert_eq!(
722 parse_binary_bandwidth("2.123GiBps"),
723 Ok(new_bandwidth(0, 2, 125, 974, 868))
724 );
725 assert_eq!(
726 parse_binary_bandwidth("4.1234giBps"),
727 Ok(new_bandwidth(0, 4, 126, 370, 285))
728 );
729 assert_eq!(
730 parse_binary_bandwidth("6.12345GiByte/s"),
731 Ok(new_bandwidth(0, 6, 126, 422, 724))
732 );
733 assert_eq!(
734 parse_binary_bandwidth("8.123456giByte/s"),
735 Ok(new_bandwidth(0, 8, 126, 428, 1023))
736 );
737 assert_eq!(
738 parse_binary_bandwidth("16.123456789GiB/s"),
739 Ok(new_bandwidth(0, 16, 126, 429, 846))
740 );
741 assert_eq!(
742 parse_binary_bandwidth("40.12345678912giB/s"),
743 Ok(new_bandwidth(0, 40, 126, 429, 846))
744 );
745 assert_eq!(
746 parse_binary_bandwidth("1.123TiBps"),
747 Ok(new_bandwidth(1, 125, 974, 868, 360))
748 );
749 assert_eq!(
750 parse_binary_bandwidth("2.1234tiBps"),
751 Ok(new_bandwidth(2, 126, 370, 285, 84))
752 );
753 assert_eq!(
754 parse_binary_bandwidth("4.12345TiByte/s"),
755 Ok(new_bandwidth(4, 126, 422, 724, 177))
756 );
757 assert_eq!(
758 parse_binary_bandwidth("8.123456tiByte/s"),
759 Ok(new_bandwidth(8, 126, 428, 1022, 639))
760 );
761 assert_eq!(
762 parse_binary_bandwidth("16.123456789TiB/s"),
763 Ok(new_bandwidth(16, 126, 429, 845, 825))
764 );
765 assert_eq!(
766 parse_binary_bandwidth("32.12345678912tiB/s"),
767 Ok(new_bandwidth(32, 126, 429, 845, 957))
768 );
769 }
770
771 #[test]
772 fn test_combo() {
773 assert_eq!(
774 parse_binary_bandwidth("1Bps 2Byte/s 3B/s"),
775 Ok(new_bandwidth(0, 0, 0, 0, 6))
776 );
777 assert_eq!(
778 parse_binary_bandwidth("4kiBps 5KiBps 6kiByte/s"),
779 Ok(new_bandwidth(0, 0, 0, 15, 0))
780 );
781 assert_eq!(
782 parse_binary_bandwidth("7MiBps 8miBps 9MiByte/s"),
783 Ok(new_bandwidth(0, 0, 24, 0, 0))
784 );
785 assert_eq!(
786 parse_binary_bandwidth("10GiBps 11giBps 12GiByte/s"),
787 Ok(new_bandwidth(0, 33, 0, 0, 0))
788 );
789 assert_eq!(
790 parse_binary_bandwidth("13TiBps 14tiBps 15TiByte/s"),
791 Ok(new_bandwidth(42, 0, 0, 0, 0))
792 );
793 assert_eq!(
794 parse_binary_bandwidth("10GiBps 5MiBps 1B/s"),
795 Ok(new_bandwidth(0, 10, 5, 0, 1))
796 );
797 assert_eq!(
798 parse_binary_bandwidth("36MiBps 12kiBps 24Bps"),
799 Ok(new_bandwidth(0, 0, 36, 12, 24))
800 );
801 }
802
803 #[test]
804 fn test_decimal_combo() {
805 assert_eq!(
806 parse_binary_bandwidth("1.1Bps 2.2Byte/s 3.3B/s"),
807 Ok(new_bandwidth(0, 0, 0, 0, 6))
808 );
809 assert_eq!(
810 parse_binary_bandwidth("4.4kiBps 5.5KiBps 6.6kiByte/s"),
811 Ok(new_bandwidth(0, 0, 0, 16, 512))
812 );
813 assert_eq!(
814 parse_binary_bandwidth("7.7MiBps 8.8miBps 9.9MiByte/s"),
815 Ok(new_bandwidth(0, 0, 26, 409, 614))
816 );
817 assert_eq!(
818 parse_binary_bandwidth("10.10GiBps 11.11giBps 12.12GiByte/s"),
819 Ok(new_bandwidth(0, 33, 337, 942, 82))
820 );
821 assert_eq!(
822 parse_binary_bandwidth("13.13TiBps 14.14tiBps 15.15TiByte/s"),
823 Ok(new_bandwidth(42, 430, 81, 942, 82))
824 );
825 assert_eq!(
826 parse_binary_bandwidth("10.1GiBps 5.2MiBps 1.3B/s"),
827 Ok(new_bandwidth(0, 10, 107, 614, 410))
828 );
829 assert_eq!(
830 parse_binary_bandwidth("36.1MiBps 12.2kiBps 24.3Bps"),
831 Ok(new_bandwidth(0, 0, 36, 114, 639))
832 );
833 }
834
835 #[test]
836 fn test_overflow() {
837 assert_eq!(
839 parse_binary_bandwidth("100_000_000_000_000_000_000Bps"),
840 Err(Error::NumberOverflow)
841 );
842 assert!(parse_binary_bandwidth("10_000_000_000_000_000_000Bps").is_ok());
843 assert_eq!(
844 parse_binary_bandwidth("100_000_000_000_000_000_000kiBps"),
845 Err(Error::NumberOverflow)
846 );
847 assert!(parse_binary_bandwidth("10_000_000_000_000_000_000kiBps").is_ok());
848 assert_eq!(
849 parse_binary_bandwidth("100_000_000_000_000_000_000MiBps"),
850 Err(Error::NumberOverflow)
851 );
852 assert!(parse_binary_bandwidth("10_000_000_000_000_000_000MiBps").is_ok());
853
854 assert_eq!(
856 parse_binary_bandwidth("10_000_000_000_000_000_000GiBps"),
857 Err(Error::NumberOverflow)
858 );
859 assert!(parse_binary_bandwidth("1_000_000_000_000_000_000GiBps").is_ok());
860 assert_eq!(
861 parse_binary_bandwidth("10_000_000_000_000_000TiBps"),
862 Err(Error::NumberOverflow)
863 );
864 assert!(parse_binary_bandwidth("1_000_000_000_000_000TiBps").is_ok());
865 }
866
867 #[test]
868 fn test_nice_error_message() {
869 assert_eq!(
870 parse_binary_bandwidth("123").unwrap_err().to_string(),
871 "binary bandwidth unit needed, for example 123MiB/s or 123B/s"
872 );
873 assert_eq!(
874 parse_binary_bandwidth("10 GiBps 1")
875 .unwrap_err()
876 .to_string(),
877 "binary bandwidth unit needed, for example 1MiB/s or 1B/s"
878 );
879 assert_eq!(
880 parse_binary_bandwidth("10 byte/s").unwrap_err().to_string(),
881 "unknown binary bandwidth unit \"byte/s\", \
882 supported units: B/s, kiB/s, MiB/s, GiB/s, TiB/s"
883 );
884 }
885
886 #[test]
887 fn test_formatted_bandwidth_integer() {
888 struct TestInteger(FormattedBinaryBandwidth);
889 impl From<FormattedBinaryBandwidth> for TestInteger {
890 fn from(fb: FormattedBinaryBandwidth) -> Self {
891 TestInteger(fb)
892 }
893 }
894 impl fmt::Display for TestInteger {
895 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
896 self.0.fmt_integer(f)
897 }
898 }
899 assert_eq!(
900 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 0, 0, 0, 0))).to_string(),
901 "0B/s"
902 );
903 assert_eq!(
904 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 0, 0, 0, 1))).to_string(),
905 "1B/s"
906 );
907 assert_eq!(
908 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 0, 0, 0, 15))).to_string(),
909 "15B/s"
910 );
911 assert_eq!(
912 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 0, 0, 51, 0))).to_string(),
913 "51kiB/s"
914 );
915 assert_eq!(
916 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 0, 32, 0, 0))).to_string(),
917 "32MiB/s"
918 );
919 assert_eq!(
920 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 0, 79, 0, 0))).to_string(),
921 "79MiB/s"
922 );
923 assert_eq!(
924 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 0, 100, 0, 0))).to_string(),
925 "100MiB/s"
926 );
927 assert_eq!(
928 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 0, 150, 0, 0))).to_string(),
929 "150MiB/s"
930 );
931 assert_eq!(
932 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 0, 410, 0, 0))).to_string(),
933 "410MiB/s"
934 );
935 assert_eq!(
936 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 1, 0, 0, 0))).to_string(),
937 "1GiB/s"
938 );
939 assert_eq!(
940 TestInteger::from(format_binary_bandwidth(new_bandwidth(0, 4, 500, 0, 0))).to_string(),
941 "4GiB/s 500MiB/s"
942 );
943 assert_eq!(
944 TestInteger::from(format_binary_bandwidth(new_bandwidth(9, 420, 0, 0, 0))).to_string(),
945 "9TiB/s 420GiB/s"
946 );
947 }
948
949 #[test]
950 fn test_formatted_bandwidth_decimal() {
951 struct TestDecimal(FormattedBinaryBandwidth);
952 impl From<FormattedBinaryBandwidth> for TestDecimal {
953 fn from(fb: FormattedBinaryBandwidth) -> Self {
954 TestDecimal(fb)
955 }
956 }
957 impl fmt::Display for TestDecimal {
958 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
959 self.0.fmt_decimal(f)
960 }
961 }
962 assert_eq!(
963 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 0, 0, 0, 0))).to_string(),
964 "0B/s"
965 );
966 assert_eq!(
967 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 0, 0, 0, 1))).to_string(),
968 "1B/s"
969 );
970 assert_eq!(
971 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 0, 0, 0, 15))).to_string(),
972 "15B/s"
973 );
974 assert_eq!(
975 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 0, 0, 51, 256))).to_string(),
976 "51.25kiB/s"
977 );
978 assert_eq!(
979 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 0, 32, 256, 0))).to_string(),
980 "32.25MiB/s"
981 );
982 assert_eq!(
983 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 0, 79, 0, 5))).to_string(),
984 "79.000005MiB/s"
985 );
986 assert_eq!(
987 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 0, 100, 128, 7)))
988 .to_string(),
989 "100.125007MiB/s"
990 );
991 assert_eq!(
992 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 0, 150, 0, 0))).to_string(),
993 "150MiB/s"
994 );
995 assert_eq!(
996 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 0, 410, 9, 116)))
997 .to_string(),
998 "410.0089MiB/s"
999 );
1000 assert_eq!(
1001 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 1, 0, 0, 0))).to_string(),
1002 "1GiB/s"
1003 );
1004 assert_eq!(
1005 TestDecimal::from(format_binary_bandwidth(new_bandwidth(0, 4, 512, 0, 0))).to_string(),
1006 "4.5GiB/s"
1007 );
1008 assert_eq!(
1009 TestDecimal::from(format_binary_bandwidth(new_bandwidth(8, 768, 0, 0, 0))).to_string(),
1010 "8.75TiB/s"
1011 );
1012 assert_eq!(
1013 "9.375TiB/s",
1014 TestDecimal::from(format_binary_bandwidth(new_bandwidth(9, 384, 0, 0, 0))).to_string(),
1015 );
1016 }
1017
1018 #[test]
1019 fn test_formatted_bandwidth_decimal_with_precision() {
1020 struct TestDecimal(FormattedBinaryBandwidth);
1021 impl From<FormattedBinaryBandwidth> for TestDecimal {
1022 fn from(fb: FormattedBinaryBandwidth) -> Self {
1023 TestDecimal(fb)
1024 }
1025 }
1026 impl fmt::Display for TestDecimal {
1027 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1028 self.0.fmt_decimal(f)
1029 }
1030 }
1031 let bandwidths = [
1032 (new_bandwidth(0, 0, 0, 0, 0), 0, 0, "B/s", 0),
1033 (new_bandwidth(0, 0, 0, 0, 1), 1, 0, "B/s", 0),
1034 (new_bandwidth(0, 0, 0, 0, 15), 15, 0, "B/s", 0),
1035 (new_bandwidth(0, 0, 0, 51, 256), 51, 250, "kiB/s", 3),
1036 (new_bandwidth(0, 0, 32, 256, 0), 32, 250_000, "MiB/s", 6),
1037 (new_bandwidth(0, 0, 79, 0, 5), 79, 5, "MiB/s", 6),
1038 (new_bandwidth(0, 0, 100, 128, 7), 100, 125_007, "MiB/s", 6),
1039 (new_bandwidth(0, 0, 150, 0, 0), 150, 0, "MiB/s", 6),
1040 (new_bandwidth(0, 0, 410, 9, 116), 410, 8_900, "MiB/s", 6),
1041 (new_bandwidth(0, 1, 0, 0, 0), 1, 0, "GiB/s", 9),
1042 (new_bandwidth(0, 4, 512, 0, 0), 4, 500_000_000, "GiB/s", 9),
1043 (
1044 new_bandwidth(8, 768, 0, 0, 0),
1045 8,
1046 750_000_000_000,
1047 "TiB/s",
1048 12,
1049 ),
1050 (
1051 new_bandwidth(9, 384, 0, 0, 0),
1052 9,
1053 375_000_000_000,
1054 "TiB/s",
1055 12,
1056 ),
1057 ];
1058 for precision in 0..7 {
1059 for (bandwidth, int, fract, unit, max_precision) in bandwidths.iter() {
1060 let bandwidth = TestDecimal::from(format_binary_bandwidth(*bandwidth));
1061 let pow = 10_u64.pow((max_precision - precision.min(*max_precision)) as u32);
1062 let fract = if pow != 1 {
1063 if fract % pow > pow / 2 || fract % pow == pow / 2 && fract / pow % 2 == 1 {
1064 fract / pow + 1
1065 } else {
1066 fract / pow
1067 }
1068 } else {
1069 *fract
1070 };
1071 if precision != 0 && *max_precision != 0 {
1072 assert_eq!(
1073 format!("{bandwidth:.precision$}"),
1074 format!(
1075 "{int}.{fract:0precision$}{unit}",
1076 precision = precision.min(*max_precision)
1077 )
1078 );
1079 } else {
1080 let int = if fract == 1 { int + 1 } else { *int };
1081 assert_eq!(format!("{bandwidth:.precision$}"), format!("{int}{unit}"));
1082 }
1083 }
1084 }
1085 }
1086}