1use std::fmt;
2use std::iter::Sum;
3use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
4use std::time::Duration;
5
6#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
11pub struct Bitrate(f64);
12
13impl Bitrate {
14 pub const ZERO: Self = Self::bps(0);
16 pub const MAX: Self = Self::bps(u64::MAX);
18 pub const INFINITY: Self = Self(f64::INFINITY);
20 pub const NEG_INFINITY: Self = Self(f64::NEG_INFINITY);
22
23 pub const fn bps(bps: u64) -> Self {
25 Bitrate(bps as f64)
26 }
27
28 pub const fn kbps(kbps: u64) -> Self {
30 Self::bps(kbps * 10_u64.pow(3))
31 }
32
33 pub const fn mbps(mbps: u64) -> Self {
35 Self::bps(mbps * 10_u64.pow(6))
36 }
37
38 pub const fn gbps(gbps: u64) -> Self {
40 Self::bps(gbps * 10_u64.pow(9))
41 }
42
43 pub fn as_f64(&self) -> f64 {
45 self.0
46 }
47
48 pub fn as_u64(&self) -> u64 {
50 self.0.ceil() as u64
51 }
52
53 pub fn clamp(&self, min: Self, max: Self) -> Self {
55 Self(self.0.clamp(min.0, max.0))
56 }
57
58 pub fn min(&self, other: Self) -> Self {
60 Self(self.0.min(other.0))
61 }
62
63 pub fn max(&self, other: Self) -> Self {
65 Self(self.0.max(other.0))
66 }
67
68 pub fn is_valid(&self) -> bool {
70 self.0.is_finite()
71 }
72
73 pub fn as_valid(&self) -> Option<Bitrate> {
75 self.is_valid().then_some(*self)
76 }
77
78 pub fn is_zero(&self) -> bool {
80 *self == Bitrate::ZERO
81 }
82}
83
84impl From<u64> for Bitrate {
85 fn from(value: u64) -> Self {
86 Self::bps(value)
87 }
88}
89
90impl From<f64> for Bitrate {
91 fn from(value: f64) -> Self {
92 Self(value)
93 }
94}
95
96impl Mul<Duration> for Bitrate {
97 type Output = DataSize;
98
99 fn mul(self, rhs: Duration) -> Self::Output {
100 let bits = self.0 * rhs.as_secs_f64();
101 let bytes = bits / 8.0;
102
103 DataSize::bytes(bytes.round() as i64)
104 }
105}
106
107impl Mul<f64> for Bitrate {
108 type Output = Bitrate;
109
110 fn mul(self, rhs: f64) -> Self::Output {
111 Bitrate(self.0 * rhs)
112 }
113}
114
115impl Sub<Bitrate> for Bitrate {
116 type Output = Bitrate;
117
118 fn sub(self, rhs: Bitrate) -> Self::Output {
119 assert!(
120 self.0 >= rhs.0,
121 "Attempted to subtract Bitrates that would result in overflow. lhs={}, rhs={}",
122 self,
123 rhs
124 );
125
126 Self(self.0 - rhs.0)
127 }
128}
129
130impl Add<Bitrate> for Bitrate {
131 type Output = Bitrate;
132
133 fn add(self, rhs: Bitrate) -> Self::Output {
134 Self(self.0 + rhs.0)
135 }
136}
137
138impl fmt::Display for Bitrate {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 let rate = self.0;
141 let log = rate.log10().floor() as u64;
142
143 match log {
144 0..=2 => write!(f, "{rate}bit/s"),
145 3..=5 => write!(f, "{:.3}kbit/s", rate / 10.0_f64.powf(3.0)),
146 6..=8 => write!(f, "{:.3}Mbit/s", rate / 10.0_f64.powf(6.0)),
147 9..=11 => write!(f, "{:.3}Gbit/s", rate / 10.0_f64.powf(9.0)),
148 12.. => write!(f, "{:.3}Tbit/s", rate / 10.0_f64.powf(12.0)),
149 }
150 }
151}
152
153#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
155pub struct DataSize(i64);
156
157impl DataSize {
158 pub const ZERO: Self = DataSize::bytes(0);
160
161 pub const fn bytes(bytes: i64) -> DataSize {
163 Self(bytes)
164 }
165
166 pub const fn kbytes(kbytes: i64) -> DataSize {
168 Self(kbytes * 1024)
169 }
170
171 pub const fn mbytes(mbytes: i64) -> DataSize {
173 Self(mbytes * 1024 * 1024)
174 }
175
176 pub const fn gbytes(gbytes: i64) -> DataSize {
178 Self(gbytes * 1024 * 1024 * 1024)
179 }
180
181 pub fn as_bytes_f64(&self) -> f64 {
183 self.0 as f64
184 }
185
186 pub fn as_bytes_usize(&self) -> usize {
188 self.0
189 .try_into()
190 .expect("DataSize i64 value must fit in usize")
191 }
192
193 pub fn as_bytes_i64(&self) -> i64 {
195 self.0
196 }
197
198 pub fn saturating_sub(self, rhs: Self) -> Self {
200 Self((self.0 - rhs.0).max(0))
201 }
202
203 pub fn as_kb(&self) -> f64 {
205 self.0 as f64 / 1000.0
206 }
207}
208
209impl From<usize> for DataSize {
210 fn from(value: usize) -> Self {
211 Self(value as i64)
212 }
213}
214
215impl From<u8> for DataSize {
216 fn from(value: u8) -> Self {
217 Self(value as i64)
218 }
219}
220
221impl Div<Duration> for DataSize {
222 type Output = Bitrate;
223
224 fn div(self, rhs: Duration) -> Self::Output {
225 let bytes = self.as_bytes_f64();
226 let s = rhs.as_secs_f64();
227
228 if s == 0.0 {
229 return Bitrate::ZERO;
230 }
231
232 let bps = (bytes * 8.0) / s;
233
234 bps.into()
235 }
236}
237
238impl Div<Bitrate> for DataSize {
239 type Output = Duration;
240
241 fn div(self, rhs: Bitrate) -> Self::Output {
242 let bits = self.as_bytes_f64() * 8.0;
243 let rhs = rhs.as_f64();
244
245 if rhs == 0.0 {
246 return Duration::ZERO;
247 }
248
249 let seconds = bits / rhs;
250
251 Duration::from_secs_f64(seconds)
252 }
253}
254
255impl Mul<i64> for DataSize {
256 type Output = i64;
257
258 fn mul(self, rhs: i64) -> Self::Output {
259 self.as_bytes_i64() * rhs
260 }
261}
262
263impl Div<f64> for Bitrate {
264 type Output = Bitrate;
265
266 fn div(self, rhs: f64) -> Self::Output {
267 if rhs == 0.0 {
268 return Self::ZERO;
269 }
270
271 Self(self.0 / rhs)
272 }
273}
274
275impl Mul<u64> for DataSize {
276 type Output = DataSize;
277
278 fn mul(self, rhs: u64) -> Self::Output {
279 Self(self.0 * rhs as i64)
280 }
281}
282
283impl AddAssign<DataSize> for DataSize {
284 fn add_assign(&mut self, rhs: DataSize) {
285 self.0 += rhs.0;
286 }
287}
288
289impl Sub<DataSize> for DataSize {
290 type Output = DataSize;
291
292 fn sub(self, rhs: DataSize) -> Self::Output {
293 Self(self.0 - rhs.0)
294 }
295}
296
297impl SubAssign<DataSize> for DataSize {
298 fn sub_assign(&mut self, rhs: DataSize) {
299 self.0 -= rhs.0;
300 }
301}
302
303impl Add<DataSize> for DataSize {
304 type Output = DataSize;
305
306 fn add(self, rhs: DataSize) -> Self::Output {
307 Self(self.0 + rhs.0)
308 }
309}
310
311impl Sum<DataSize> for DataSize {
312 fn sum<I: Iterator<Item = DataSize>>(iter: I) -> Self {
313 iter.fold(DataSize::ZERO, |acc, s| acc + s)
314 }
315}
316
317impl fmt::Display for DataSize {
318 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319 let size = self.0 as f64;
320 let log = (size as u64).ilog10();
321
322 match log {
323 0..=2 => write!(f, "{size}B"),
324 3..=5 => write!(f, "{:.3}kB", size / 10.0_f64.powf(3.0)),
325 6..=8 => write!(f, "{:.3}MB", size / 10.0_f64.powf(6.0)),
326 9..=11 => write!(f, "{:.3}GB", size / 10.0_f64.powf(9.0)),
327 12.. => write!(f, "{:.3}TB", size / 10.0_f64.powf(12.0)),
328 }
329 }
330}
331
332#[cfg(test)]
333mod test {
334 use std::time::Duration;
335
336 use super::{Bitrate, DataSize};
337
338 #[test]
339 fn test_bitrate_display() {
340 let rate = Bitrate::bps(1);
341 assert_eq!(rate.to_string(), "1bit/s");
342
343 let rate = Bitrate::bps(12);
344 assert_eq!(rate.to_string(), "12bit/s");
345
346 let rate = Bitrate::bps(123);
347 assert_eq!(rate.to_string(), "123bit/s");
348
349 let rate = Bitrate::bps(1234);
350 assert_eq!(rate.to_string(), "1.234kbit/s");
351
352 let rate = Bitrate::bps(12345);
353 assert_eq!(rate.to_string(), "12.345kbit/s");
354
355 let rate = Bitrate::bps(123456);
356 assert_eq!(rate.to_string(), "123.456kbit/s");
357
358 let rate = Bitrate::bps(1234567);
359 assert_eq!(rate.to_string(), "1.235Mbit/s");
360
361 let rate = Bitrate::bps(12345678);
362 assert_eq!(rate.to_string(), "12.346Mbit/s");
363
364 let rate = Bitrate::bps(123456789);
365 assert_eq!(rate.to_string(), "123.457Mbit/s");
366
367 let rate = Bitrate::bps(1234567898);
368 assert_eq!(rate.to_string(), "1.235Gbit/s");
369
370 let rate = Bitrate::bps(12345678987);
371 assert_eq!(rate.to_string(), "12.346Gbit/s");
372
373 let rate = Bitrate::bps(123456789876);
374 assert_eq!(rate.to_string(), "123.457Gbit/s");
375
376 let rate = Bitrate::bps(1234567898765);
377 assert_eq!(rate.to_string(), "1.235Tbit/s");
378 }
379
380 #[test]
381 fn test_data_size_div_duration() {
382 let size = DataSize::bytes(2_500_000);
383 let rate = size / Duration::from_secs(1);
384
385 assert_eq!(rate.as_u64(), 20_000_000);
386 }
387
388 #[test]
389 fn test_data_size_div_bitrate() {
390 let size = DataSize::bytes(12_500);
391 let rate = Bitrate::kbps(2_500);
392 let duration = size / rate;
393
394 assert_eq!(duration.as_millis(), 40);
395 }
396
397 #[test]
398 fn test_bitrate_div_f64() {
399 let rate = Bitrate::kbps(2_500);
400 let new_rate = rate / 2.0;
401
402 assert_eq!(new_rate, Bitrate::kbps(1250));
403 }
404
405 #[test]
406 fn test_datasize_negative() {
407 let size = DataSize::bytes(-100);
408 assert_eq!(size.as_bytes_i64(), -100);
409
410 let size_kb = DataSize::kbytes(-5);
412 assert_eq!(size_kb.as_bytes_i64(), -5 * 1024);
413
414 let positive = DataSize::bytes(50);
416 let negative = DataSize::bytes(-50);
417 assert!(negative < positive);
418 assert!(negative < DataSize::ZERO);
419 }
420
421 #[test]
422 fn test_datasize_mul_negative() {
423 let size = DataSize::bytes(100);
424
425 let negated = size * -1i64;
427 assert_eq!(negated, -100);
428
429 let doubled_neg = size * -2i64;
431 assert_eq!(doubled_neg, -200);
432
433 let negative_size = DataSize::bytes(-50);
435 let positive_result = negative_size * -1i64;
436 assert_eq!(positive_result, 50);
437 }
438
439 #[test]
440 fn test_datasize_arithmetic_with_negatives() {
441 let positive = DataSize::bytes(100);
442 let negative = DataSize::bytes(-50);
443
444 let result = positive + negative;
446 assert_eq!(result.as_bytes_i64(), 50);
447
448 let result2 = positive - negative;
450 assert_eq!(result2.as_bytes_i64(), 150);
451 }
452}