1use std::time::Duration;
28
29const NUM_MILLIS_PER_SECOND: u64 = 1000;
30const NUM_MICROS_PER_MILLI: u64 = 1000;
31const NUM_MICROS_PER_SECOND: u64 = NUM_MICROS_PER_MILLI * NUM_MILLIS_PER_SECOND;
32const NUM_NANOS_PER_SECOND: u64 = 1000 * NUM_MICROS_PER_SECOND;
33
34#[derive(PartialEq, PartialOrd, Eq, Ord, Clone, Copy)]
35pub struct Bandwidth {
36 bits_per_second: u64,
37}
38
39impl std::ops::Mul<f64> for Bandwidth {
40 type Output = Bandwidth;
41
42 fn mul(self, rhs: f64) -> Self::Output {
43 Bandwidth {
44 bits_per_second: (self.bits_per_second as f64 * rhs).round() as u64,
45 }
46 }
47}
48
49impl std::ops::Mul<f32> for Bandwidth {
50 type Output = Bandwidth;
51
52 fn mul(self, rhs: f32) -> Self::Output {
53 self * rhs as f64
54 }
55}
56
57impl std::ops::Sub<Bandwidth> for Bandwidth {
58 type Output = Option<Bandwidth>;
59
60 fn sub(self, rhs: Bandwidth) -> Self::Output {
61 self.bits_per_second
62 .checked_sub(rhs.bits_per_second)
63 .map(|bps| Bandwidth {
64 bits_per_second: bps,
65 })
66 }
67}
68
69impl std::ops::Add<Bandwidth> for Bandwidth {
70 type Output = Bandwidth;
71
72 fn add(self, rhs: Bandwidth) -> Self::Output {
73 Bandwidth {
74 bits_per_second: self.bits_per_second.add(rhs.bits_per_second),
75 }
76 }
77}
78
79impl std::ops::Mul<Duration> for Bandwidth {
80 type Output = u64;
81
82 fn mul(self, rhs: Duration) -> Self::Output {
83 self.to_bytes_per_period(rhs)
84 }
85}
86
87impl Bandwidth {
88 pub const fn from_bytes_and_time_delta(
89 bytes: usize, time_delta: Duration,
90 ) -> Self {
91 if bytes == 0 {
92 return Bandwidth { bits_per_second: 0 };
93 }
94
95 let mut nanos = time_delta.as_nanos() as u64;
96 if nanos == 0 {
97 nanos = 1;
98 }
99
100 let num_nano_bits = 8 * bytes as u64 * NUM_NANOS_PER_SECOND;
101 if num_nano_bits < nanos {
102 return Bandwidth { bits_per_second: 1 };
103 }
104
105 Bandwidth {
106 bits_per_second: num_nano_bits / nanos,
107 }
108 }
109
110 #[allow(dead_code)]
111 pub const fn from_bytes_per_second(bytes_per_second: u64) -> Self {
112 Bandwidth {
113 bits_per_second: bytes_per_second * 8,
114 }
115 }
116
117 #[allow(dead_code)]
118 pub const fn to_bits_per_second(self) -> u64 {
119 self.bits_per_second
120 }
121
122 pub const fn to_bytes_per_second(self) -> u64 {
123 self.bits_per_second / 8
124 }
125
126 pub const fn from_kbits_per_second(k_bits_per_second: u64) -> Self {
127 Bandwidth {
128 bits_per_second: k_bits_per_second * 1_000,
129 }
130 }
131
132 #[allow(dead_code)]
133 pub const fn from_mbits_per_second(m_bits_per_second: u64) -> Self {
134 Bandwidth::from_kbits_per_second(m_bits_per_second * 1_000)
135 }
136
137 pub const fn infinite() -> Self {
139 Bandwidth {
140 bits_per_second: u64::MAX,
141 }
142 }
143
144 pub const fn zero() -> Self {
145 Bandwidth { bits_per_second: 0 }
146 }
147
148 pub fn transfer_time(&self, bytes: u64) -> Duration {
154 if self.bits_per_second == u64::MAX {
156 return Duration::ZERO;
157 }
158
159 if self.bits_per_second == 0 {
160 return Duration::ZERO;
161 }
162
163 if let Some(nanos) = bytes.checked_mul(8 * NUM_NANOS_PER_SECOND) {
166 return Duration::from_nanos(nanos / self.bits_per_second);
167 }
168
169 let nanos = (bytes as u128) * (8 * NUM_NANOS_PER_SECOND) as u128;
173 let nanos = nanos / (self.bits_per_second as u128);
174
175 Duration::from_nanos(nanos.min(u64::MAX as u128) as u64)
177 }
178
179 pub fn to_bytes_per_period(self, time_period: Duration) -> u64 {
186 if self.bits_per_second == u64::MAX {
188 if time_period != Duration::ZERO {
189 return u64::MAX;
190 } else {
191 return 0;
192 }
193 }
194
195 if let Ok(time_nanos) = u64::try_from(time_period.as_nanos()) {
198 if let Some(bits) = self.bits_per_second.checked_mul(time_nanos) {
199 return bits / (8 * NUM_NANOS_PER_SECOND);
200 }
201 }
202
203 let time_nanos = time_period.as_nanos();
207 let bits = (self.bits_per_second as u128).saturating_mul(time_nanos);
208 let bytes = bits / (8 * NUM_NANOS_PER_SECOND) as u128;
209
210 bytes.min(u64::MAX as u128) as u64
212 }
213}
214
215impl std::fmt::Debug for Bandwidth {
216 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
217 match self.bits_per_second {
218 x if x < 1_000_000 => write!(f, "{:.2} Kbps", x as f64 / 1_000.),
219 x if x < 1_000_000_000 => {
220 write!(f, "{:.2} Mbps", x as f64 / 1_000_000.)
221 },
222 x => write!(f, "{:.2} Gbps", x as f64 / 1_000_000_000.),
223 }
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230
231 #[test]
232 fn constructors() {
233 assert_eq!(Bandwidth::from_bytes_per_second(100).bits_per_second, 800);
235 let bw = Bandwidth::from_bytes_per_second(100);
236 assert_eq!(bw.to_bits_per_second(), 800);
237 assert_eq!(bw.to_bytes_per_second(), 100);
238
239 assert_eq!(
241 Bandwidth::from_kbits_per_second(100).bits_per_second,
242 100_000
243 );
244
245 assert_eq!(
247 Bandwidth::from_mbits_per_second(100).bits_per_second,
248 100_000_000
249 );
250
251 assert_eq!(Bandwidth::infinite().bits_per_second, u64::MAX);
252 assert_eq!(Bandwidth::zero().bits_per_second, 0);
253 }
254
255 #[test]
256 fn arithmetic_ops() {
257 let bw_1k = Bandwidth::from_kbits_per_second(1);
258 let bw_5k = Bandwidth::from_kbits_per_second(5);
259 let bw_6k = Bandwidth::from_kbits_per_second(6);
260
261 assert_eq!(bw_1k + bw_5k, bw_6k);
263
264 assert_eq!(bw_6k - bw_5k, Some(bw_1k));
266 assert_eq!(bw_6k - bw_6k, Some(Bandwidth::zero()));
267
268 assert_eq!(bw_1k - bw_5k, None);
270
271 assert_eq!(bw_1k * 6.0f64, bw_6k);
273 assert_eq!(bw_1k * 6.0f32, bw_6k);
274 assert_eq!(bw_5k * 0.0, Bandwidth::zero());
275 assert_eq!(bw_5k * 1.0, bw_5k);
276
277 assert_eq!(Bandwidth::infinite() * -1.0, Bandwidth::zero());
279 assert_eq!((Bandwidth::infinite() * 2.0f64).bits_per_second, u64::MAX);
280
281 assert_eq!(
283 (Bandwidth::infinite() * 0.5f64).bits_per_second,
284 u64::MAX / 2 + 1
285 );
286 }
287
288 #[test]
289 fn from_bytes_and_time_delta() {
290 assert_eq!(
291 Bandwidth::from_bytes_and_time_delta(10, Duration::from_millis(1000))
292 .bits_per_second,
293 80
294 );
295 assert_eq!(
296 Bandwidth::from_bytes_and_time_delta(10, Duration::from_millis(100))
297 .bits_per_second,
298 800
299 );
300 assert_eq!(
301 Bandwidth::from_bytes_and_time_delta(
302 100,
303 Duration::from_millis(1000)
304 )
305 .bits_per_second,
306 800
307 );
308 }
309
310 #[test]
311 fn transfer_time() {
312 let one_kbit_sec = Bandwidth::from_kbits_per_second(1);
313 assert_eq!(one_kbit_sec.transfer_time(0), Duration::ZERO);
314 assert_eq!(one_kbit_sec.transfer_time(100), Duration::from_millis(800));
315 }
316
317 #[test]
320 fn transfer_time_overflow() {
321 let low_bandwidth = Bandwidth::from_kbits_per_second(1);
322
323 let large_bytes = u64::MAX;
326 let result = low_bandwidth.transfer_time(large_bytes);
327
328 assert_eq!(result, Duration::from_nanos(u64::MAX));
332
333 let one_gbps = Bandwidth::from_mbits_per_second(1_000); let ten_gib = 10 * 1024 * 1024 * 1024;
336 let expected = Duration::from_nanos(85_899_345_920);
338 assert_eq!(one_gbps.transfer_time(ten_gib), expected);
339 }
340
341 #[test]
342 fn transfer_time_infinite() {
343 let inf = Bandwidth::infinite();
345
346 assert_eq!(inf.transfer_time(0), Duration::ZERO);
348
349 assert_eq!(inf.transfer_time(1), Duration::ZERO);
351 assert_eq!(inf.transfer_time(100), Duration::ZERO);
352 assert_eq!(inf.transfer_time(1024), Duration::ZERO);
353
354 assert_eq!(inf.transfer_time(1_000_000), Duration::ZERO);
356 assert_eq!(inf.transfer_time(u64::MAX), Duration::ZERO);
357 }
358
359 #[test]
360 fn to_bytes_per_period() {
361 let one_kbit_sec = Bandwidth::from_kbits_per_second(1);
362 assert_eq!(
363 one_kbit_sec.to_bytes_per_period(Duration::from_millis(10_000)),
364 1250
365 );
366 assert_eq!(
367 one_kbit_sec.to_bytes_per_period(Duration::from_millis(1000)),
368 125
369 );
370 assert_eq!(
371 one_kbit_sec.to_bytes_per_period(Duration::from_millis(100)),
372 12
373 );
374 assert_eq!(
375 one_kbit_sec.to_bytes_per_period(Duration::from_millis(10)),
376 1
377 );
378 assert_eq!(
379 one_kbit_sec.to_bytes_per_period(Duration::from_millis(1)),
380 0
381 );
382
383 assert_eq!(one_kbit_sec * Duration::from_millis(10_000), 1250);
385 }
386
387 #[test]
388 fn to_bytes_per_period_high_bandwidth() {
389 let ten_gbps = Bandwidth::from_mbits_per_second(10_000);
391 assert_eq!(
392 ten_gbps.to_bytes_per_period(Duration::from_secs(1)),
393 1_250_000_000
394 );
395
396 let hundred_gbps = Bandwidth::from_mbits_per_second(100_000);
398 assert_eq!(
399 hundred_gbps.to_bytes_per_period(Duration::from_millis(100)),
400 1_250_000_000
401 );
402
403 let one_tbps = Bandwidth::from_mbits_per_second(1_000_000);
405 assert_eq!(
406 one_tbps.to_bytes_per_period(Duration::from_millis(10)),
407 1_250_000_000
408 );
409 }
410
411 #[test]
412 fn to_bytes_per_period_overflow_intermediate() {
413 let huge_bw = Bandwidth {
417 bits_per_second: 10_000_000_000_000_000_000,
418 };
419 let result = huge_bw.to_bytes_per_period(Duration::from_secs(1));
420 assert_eq!(result, 1_250_000_000_000_000_000);
421 }
422
423 #[test]
424 fn to_bytes_per_period_saturate_very_high_bandwidth() {
425 let very_high_bw = Bandwidth {
428 bits_per_second: 1u64 << 63, };
430 let result = very_high_bw.to_bytes_per_period(Duration::from_secs(100));
431 assert_eq!(result, u64::MAX);
433 }
434
435 #[test]
436 fn to_bytes_per_period_saturate_long_period() {
437 let high_bw = Bandwidth {
439 bits_per_second: u64::MAX / 2,
440 };
441 let result = high_bw.to_bytes_per_period(Duration::from_secs(100));
442 assert_eq!(result, u64::MAX);
444 }
445
446 #[test]
447 fn to_bytes_per_period_large_no_saturate() {
448 let high_bw = Bandwidth::from_mbits_per_second(100_000); let one_hour = Duration::from_secs(3600);
451 let result = high_bw.to_bytes_per_period(one_hour);
452 assert_eq!(result, 45_000_000_000_000); }
454
455 #[test]
456 fn to_bytes_per_period_infinite() {
457 let inf = Bandwidth::infinite();
459 assert_eq!(inf.to_bytes_per_period(Duration::from_secs(1)), u64::MAX);
460 assert_eq!(inf.to_bytes_per_period(Duration::from_millis(1)), u64::MAX);
461 assert_eq!(inf.to_bytes_per_period(Duration::ZERO), 0);
462
463 assert_eq!(inf * Duration::from_secs(1), u64::MAX);
465 }
466
467 #[test]
468 fn to_bytes_per_period_duration_exceeds_u64_nanos() {
469 let bw = Bandwidth::from_mbits_per_second(1000); let huge_duration = Duration::from_secs(20_000_000_000); let result = bw.to_bytes_per_period(huge_duration);
483 assert_eq!(result, 2_500_000_000_000_000_000);
484 }
485
486 #[test]
487 fn to_bytes_per_period_u128_overflow() {
488 let huge_bw = Bandwidth {
494 bits_per_second: u64::MAX - 1,
495 };
496 let max_duration = Duration::MAX;
497
498 let result = huge_bw.to_bytes_per_period(max_duration);
501 assert_eq!(result, u64::MAX);
502 }
503
504 #[test]
505 fn debug() {
506 assert_eq!(
507 format!("{:?}", Bandwidth { bits_per_second: 1 }),
508 "0.00 Kbps"
509 );
510 assert_eq!(
511 format!("{:?}", Bandwidth {
512 bits_per_second: 12
513 }),
514 "0.01 Kbps"
515 );
516 assert_eq!(
517 format!("{:?}", Bandwidth {
518 bits_per_second: 123
519 }),
520 "0.12 Kbps"
521 );
522 assert_eq!(
523 format!("{:?}", Bandwidth {
524 bits_per_second: 1234
525 }),
526 "1.23 Kbps"
527 );
528 assert_eq!(
529 format!("{:?}", Bandwidth {
530 bits_per_second: 12345
531 }),
532 "12.35 Kbps"
533 );
534 assert_eq!(
535 format!("{:?}", Bandwidth {
536 bits_per_second: 123456
537 }),
538 "123.46 Kbps"
539 );
540 assert_eq!(
541 format!("{:?}", Bandwidth {
542 bits_per_second: 1234567
543 }),
544 "1.23 Mbps"
545 );
546 assert_eq!(
547 format!("{:?}", Bandwidth {
548 bits_per_second: 12345678
549 }),
550 "12.35 Mbps"
551 );
552 assert_eq!(
553 format!("{:?}", Bandwidth {
554 bits_per_second: 123456789
555 }),
556 "123.46 Mbps"
557 );
558 assert_eq!(
559 format!("{:?}", Bandwidth {
560 bits_per_second: 1234567890
561 }),
562 "1.23 Gbps"
563 );
564 }
565}