93 lines
2.8 KiB
Rust
93 lines
2.8 KiB
Rust
//! size in bytes
|
|
//!
|
|
//! implement fmt::Display to display size in a human readable unit (B, KB, MB, GB, TB).
|
|
//!
|
|
//! For Bytes, unit isn't printed.
|
|
//!
|
|
//! implement std::ops::Add
|
|
|
|
use std::fmt;
|
|
|
|
#[derive(PartialEq, PartialOrd, Eq, Ord, Copy, Clone)]
|
|
pub struct Size(u64);
|
|
|
|
//#[derive(Debug)]
|
|
impl Size {
|
|
pub fn new(bytes: u64) -> Self {
|
|
Self(bytes)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Size {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let length: u32 = self.0.checked_ilog10().unwrap_or(0); //number of digits -1
|
|
// match over number of 3 digits groups, 1000 ~ 1024
|
|
// 1000^n and 1024^n have the same number of digits if n<98
|
|
// here n<=4 (TB)
|
|
//
|
|
// if size in KB or above we want at most 1 decimal
|
|
match length / 3 {
|
|
0 => write!(f, "{}", self.0 as f32), // we assume no unit printed means Bytes.
|
|
1 => write!(
|
|
f,
|
|
"{}KB",
|
|
(((self.0 as f32) / 1024.0) * 10.0_f32).round().trunc() / 10.0
|
|
),
|
|
2 => write!(
|
|
f,
|
|
"{}MB",
|
|
(((self.0 as f32) / 1048576.0) * 10.0_f32).round().trunc() / 10.0
|
|
),
|
|
3 => write!(
|
|
f,
|
|
"{}GB",
|
|
(((self.0 as f32) / 1073741824.0) * 10.0_f32)
|
|
.round()
|
|
.trunc()
|
|
/ 10.0
|
|
),
|
|
4 => write!(
|
|
f,
|
|
"{}TB",
|
|
(((self.0 as f32) / 1099511627776.0) * 10.0_f32)
|
|
.round()
|
|
.trunc()
|
|
/ 10.0
|
|
),
|
|
_ => panic!(), // unlikely to have PetaBytes of files (and above) on consumer grade hardware
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::ops::Add for Size {
|
|
type Output = Self;
|
|
fn add(self, other: Self) -> Self::Output {
|
|
Self(self.0 + other.0)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
#[test]
|
|
fn create() {
|
|
assert_eq!(Size::new(1).0, 1);
|
|
}
|
|
#[test]
|
|
fn add() {
|
|
let s1 = Size::new(60);
|
|
let s2 = Size::new(40);
|
|
assert_eq!((s1 + s2).0, 100);
|
|
}
|
|
#[test]
|
|
fn display() {
|
|
assert_eq!(10u32.checked_ilog10().unwrap_or(0) + 1, 2);
|
|
|
|
assert_eq!(format!("{}", Size::new(1024)), "1KB");
|
|
// 1700/1024 = 1.66015625
|
|
assert_eq!(format!("{}", Size::new(1700)), "1.7KB");
|
|
// 2411724/(1024^2) = 2.299999237060547
|
|
assert_eq!(format!("{}", Size::new(2411724)), "2.3MB");
|
|
}
|
|
}
|