size_display/
lib.rs

1//! Display human readable file sizes.
2//!
3//! # Limitation
4//!
5//! Displayed units go up to Exabyte (2^60).
6//!
7//! # Example
8//!
9//! ```
10//! use size_display::Size;
11//!
12//! assert_eq!("24", format!("{}", Size(24)));
13//! assert_eq!("4.2G", format!("{:.1}", Size(4509715660)));
14//! ```
15
16use std::fmt;
17
18pub const KILO: u64 = 1024;
19pub const MEGA: u64 = KILO * KILO;
20pub const GIGA: u64 = MEGA * KILO;
21pub const TERA: u64 = GIGA * KILO;
22pub const PETA: u64 = TERA * KILO;
23pub const EXA: u64 = PETA * KILO;
24
25/// File size type with human-readable [`Display`].
26///
27/// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
28pub struct Size(pub u64);
29
30impl fmt::Debug for Size {
31    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32        <Self as fmt::Display>::fmt(self, f)
33    }
34}
35
36impl fmt::Display for Size {
37    #[inline]
38    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39        let bytes = self.0;
40
41        let (unit, char) = match bytes {
42            e if e >= EXA => (EXA, "E"),
43            p if p >= PETA => (PETA, "P"),
44            t if t >= TERA => (TERA, "T"),
45            g if g >= GIGA => (GIGA, "G"),
46            m if m >= MEGA => (MEGA, "M"),
47            k if k >= KILO => (KILO, "K"),
48            _ => (1, ""),
49        };
50
51        match bytes % unit {
52            0 => <u64 as fmt::Display>::fmt(&(bytes / unit), f),
53            _ => <f64 as fmt::Display>::fmt(&(bytes as f64 / unit as f64), f),
54        }?;
55
56        if char != "" {
57            write!(f, "{}", char)?;
58        }
59
60        Ok(())
61    }
62}