use std::cell::RefCell;
use std::fmt::{Display, Formatter, Result};
use std::sync::{Arc, Mutex};
mod config;
pub use config::*;
mod test;
pub trait Unsigned {}
impl Unsigned for u8 {}
impl Unsigned for u16 {}
impl Unsigned for u32 {}
impl Unsigned for u64 {}
pub const GABYTES: [&str; 7] = ["B", "KB", "MB", "GB", "TB", "PB", "EB"];
pub const BIBYTES: [&str; 7] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
#[derive(Default, Clone)]
pub struct Bytes<U: Unsigned + Display + PartialOrd + Into<u64> + Copy> {
config: Arc<Mutex<RefCell<BytesParam>>>,
bytes: U,
}
impl<U: Unsigned + Display + PartialOrd + Into<u64> + Copy> Bytes<U> {
fn new(config: Arc<Mutex<RefCell<BytesParam>>>, byte: U) -> Self {
Self {
config,
bytes: byte,
}
}
pub fn value(&self) -> U {
self.bytes.clone()
}
pub fn into_inner(self) -> U {
self.bytes
}
}
impl<U> Display for Bytes<U>
where
U: Unsigned + Display + PartialOrd + Into<u64> + Copy,
{
fn fmt(&self, f: &mut Formatter) -> Result {
let base: u64 = match (*self.config).lock().unwrap().borrow().base {
BytesBase::Gabyte => 1000,
BytesBase::Bibyte => 1024,
};
let precision: usize = (*self.config).lock().unwrap().borrow().precision;
let prec_factor: f64 = 10.0_f64.powi(precision as i32);
let aligned: bool = (*self.config).lock().unwrap().borrow().aligned;
let b: u64 = self.bytes.into();
for e in 0_u32..7_u32 {
let divisor = base.pow(e);
let quotient = b / divisor;
let remainder = b % divisor;
let mut result: f64 = quotient as f64 + remainder as f64 / divisor as f64;
result = (result * prec_factor).round() / prec_factor;
if e == 0 {
if result < base as f64 {
let unit = if base == 1000 {
GABYTES[e as usize]
} else {
BIBYTES[e as usize]
};
if aligned {
let width = 4 + precision;
return write!(f, "{:width$} {}", result, unit);
} else {
return write!(f, "{:.0} {}", result as usize, unit);
}
}
} else {
if result < base as f64 {
let unit = if base == 1000 {
GABYTES[e as usize]
} else {
BIBYTES[e as usize]
};
if aligned {
let width = 4 + precision;
return write!(f, "{:width$.precision$} {}", result, unit);
} else {
return write!(f, "{:.precision$} {}", result, unit);
}
}
}
}
Err(std::fmt::Error)
}
}