net_bytes/
download_speed.rs1use std::fmt;
2use std::num::NonZeroU64;
3use std::time::Duration;
4
5use rust_decimal::Decimal;
6
7use crate::{SizeStandard, format_parts};
8
9#[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 #[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 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 #[inline]
84 pub fn as_decimal(&self) -> Decimal {
85 self.bytes_per_second
86 }
87
88 #[inline]
92 pub fn as_u64(&self) -> u64 {
93 self.bytes_per_second.floor().try_into().unwrap_or(0)
94 }
95
96 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 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}