net_bytes/
download_speed.rs

1use std::time::Duration;
2
3use rust_decimal::Decimal;
4
5use crate::{FileSizeFormat, format_parts};
6
7/// Download speed in bytes per second
8///
9/// 表示下载速度(单位:字节每秒)
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
11pub struct DownloadSpeed {
12    bytes_per_second: Decimal,
13}
14
15impl DownloadSpeed {
16    /// Create a new download speed from raw bytes per second
17    ///
18    /// # Parameters
19    /// - `bytes_per_second`: Speed in bytes per second (can be zero)
20    ///
21    /// 从原始字节/秒创建一个新的下载速度实例
22    ///
23    /// # 参数
24    /// - `bytes_per_second`: 字节/秒速度(可以为零)
25    #[inline]
26    pub fn from_raw(bytes_per_second: u64) -> Self {
27        Self {
28            bytes_per_second: Decimal::from(bytes_per_second),
29        }
30    }
31
32    /// Create a new download speed from bytes downloaded and time taken
33    ///
34    /// # Parameters
35    /// - `bytes`: Number of bytes downloaded (can be zero)
36    /// - `duration`: Time taken for the download
37    ///
38    /// 从下载的字节数和所用时间创建一个新的下载速度实例
39    ///
40    /// # 参数
41    /// - `bytes`: 下载的字节数(可以为零)
42    /// - `duration`: 下载所用的时间
43    pub fn new(bytes: u64, duration: Duration) -> Self {
44        let seconds = Decimal::from(duration.as_secs())
45            + Decimal::from(duration.subsec_nanos()) / Decimal::from(1_000_000_000);
46        let bytes_per_second = if seconds.is_zero() {
47            Decimal::ZERO
48        } else {
49            Decimal::from(bytes) / seconds
50        };
51
52        Self { bytes_per_second }
53    }
54
55    /// Get the speed in bytes per second as a `Decimal`
56    ///
57    /// 以 `Decimal` 的形式获取字节每秒
58    #[inline]
59    pub fn as_decimal(&self) -> Decimal {
60        self.bytes_per_second
61    }
62
63    /// Get the speed in bytes per second as `u64` (floored)
64    ///
65    /// 以 `u64` 的形式获取字节每秒(向下取整)
66    #[inline]
67    pub fn as_u64(&self) -> u64 {
68        self.bytes_per_second.floor().try_into().unwrap_or(0)
69    }
70}
71
72impl FileSizeFormat for DownloadSpeed {
73    /// Returns the formatted value and unit in SI (base-1000) standard
74    ///
75    /// 返回 SI (base-1000) 标准的 (formatted_value, unit)
76    fn get_si_parts(&self) -> (String, &'static str) {
77        const UNITS: &[&str] = &[
78            "B/s", "KB/s", "MB/s", "GB/s", "TB/s", "PB/s", "EB/s", "ZB/s", "YB/s",
79        ];
80        format_parts(self.bytes_per_second, Decimal::from(1000), UNITS)
81    }
82
83    /// Returns the formatted value and unit in IEC (base-1024) standard
84    ///
85    /// 返回 IEC (base-1024) 标准的 (formatted_value, unit)
86    fn get_iec_parts(&self) -> (String, &'static str) {
87        const UNITS: &[&str] = &[
88            "B/s", "KiB/s", "MiB/s", "GiB/s", "TiB/s", "PiB/s", "EiB/s", "ZiB/s", "YiB/s",
89        ];
90        format_parts(self.bytes_per_second, Decimal::from(1024), UNITS)
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use std::time::Duration;
97
98    use rust_decimal::Decimal;
99
100    use super::DownloadSpeed;
101    use crate::{SizeStandard, FileSizeFormat};
102
103    /// Helper function - SI standard
104    ///
105    /// 辅助函数 - SI 标准
106    fn format_test_si(bytes: u64) -> String {
107        DownloadSpeed::from_raw(bytes).to_formatted(SizeStandard::SI).to_string()
108    }
109
110    /// Helper function - IEC standard
111    ///
112    /// 辅助函数 - IEC 标准
113    fn format_test_iec(bytes: u64) -> String {
114        DownloadSpeed::from_raw(bytes).to_formatted(SizeStandard::IEC).to_string()
115    }
116
117    // --- Tests for SI (base-1000) standard ---
118    // --- SI (base-1000) 测试 ---
119    #[test]
120    fn test_si_speed() {
121        assert_eq!(format_test_si(512), "512.0 B/s");
122        assert_eq!(format_test_si(1000), "1.00 KB/s");
123        assert_eq!(format_test_si(1024), "1.02 KB/s");
124        assert_eq!(format_test_si(9999), "10.00 KB/s");
125        assert_eq!(format_test_si(10_000), "10.0 KB/s");
126        assert_eq!(format_test_si(100_000), "100.0 KB/s");
127    }
128
129    // --- Tests for IEC (base-1024) standard ---
130    // --- IEC (base-1024) 测试 ---
131    #[test]
132    fn test_iec_speed() {
133        assert_eq!(format_test_iec(0), "0.00 B/s");
134        assert_eq!(format_test_iec(1024), "1.00 KiB/s");
135        assert_eq!(format_test_iec(1500), "1.46 KiB/s");
136
137        let bytes_near_10 = (9.999 * 1024.0) as u64;
138        assert_eq!(format_test_iec(bytes_near_10), "10.00 KiB/s");
139
140        assert_eq!(format_test_iec(10 * 1024), "10.0 KiB/s");
141        assert_eq!(format_test_iec(100 * 1024), "100.0 KiB/s");
142    }
143
144    #[test]
145    fn test_zero_speed() {
146        let zero_speed = DownloadSpeed::from_raw(0);
147        assert_eq!(zero_speed.as_u64(), 0);
148        assert_eq!(zero_speed.as_decimal(), Decimal::ZERO);
149
150        let formatted = zero_speed.to_formatted(SizeStandard::SI).to_string();
151        assert_eq!(formatted, "0.00 B/s");
152
153        let zero_duration = Duration::from_secs(0);
154        let zero_speed = DownloadSpeed::new(1000, zero_duration);
155        assert_eq!(zero_speed.as_u64(), 0);
156    }
157}