net_bytes/
download_speed.rs

1use std::fmt;
2use std::num::NonZeroU64;
3use std::time::Duration;
4
5use rust_decimal::Decimal;
6
7use crate::{SizeStandard, format_parts};
8
9/// Download speed in bytes per second
10/// 
11/// 表示下载速度(单位:字节每秒)
12#[derive(Debug, Clone, Copy)]
13pub struct DownloadSpeed {
14    bytes_per_second: Decimal,
15    standard: SizeStandard,
16}
17
18impl PartialEq for DownloadSpeed {
19    #[inline]
20    fn eq(&self, other: &Self) -> bool {
21        self.bytes_per_second == other.bytes_per_second
22    }
23}
24
25impl PartialOrd for DownloadSpeed {
26    #[inline]
27    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
28        self.bytes_per_second.partial_cmp(&other.bytes_per_second)
29    }
30}
31
32impl DownloadSpeed {
33    /// Create a new download speed from raw bytes per second
34    /// 
35    /// # Parameters
36    /// - `bytes_per_second`: Non-zero speed in bytes per second
37    /// - `standard`: Standard to use (SI or IEC)
38    ///
39    /// 从原始字节/秒创建一个新的下载速度实例
40    ///
41    /// # 参数
42    /// - `bytes_per_second`: 非零的字节/秒速度
43    /// - `standard`: 使用的标准(SI 或 IEC)
44    #[inline]
45    pub fn from_raw(bytes_per_second: NonZeroU64, standard: SizeStandard) -> Self {
46        Self {
47            bytes_per_second: Decimal::from(bytes_per_second.get()),
48            standard,
49        }
50    }
51
52    /// Create a new download speed from bytes downloaded and time taken
53    /// 
54    /// # Parameters
55    /// - `bytes`: Non-zero number of bytes downloaded
56    /// - `duration`: Time taken for the download
57    /// - `standard`: Standard to use (SI or IEC)
58    ///
59    /// 从下载的字节数和所用时间创建一个新的下载速度实例
60    ///
61    /// # 参数
62    /// - `bytes`: 非零的下载字节数
63    /// - `duration`: 下载所用的时间
64    /// - `standard`: 使用的标准(SI 或 IEC)
65    pub fn new(bytes: NonZeroU64, duration: Duration, standard: SizeStandard) -> Self {
66        let seconds = Decimal::from(duration.as_secs())
67            + Decimal::from(duration.subsec_nanos()) / Decimal::from(1_000_000_000);
68        let bytes_per_second = if seconds.is_zero() {
69            Decimal::ZERO
70        } else {
71            Decimal::from(bytes.get()) / seconds
72        };
73
74        Self {
75            bytes_per_second,
76            standard,
77        }
78    }
79
80    /// Get the speed in bytes per second as a `Decimal`
81    /// 
82    /// 以 `Decimal` 的形式获取字节每秒
83    #[inline]
84    pub fn as_decimal(&self) -> Decimal {
85        self.bytes_per_second
86    }
87
88    /// Get the speed in bytes per second as `u64` (floored)
89    /// 
90    /// 以 `u64` 的形式获取字节每秒(向下取整)
91    #[inline]
92    pub fn as_u64(&self) -> u64 {
93        self.bytes_per_second.floor().try_into().unwrap_or(0)
94    }
95
96    /// Returns the formatted value and unit in SI (base-1000) standard
97    /// 
98    /// 返回 SI (base-1000) 标准的 (formatted_value, unit)
99    pub fn get_si_parts(&self) -> (String, &'static str) {
100        const UNITS: &[&str] = &[
101            "B/s", "KB/s", "MB/s", "GB/s", "TB/s", "PB/s", "EB/s", "ZB/s", "YB/s",
102        ];
103        format_parts(self.bytes_per_second, Decimal::from(1000), UNITS)
104    }
105
106    /// Returns the formatted value and unit in IEC (base-1024) standard
107    /// 
108    /// 返回 IEC (base-1024) 标准的 (formatted_value, unit)
109    pub fn get_iec_parts(&self) -> (String, &'static str) {
110        const UNITS: &[&str] = &[
111            "B/s", "KiB/s", "MiB/s", "GiB/s", "TiB/s", "PiB/s", "EiB/s", "ZiB/s", "YiB/s",
112        ];
113        format_parts(self.bytes_per_second, Decimal::from(1024), UNITS)
114    }
115}
116
117impl fmt::Display for DownloadSpeed {
118    #[inline]
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        let (value, unit) = match self.standard {
121            SizeStandard::SI => self.get_si_parts(),
122            SizeStandard::IEC => self.get_iec_parts(),
123        };
124        write!(f, "{} {}", value, unit)
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::DownloadSpeed;
131    use crate::SizeStandard;
132    use std::num::NonZeroU64;
133    use std::time::Duration;
134
135    #[test]
136    fn test_si_speed() {
137        let one_second = Duration::from_secs(1);
138
139        let speed = DownloadSpeed::from_raw(NonZeroU64::new(512).unwrap(), SizeStandard::SI);
140        assert_eq!(speed.to_string(), "512.0 B/s");
141
142        let speed =
143            DownloadSpeed::new(NonZeroU64::new(1000).unwrap(), one_second, SizeStandard::SI);
144        assert_eq!(speed.to_string(), "1.00 KB/s");
145
146        let speed =
147            DownloadSpeed::new(NonZeroU64::new(1024).unwrap(), one_second, SizeStandard::SI);
148        assert_eq!(speed.to_string(), "1.02 KB/s");
149
150        let speed =
151            DownloadSpeed::new(NonZeroU64::new(9999).unwrap(), one_second, SizeStandard::SI);
152        assert_eq!(speed.to_string(), "10.00 KB/s");
153
154        let speed = DownloadSpeed::new(
155            NonZeroU64::new(10_000).unwrap(),
156            one_second,
157            SizeStandard::SI,
158        );
159        assert_eq!(speed.to_string(), "10.0 KB/s");
160
161        let speed = DownloadSpeed::new(
162            NonZeroU64::new(100_000).unwrap(),
163            one_second,
164            SizeStandard::SI,
165        );
166        assert_eq!(speed.to_string(), "100.0 KB/s");
167    }
168
169    #[test]
170    fn test_iec_speed() {
171        let one_second = Duration::from_secs(1);
172
173        let speed = DownloadSpeed::from_raw(NonZeroU64::new(1024).unwrap(), SizeStandard::IEC);
174        assert_eq!(speed.to_string(), "1.00 KiB/s");
175
176        let speed = DownloadSpeed::new(
177            NonZeroU64::new(1500).unwrap(),
178            one_second,
179            SizeStandard::IEC,
180        );
181        assert_eq!(speed.to_string(), "1.46 KiB/s");
182
183        let bytes_near_10 = NonZeroU64::new((9.999_f64 * 1024_f64) as u64).unwrap();
184        let speed = DownloadSpeed::new(bytes_near_10, one_second, SizeStandard::IEC);
185        assert_eq!(speed.to_string(), "10.00 KiB/s");
186
187        let speed = DownloadSpeed::new(
188            NonZeroU64::new(10 * 1024).unwrap(),
189            one_second,
190            SizeStandard::IEC,
191        );
192        assert_eq!(speed.to_string(), "10.0 KiB/s");
193
194        let speed = DownloadSpeed::new(
195            NonZeroU64::new(100 * 1024).unwrap(),
196            one_second,
197            SizeStandard::IEC,
198        );
199        assert_eq!(speed.to_string(), "100.0 KiB/s");
200    }
201}