diff options
Diffstat (limited to 'vendor/bytesize/src')
-rw-r--r-- | vendor/bytesize/src/lib.rs | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/vendor/bytesize/src/lib.rs b/vendor/bytesize/src/lib.rs new file mode 100644 index 000000000..e2d63c9c5 --- /dev/null +++ b/vendor/bytesize/src/lib.rs @@ -0,0 +1,377 @@ +//! ByteSize is an utility that easily makes bytes size representation +//! and helps its arithmetic operations. +//! +//! ## Example +//! +//! ```ignore +//! extern crate bytesize; +//! +//! use bytesize::ByteSize; +//! +//! fn byte_arithmetic_operator() { +//! let x = ByteSize::mb(1); +//! let y = ByteSize::kb(100); +//! +//! let plus = x + y; +//! print!("{} bytes", plus.as_u64()); +//! +//! let minus = ByteSize::tb(100) - ByteSize::gb(4); +//! print!("{} bytes", minus.as_u64()); +//! } +//! ``` +//! +//! It also provides its human readable string as follows: +//! +//! ```ignore= +//! assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true)); +//! assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false)); +//! ``` + +#[cfg(feature = "serde")] +#[macro_use] +extern crate serde; + +use std::fmt::{Debug, Display, Formatter, Result}; +use std::ops::{Add, Mul}; + +/// byte size for 1 byte +pub const B: u64 = 1; +/// bytes size for 1 kilobyte +pub const KB: u64 = 1_000; +/// bytes size for 1 megabyte +pub const MB: u64 = 1_000_000; +/// bytes size for 1 gigabyte +pub const GB: u64 = 1_000_000_000; +/// bytes size for 1 terabyte +pub const TB: u64 = 1_000_000_000_000; +/// bytes size for 1 petabyte +pub const PB: u64 = 1_000_000_000_000_000; + +/// bytes size for 1 kibibyte +pub const KIB: u64 = 1_024; +/// bytes size for 1 mebibyte +pub const MIB: u64 = 1_048_576; +/// bytes size for 1 gibibyte +pub const GIB: u64 = 1_073_741_824; +/// bytes size for 1 tebibyte +pub const TIB: u64 = 1_099_511_627_776; +/// bytes size for 1 pebibyte +pub const PIB: u64 = 1_125_899_906_842_624; + +static UNITS: &'static str = "KMGTPE"; +static UNITS_SI: &'static str = "kMGTPE"; +static LN_KB: f64 = 6.931471806; // ln 1024 +static LN_KIB: f64 = 6.907755279; // ln 1000 + +pub fn kb<V: Into<u64>>(size: V) -> u64 { + size.into() * KB +} + +pub fn kib<V: Into<u64>>(size: V) -> u64 { + size.into() * KIB +} + +pub fn mb<V: Into<u64>>(size: V) -> u64 { + size.into() * MB +} + +pub fn mib<V: Into<u64>>(size: V) -> u64 { + size.into() * MIB +} + +pub fn gb<V: Into<u64>>(size: V) -> u64 { + size.into() * GB +} + +pub fn gib<V: Into<u64>>(size: V) -> u64 { + size.into() * GIB +} + +pub fn tb<V: Into<u64>>(size: V) -> u64 { + size.into() * TB +} + +pub fn tib<V: Into<u64>>(size: V) -> u64 { + size.into() * TIB +} + +pub fn pb<V: Into<u64>>(size: V) -> u64 { + size.into() * PB +} + +pub fn pib<V: Into<u64>>(size: V) -> u64 { + size.into() * PIB +} + +/// Byte size representation +#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ByteSize(pub u64); + +impl ByteSize { + #[inline(always)] + pub fn b(size: u64) -> ByteSize { + ByteSize(size) + } + + #[inline(always)] + pub fn kb(size: u64) -> ByteSize { + ByteSize(size * KB) + } + + #[inline(always)] + pub fn kib(size: u64) -> ByteSize { + ByteSize(size * KIB) + } + + #[inline(always)] + pub fn mb(size: u64) -> ByteSize { + ByteSize(size * MB) + } + + #[inline(always)] + pub fn mib(size: u64) -> ByteSize { + ByteSize(size * MIB) + } + + #[inline(always)] + pub fn gb(size: u64) -> ByteSize { + ByteSize(size * GB) + } + + #[inline(always)] + pub fn gib(size: u64) -> ByteSize { + ByteSize(size * GIB) + } + + #[inline(always)] + pub fn tb(size: u64) -> ByteSize { + ByteSize(size * TB) + } + + #[inline(always)] + pub fn tib(size: u64) -> ByteSize { + ByteSize(size * TIB) + } + + #[inline(always)] + pub fn pb(size: u64) -> ByteSize { + ByteSize(size * PB) + } + + #[inline(always)] + pub fn pib(size: u64) -> ByteSize { + ByteSize(size * PIB) + } + + #[inline(always)] + pub fn as_u64(&self) -> u64 { + self.0 + } + + #[inline(always)] + pub fn to_string_as(&self, si_unit: bool) -> String { + to_string(self.0, si_unit) + } +} + +pub fn to_string(bytes: u64, si_prefix: bool) -> String { + let unit = if si_prefix { KIB } else { KB }; + let unit_base = if si_prefix { LN_KIB } else { LN_KB }; + let unit_prefix = if si_prefix { + UNITS_SI.as_bytes() + } else { + UNITS.as_bytes() + }; + let unit_suffix = if si_prefix { "iB" } else { "B" }; + + if bytes < unit { + format!("{} B", bytes) + } else { + let size = bytes as f64; + let exp = match (size.ln() / unit_base) as usize { + e if e == 0 => 1, + e => e, + }; + + format!( + "{:.1} {}{}", + (size / unit.pow(exp as u32) as f64), + unit_prefix[exp - 1] as char, + unit_suffix + ) + } +} + +impl Display for ByteSize { + fn fmt(&self, f: &mut Formatter) -> Result { + f.pad(&to_string(self.0, false)) + } +} + +impl Debug for ByteSize { + fn fmt(&self, f: &mut Formatter) -> Result { + write!(f, "{}", self) + } +} + +macro_rules! commutative_op { + ($t:ty) => { + impl Add<$t> for ByteSize { + type Output = ByteSize; + #[inline(always)] + fn add(self, rhs: $t) -> ByteSize { + ByteSize(self.0 + (rhs as u64)) + } + } + + impl Add<ByteSize> for $t { + type Output = ByteSize; + #[inline(always)] + fn add(self, rhs: ByteSize) -> ByteSize { + ByteSize(rhs.0 + (self as u64)) + } + } + + impl Mul<$t> for ByteSize { + type Output = ByteSize; + #[inline(always)] + fn mul(self, rhs: $t) -> ByteSize { + ByteSize(self.0 * (rhs as u64)) + } + } + + impl Mul<ByteSize> for $t { + type Output = ByteSize; + #[inline(always)] + fn mul(self, rhs: ByteSize) -> ByteSize { + ByteSize(rhs.0 * (self as u64)) + } + } + }; +} + +commutative_op!(u64); +commutative_op!(u32); +commutative_op!(u16); +commutative_op!(u8); + +impl Add<ByteSize> for ByteSize { + type Output = ByteSize; + + #[inline(always)] + fn add(self, rhs: ByteSize) -> ByteSize { + ByteSize(self.0 + rhs.0) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_arithmetic_op() { + let x = ByteSize::mb(1); + let y = ByteSize::kb(100); + + assert_eq!((x + y).as_u64(), 1_100_000u64); + + assert_eq!((x + (100 * 1000) as u64).as_u64(), 1_100_000); + + assert_eq!((x * 2u64).as_u64(), 2_000_000); + } + + #[test] + fn test_arithmetic_primitives() { + let x = ByteSize::mb(1); + + assert_eq!((x + MB as u64).as_u64(), 2_000_000); + + assert_eq!((x + MB as u32).as_u64(), 2_000_000); + + assert_eq!((x + KB as u16).as_u64(), 1_001_000); + + assert_eq!((x + B as u8).as_u64(), 1_000_001); + } + + #[test] + fn test_comparison() { + assert!(ByteSize::mb(1) == ByteSize::kb(1000)); + assert!(ByteSize::mib(1) == ByteSize::kib(1024)); + assert!(ByteSize::mb(1) != ByteSize::kib(1024)); + assert!(ByteSize::mb(1) < ByteSize::kib(1024)); + assert!(ByteSize::b(0) < ByteSize::tib(1)); + } + + fn assert_display(expected: &str, b: ByteSize) { + assert_eq!(expected, format!("{}", b)); + } + + #[test] + fn test_display() { + assert_display("215 B", ByteSize::b(215)); + assert_display("1.0 KB", ByteSize::kb(1)); + assert_display("301.0 KB", ByteSize::kb(301)); + assert_display("419.0 MB", ByteSize::mb(419)); + assert_display("518.0 GB", ByteSize::gb(518)); + assert_display("815.0 TB", ByteSize::tb(815)); + assert_display("609.0 PB", ByteSize::pb(609)); + } + + #[test] + fn test_display_alignment() { + assert_eq!("|357 B |", format!("|{:10}|", ByteSize(357))); + assert_eq!("| 357 B|", format!("|{:>10}|", ByteSize(357))); + assert_eq!("|357 B |", format!("|{:<10}|", ByteSize(357))); + assert_eq!("| 357 B |", format!("|{:^10}|", ByteSize(357))); + + assert_eq!("|-----357 B|", format!("|{:->10}|", ByteSize(357))); + assert_eq!("|357 B-----|", format!("|{:-<10}|", ByteSize(357))); + assert_eq!("|--357 B---|", format!("|{:-^10}|", ByteSize(357))); + } + + fn assert_to_string(expected: &str, b: ByteSize, si: bool) { + assert_eq!(expected.to_string(), b.to_string_as(si)); + } + + #[test] + fn test_to_string_as() { + assert_to_string("215 B", ByteSize::b(215), true); + assert_to_string("215 B", ByteSize::b(215), false); + + assert_to_string("1.0 kiB", ByteSize::kib(1), true); + assert_to_string("1.0 KB", ByteSize::kib(1), false); + + assert_to_string("293.9 kiB", ByteSize::kb(301), true); + assert_to_string("301.0 KB", ByteSize::kb(301), false); + + assert_to_string("1.0 MiB", ByteSize::mib(1), true); + assert_to_string("1048.6 KB", ByteSize::mib(1), false); + + // a bug case: https://github.com/flang-project/bytesize/issues/8 + assert_to_string("1.9 GiB", ByteSize::mib(1907), true); + assert_to_string("2.0 GB", ByteSize::mib(1908), false); + + assert_to_string("399.6 MiB", ByteSize::mb(419), true); + assert_to_string("419.0 MB", ByteSize::mb(419), false); + + assert_to_string("482.4 GiB", ByteSize::gb(518), true); + assert_to_string("518.0 GB", ByteSize::gb(518), false); + + assert_to_string("741.2 TiB", ByteSize::tb(815), true); + assert_to_string("815.0 TB", ByteSize::tb(815), false); + + assert_to_string("540.9 PiB", ByteSize::pb(609), true); + assert_to_string("609.0 PB", ByteSize::pb(609), false); + } + + #[test] + fn test_default() { + assert_eq!(ByteSize::b(0), ByteSize::default()); + } + + #[test] + fn test_to_string() { + assert_to_string("609.0 PB", ByteSize::pb(609), false); + } +} |