use core::fmt;
use crate::BSize;
#[derive(Debug, Clone)]
pub struct Display {
size: u64,
mode: DisplayMode,
}
#[derive(Debug, Clone)]
enum DisplayMode {
Binary,
Decimal,
}
impl Display {
pub fn binary(mut self) -> Self {
self.mode = DisplayMode::Binary;
self
}
pub fn decimal(mut self) -> Self {
self.mode = DisplayMode::Decimal;
self
}
fn new(size: u64) -> Self {
Self {
size,
mode: DisplayMode::Binary,
}
}
}
impl fmt::Display for Display {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let bytes = self.size;
let unit = match self.mode {
DisplayMode::Binary => 1024,
DisplayMode::Decimal => 1000,
};
let unit_prefixes = match self.mode {
DisplayMode::Binary => b"KMGTPE",
DisplayMode::Decimal => b"kMGTPE",
};
let unit_suffix = match self.mode {
DisplayMode::Binary => "iB",
DisplayMode::Decimal => "B",
};
let unit_separator = " ";
let precision = f.precision().unwrap_or(1);
if bytes < unit {
write!(f, "{bytes}{unit_separator}B")?;
} else {
let size = bytes as f64;
let mut ideal_prefix = 0usize;
let mut ideal_size = size;
loop {
ideal_prefix += 1;
ideal_size /= unit as f64;
if ideal_size < unit as f64 {
break;
}
}
let exp = ideal_prefix;
let unit_prefix = unit_prefixes[exp - 1] as char;
write!(
f,
"{:.precision$}{unit_separator}{unit_prefix}{unit_suffix}",
size / unit.pow(exp as u32) as f64,
)?;
}
Ok(())
}
}
macro_rules! impl_display {
($($ty:ty),* $(,)?) => {
$(
impl BSize<$ty> {
pub fn display(self) -> Display {
Display::new(self.0 as u64)
}
}
)*
};
}
impl_display!(u8, u16, u32, u64, usize);