1mod parse;
31
32#[cfg(feature = "serde")]
33extern crate serde;
34#[cfg(feature = "serde")]
35use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
36#[cfg(feature = "serde")]
37use std::convert::TryFrom;
38
39use std::fmt::{self, Debug, Display, Formatter};
40use std::ops::{Add, AddAssign, Mul, MulAssign};
41
42pub const B: u64 = 1;
44pub const KB: u64 = 1_000;
46pub const MB: u64 = 1_000_000;
48pub const GB: u64 = 1_000_000_000;
50pub const TB: u64 = 1_000_000_000_000;
52pub const PB: u64 = 1_000_000_000_000_000;
54
55pub const KIB: u64 = 1_024;
57pub const MIB: u64 = 1_048_576;
59pub const GIB: u64 = 1_073_741_824;
61pub const TIB: u64 = 1_099_511_627_776;
63pub const PIB: u64 = 1_125_899_906_842_624;
65
66static UNITS: &str = "KMGTPE";
67static UNITS_SI: &str = "kMGTPE";
68static LN_KB: f64 = 6.931471806; static LN_KIB: f64 = 6.907755279; pub fn kb<V: Into<u64>>(size: V) -> u64 {
72 size.into() * KB
73}
74
75pub fn kib<V: Into<u64>>(size: V) -> u64 {
76 size.into() * KIB
77}
78
79pub fn mb<V: Into<u64>>(size: V) -> u64 {
80 size.into() * MB
81}
82
83pub fn mib<V: Into<u64>>(size: V) -> u64 {
84 size.into() * MIB
85}
86
87pub fn gb<V: Into<u64>>(size: V) -> u64 {
88 size.into() * GB
89}
90
91pub fn gib<V: Into<u64>>(size: V) -> u64 {
92 size.into() * GIB
93}
94
95pub fn tb<V: Into<u64>>(size: V) -> u64 {
96 size.into() * TB
97}
98
99pub fn tib<V: Into<u64>>(size: V) -> u64 {
100 size.into() * TIB
101}
102
103pub fn pb<V: Into<u64>>(size: V) -> u64 {
104 size.into() * PB
105}
106
107pub fn pib<V: Into<u64>>(size: V) -> u64 {
108 size.into() * PIB
109}
110
111#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
113pub struct ByteSize(pub u64);
114
115impl ByteSize {
116 #[inline(always)]
117 pub const fn b(size: u64) -> ByteSize {
118 ByteSize(size)
119 }
120
121 #[inline(always)]
122 pub const fn kb(size: u64) -> ByteSize {
123 ByteSize(size * KB)
124 }
125
126 #[inline(always)]
127 pub const fn kib(size: u64) -> ByteSize {
128 ByteSize(size * KIB)
129 }
130
131 #[inline(always)]
132 pub const fn mb(size: u64) -> ByteSize {
133 ByteSize(size * MB)
134 }
135
136 #[inline(always)]
137 pub const fn mib(size: u64) -> ByteSize {
138 ByteSize(size * MIB)
139 }
140
141 #[inline(always)]
142 pub const fn gb(size: u64) -> ByteSize {
143 ByteSize(size * GB)
144 }
145
146 #[inline(always)]
147 pub const fn gib(size: u64) -> ByteSize {
148 ByteSize(size * GIB)
149 }
150
151 #[inline(always)]
152 pub const fn tb(size: u64) -> ByteSize {
153 ByteSize(size * TB)
154 }
155
156 #[inline(always)]
157 pub const fn tib(size: u64) -> ByteSize {
158 ByteSize(size * TIB)
159 }
160
161 #[inline(always)]
162 pub const fn pb(size: u64) -> ByteSize {
163 ByteSize(size * PB)
164 }
165
166 #[inline(always)]
167 pub const fn pib(size: u64) -> ByteSize {
168 ByteSize(size * PIB)
169 }
170
171 #[inline(always)]
172 pub const fn as_u64(&self) -> u64 {
173 self.0
174 }
175
176 #[inline(always)]
177 pub fn to_string_as(&self, si_unit: bool) -> String {
178 to_string(self.0, si_unit)
179 }
180}
181
182pub fn to_string(bytes: u64, si_prefix: bool) -> String {
183 let unit = if si_prefix { KIB } else { KB };
184 let unit_base = if si_prefix { LN_KIB } else { LN_KB };
185 let unit_prefix = if si_prefix {
186 UNITS_SI.as_bytes()
187 } else {
188 UNITS.as_bytes()
189 };
190 let unit_suffix = if si_prefix { "iB" } else { "B" };
191
192 if bytes < unit {
193 format!("{} B", bytes)
194 } else {
195 let size = bytes as f64;
196 let exp = match (size.ln() / unit_base) as usize {
197 e if e == 0 => 1,
198 e => e,
199 };
200
201 format!(
202 "{:.1} {}{}",
203 (size / unit.pow(exp as u32) as f64),
204 unit_prefix[exp - 1] as char,
205 unit_suffix
206 )
207 }
208}
209
210impl Display for ByteSize {
211 fn fmt(&self, f: &mut Formatter) ->fmt::Result {
212 f.pad(&to_string(self.0, false))
213 }
214}
215
216impl Debug for ByteSize {
217 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
218 write!(f, "{}", self)
219 }
220}
221
222macro_rules! commutative_op {
223 ($t:ty) => {
224 impl Add<ByteSize> for $t {
225 type Output = ByteSize;
226 #[inline(always)]
227 fn add(self, rhs: ByteSize) -> ByteSize {
228 ByteSize(rhs.0 + (self as u64))
229 }
230 }
231
232 impl Mul<ByteSize> for $t {
233 type Output = ByteSize;
234 #[inline(always)]
235 fn mul(self, rhs: ByteSize) -> ByteSize {
236 ByteSize(rhs.0 * (self as u64))
237 }
238 }
239 };
240}
241
242commutative_op!(u64);
243commutative_op!(u32);
244commutative_op!(u16);
245commutative_op!(u8);
246
247impl Add<ByteSize> for ByteSize {
248 type Output = ByteSize;
249
250 #[inline(always)]
251 fn add(self, rhs: ByteSize) -> ByteSize {
252 ByteSize(self.0 + rhs.0)
253 }
254}
255
256impl AddAssign<ByteSize> for ByteSize {
257 #[inline(always)]
258 fn add_assign(&mut self, rhs: ByteSize) {
259 self.0 += rhs.0
260 }
261}
262
263impl<T> Add<T> for ByteSize
264 where T: Into<u64> {
265 type Output = ByteSize;
266 #[inline(always)]
267 fn add(self, rhs: T) -> ByteSize {
268 ByteSize(self.0 + (rhs.into() as u64))
269 }
270}
271
272impl<T> AddAssign<T> for ByteSize
273 where T: Into<u64> {
274 #[inline(always)]
275 fn add_assign(&mut self, rhs: T) {
276 self.0 += rhs.into() as u64;
277 }
278}
279
280impl<T> Mul<T> for ByteSize
281 where T: Into<u64> {
282 type Output = ByteSize;
283 #[inline(always)]
284 fn mul(self, rhs: T) -> ByteSize {
285 ByteSize(self.0 * (rhs.into() as u64))
286 }
287}
288
289impl<T> MulAssign<T> for ByteSize
290 where T: Into<u64> {
291 #[inline(always)]
292 fn mul_assign(&mut self, rhs: T) {
293 self.0 *= rhs.into() as u64;
294 }
295}
296
297#[cfg(feature = "serde")]
298impl<'de> Deserialize<'de> for ByteSize {
299 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
300 where
301 D: Deserializer<'de>,
302 {
303 struct ByteSizeVistor;
304
305 impl<'de> de::Visitor<'de> for ByteSizeVistor {
306 type Value = ByteSize;
307
308 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
309 formatter.write_str("an integer or string")
310 }
311
312 fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
313 if let Ok(val) = u64::try_from(value) {
314 Ok(ByteSize(val))
315 } else {
316 Err(E::invalid_value(
317 de::Unexpected::Signed(value),
318 &"integer overflow",
319 ))
320 }
321 }
322
323 fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
324 Ok(ByteSize(value))
325 }
326
327 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
328 if let Ok(val) = value.parse() {
329 Ok(val)
330 } else {
331 Err(E::invalid_value(
332 de::Unexpected::Str(value),
333 &"parsable string",
334 ))
335 }
336 }
337 }
338
339 if deserializer.is_human_readable() {
340 deserializer.deserialize_any(ByteSizeVistor)
341 } else {
342 deserializer.deserialize_u64(ByteSizeVistor)
343 }
344 }
345}
346
347#[cfg(feature = "serde")]
348impl Serialize for ByteSize {
349 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
350 where
351 S: Serializer,
352 {
353 if serializer.is_human_readable() {
354 <str>::serialize(self.to_string().as_str(), serializer)
355 } else {
356 self.0.serialize(serializer)
357 }
358 }
359}
360
361#[cfg(test)]
362mod tests {
363 use super::*;
364
365 #[test]
366 fn test_arithmetic_op() {
367 let mut x = ByteSize::mb(1);
368 let y = ByteSize::kb(100);
369
370 assert_eq!((x + y).as_u64(), 1_100_000u64);
371
372 assert_eq!((x + (100 * 1000) as u64).as_u64(), 1_100_000);
373
374 assert_eq!((x * 2u64).as_u64(), 2_000_000);
375
376 x += y;
377 assert_eq!(x.as_u64(), 1_100_000);
378 x *= 2u64;
379 assert_eq!(x.as_u64(), 2_200_000);
380 }
381
382 #[test]
383 fn test_arithmetic_primitives() {
384 let mut x = ByteSize::mb(1);
385
386 assert_eq!((x + MB as u64).as_u64(), 2_000_000);
387
388 assert_eq!((x + MB as u32).as_u64(), 2_000_000);
389
390 assert_eq!((x + KB as u16).as_u64(), 1_001_000);
391
392 assert_eq!((x + B as u8).as_u64(), 1_000_001);
393
394 x += MB as u64;
395 x += MB as u32;
396 x += 10u16;
397 x += 1u8;
398 assert_eq!(x.as_u64(), 3_000_011);
399 }
400
401 #[test]
402 fn test_comparison() {
403 assert!(ByteSize::mb(1) == ByteSize::kb(1000));
404 assert!(ByteSize::mib(1) == ByteSize::kib(1024));
405 assert!(ByteSize::mb(1) != ByteSize::kib(1024));
406 assert!(ByteSize::mb(1) < ByteSize::kib(1024));
407 assert!(ByteSize::b(0) < ByteSize::tib(1));
408 }
409
410 fn assert_display(expected: &str, b: ByteSize) {
411 assert_eq!(expected, format!("{}", b));
412 }
413
414 #[test]
415 fn test_display() {
416 assert_display("215 B", ByteSize::b(215));
417 assert_display("1.0 KB", ByteSize::kb(1));
418 assert_display("301.0 KB", ByteSize::kb(301));
419 assert_display("419.0 MB", ByteSize::mb(419));
420 assert_display("518.0 GB", ByteSize::gb(518));
421 assert_display("815.0 TB", ByteSize::tb(815));
422 assert_display("609.0 PB", ByteSize::pb(609));
423 }
424
425 #[test]
426 fn test_display_alignment() {
427 assert_eq!("|357 B |", format!("|{:10}|", ByteSize(357)));
428 assert_eq!("| 357 B|", format!("|{:>10}|", ByteSize(357)));
429 assert_eq!("|357 B |", format!("|{:<10}|", ByteSize(357)));
430 assert_eq!("| 357 B |", format!("|{:^10}|", ByteSize(357)));
431
432 assert_eq!("|-----357 B|", format!("|{:->10}|", ByteSize(357)));
433 assert_eq!("|357 B-----|", format!("|{:-<10}|", ByteSize(357)));
434 assert_eq!("|--357 B---|", format!("|{:-^10}|", ByteSize(357)));
435 }
436
437 fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
438 assert_eq!(expected.to_string(), b.to_string_as(si));
439 }
440
441 #[test]
442 fn test_to_string_as() {
443 assert_to_string("215 B", ByteSize::b(215), true);
444 assert_to_string("215 B", ByteSize::b(215), false);
445
446 assert_to_string("1.0 kiB", ByteSize::kib(1), true);
447 assert_to_string("1.0 KB", ByteSize::kib(1), false);
448
449 assert_to_string("293.9 kiB", ByteSize::kb(301), true);
450 assert_to_string("301.0 KB", ByteSize::kb(301), false);
451
452 assert_to_string("1.0 MiB", ByteSize::mib(1), true);
453 assert_to_string("1048.6 KB", ByteSize::mib(1), false);
454
455 assert_to_string("1.9 GiB", ByteSize::mib(1907), true);
457 assert_to_string("2.0 GB", ByteSize::mib(1908), false);
458
459 assert_to_string("399.6 MiB", ByteSize::mb(419), true);
460 assert_to_string("419.0 MB", ByteSize::mb(419), false);
461
462 assert_to_string("482.4 GiB", ByteSize::gb(518), true);
463 assert_to_string("518.0 GB", ByteSize::gb(518), false);
464
465 assert_to_string("741.2 TiB", ByteSize::tb(815), true);
466 assert_to_string("815.0 TB", ByteSize::tb(815), false);
467
468 assert_to_string("540.9 PiB", ByteSize::pb(609), true);
469 assert_to_string("609.0 PB", ByteSize::pb(609), false);
470 }
471
472 #[test]
473 fn test_default() {
474 assert_eq!(ByteSize::b(0), ByteSize::default());
475 }
476
477 #[test]
478 fn test_to_string() {
479 assert_to_string("609.0 PB", ByteSize::pb(609), false);
480 }
481
482 #[cfg(feature = "serde")]
483 #[test]
484 fn test_serde() {
485 #[derive(Serialize, Deserialize)]
486 struct S {
487 x: ByteSize,
488 }
489
490 let s: S = serde_json::from_str(r#"{ "x": "5 B" }"#).unwrap();
491 assert_eq!(s.x, ByteSize(5));
492
493 let s: S = serde_json::from_str(r#"{ "x": 1048576 }"#).unwrap();
494 assert_eq!(s.x, "1 MiB".parse::<ByteSize>().unwrap());
495
496 let s: S = toml::from_str(r#"x = "2.5 MiB""#).unwrap();
497 assert_eq!(s.x, "2.5 MiB".parse::<ByteSize>().unwrap());
498
499 let s: S = toml::from_str(r#"x = "9223372036854775807""#).unwrap();
501 assert_eq!(s.x, "9223372036854775807".parse::<ByteSize>().unwrap());
502 }
503}