use std::time::Duration;
use crate::{FileSizeFormat, format_parts_scaled, SCALE};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct DownloadSpeed {
scaled_bps: u128,
}
impl DownloadSpeed {
#[inline]
pub fn from_raw(bytes_per_second: u64) -> Self {
Self {
scaled_bps: (bytes_per_second as u128) * SCALE,
}
}
pub fn new(bytes: u64, duration: Duration) -> Self {
let nanos = duration.as_nanos();
if nanos == 0 {
return Self { scaled_bps: 0 };
}
let scaled_bps = (bytes as u128) * SCALE * 1_000_000_000 / nanos;
Self { scaled_bps }
}
#[inline]
pub fn as_scaled(&self) -> u128 {
self.scaled_bps
}
#[inline]
pub fn as_u64(&self) -> u64 {
(self.scaled_bps / SCALE) as u64
}
#[inline]
pub fn as_f64(&self) -> f64 {
self.scaled_bps as f64 / SCALE as f64
}
}
impl FileSizeFormat for DownloadSpeed {
fn get_si_parts(&self) -> (String, &'static str) {
const UNITS: &[&str] = &[
"B/s", "KB/s", "MB/s", "GB/s", "TB/s", "PB/s", "EB/s", "ZB/s", "YB/s",
];
format_parts_scaled(self.scaled_bps, 1000, UNITS)
}
fn get_iec_parts(&self) -> (String, &'static str) {
const UNITS: &[&str] = &[
"B/s", "KiB/s", "MiB/s", "GiB/s", "TiB/s", "PiB/s", "EiB/s", "ZiB/s", "YiB/s",
];
format_parts_scaled(self.scaled_bps, 1024, UNITS)
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use super::DownloadSpeed;
use crate::{SizeStandard, FileSizeFormat};
fn format_test_si(bytes: u64) -> String {
DownloadSpeed::from_raw(bytes).to_formatted(SizeStandard::SI).to_string()
}
fn format_test_iec(bytes: u64) -> String {
DownloadSpeed::from_raw(bytes).to_formatted(SizeStandard::IEC).to_string()
}
#[test]
fn test_si_speed() {
assert_eq!(format_test_si(512), "512.0 B/s");
assert_eq!(format_test_si(1000), "1.00 KB/s");
assert_eq!(format_test_si(1024), "1.02 KB/s");
assert_eq!(format_test_si(9999), "10.00 KB/s");
assert_eq!(format_test_si(10_000), "10.0 KB/s");
assert_eq!(format_test_si(100_000), "100.0 KB/s");
}
#[test]
fn test_iec_speed() {
assert_eq!(format_test_iec(0), "0.00 B/s");
assert_eq!(format_test_iec(1024), "1.00 KiB/s");
assert_eq!(format_test_iec(1500), "1.46 KiB/s");
let bytes_near_10 = (9.999 * 1024.0) as u64;
assert_eq!(format_test_iec(bytes_near_10), "10.00 KiB/s");
assert_eq!(format_test_iec(10 * 1024), "10.0 KiB/s");
assert_eq!(format_test_iec(100 * 1024), "100.0 KiB/s");
}
#[test]
fn test_zero_speed() {
let zero_speed = DownloadSpeed::from_raw(0);
assert_eq!(zero_speed.as_u64(), 0);
assert_eq!(zero_speed.as_scaled(), 0);
let formatted = zero_speed.to_formatted(SizeStandard::SI).to_string();
assert_eq!(formatted, "0.00 B/s");
let zero_duration = Duration::from_secs(0);
let zero_speed = DownloadSpeed::new(1000, zero_duration);
assert_eq!(zero_speed.as_u64(), 0);
}
#[test]
fn test_new_basic() {
let speed = DownloadSpeed::new(1000, Duration::from_secs(1));
assert_eq!(speed.as_u64(), 1000);
let speed = DownloadSpeed::new(2000, Duration::from_secs(2));
assert_eq!(speed.as_u64(), 1000);
let speed = DownloadSpeed::new(1000, Duration::from_millis(500));
assert_eq!(speed.as_u64(), 2000);
}
#[test]
fn test_new_with_subsec_nanos() {
let speed = DownloadSpeed::new(1000, Duration::from_millis(1500));
assert_eq!(speed.as_u64(), 666);
let speed = DownloadSpeed::new(1000, Duration::from_millis(100));
assert_eq!(speed.as_u64(), 10000);
let speed = DownloadSpeed::new(1_000_000, Duration::new(1, 1));
assert!(speed.as_u64() >= 999_999); }
#[test]
fn test_new_zero_bytes() {
let speed = DownloadSpeed::new(0, Duration::from_secs(10));
assert_eq!(speed.as_u64(), 0);
assert_eq!(speed.as_scaled(), 0);
}
#[test]
fn test_new_zero_duration() {
let speed = DownloadSpeed::new(1000, Duration::ZERO);
assert_eq!(speed.as_u64(), 0);
assert_eq!(speed.as_scaled(), 0);
}
#[test]
fn test_new_large_values() {
let speed = DownloadSpeed::new(1_000_000_000, Duration::from_secs(1));
assert_eq!(speed.as_u64(), 1_000_000_000);
let speed = DownloadSpeed::new(10_000_000_000, Duration::from_secs(10));
assert_eq!(speed.as_u64(), 1_000_000_000);
}
#[test]
fn test_new_extreme_values() {
let speed = DownloadSpeed::new(1, Duration::from_secs(1));
assert_eq!(speed.as_u64(), 1);
let speed = DownloadSpeed::new(1, Duration::from_secs(100 * 365 * 24 * 60 * 60));
assert_eq!(speed.as_u64(), 0);
}
#[test]
fn test_new_edge_cases() {
let speed = DownloadSpeed::new(1, Duration::from_nanos(1));
assert_eq!(speed.as_u64(), 1_000_000_000);
let speed = DownloadSpeed::new(1, Duration::from_secs(1));
assert_eq!(speed.as_u64(), 1);
}
}