use std::cmp::Ordering;
use std::fmt;
const PB: u64 = 1 << 50;
const TB: u64 = 1 << 40;
const GB: u64 = 1 << 30;
const MB: u64 = 1 << 20;
const KB: u64 = 1 << 10;
const PB_F: f64 = PB as f64;
const TB_F: f64 = TB as f64;
const GB_F: f64 = GB as f64;
const MB_F: f64 = MB as f64;
const KB_F: f64 = KB as f64;
#[derive(Debug, Clone)]
pub struct FileSize {
pub pb: u16,
pub tb: u16,
pub gb: u16,
pub mb: u16,
pub kb: u16,
pub b: u16,
}
impl FileSize {
pub fn from_total_bytes(total_bytes: u64) -> Self {
let b = total_bytes;
let pb = b / PB;
let b = b - pb * PB;
let tb = b / TB;
let b = b - tb * TB;
let gb = b / GB;
let b = b - gb * GB;
let mb = b / MB;
let b = b - mb * MB;
let kb = b / KB;
let b = b - kb * KB;
Self {
pb: pb as u16,
tb: tb as u16,
gb: gb as u16,
mb: mb as u16,
kb: kb as u16,
b: b as u16,
}
}
pub fn get_total_bytes(&self) -> u64 {
let pb: u64 = (self.pb as u64) * PB;
let tb: u64 = (self.tb as u64) * TB;
let gb: u64 = (self.gb as u64) * GB;
let mb: u64 = (self.mb as u64) * MB;
let kb: u64 = (self.kb as u64) * KB;
let b: u64 = self.b as u64;
b + kb + mb + gb + tb + pb
}
pub fn get_fractional_pb(&self) -> f64 {
(self.get_total_bytes() as f64) / PB_F
}
pub fn get_fractional_tb(&self) -> f64 {
(self.get_total_bytes() as f64) / TB_F
}
pub fn get_fractional_gb(&self) -> f64 {
(self.get_total_bytes() as f64) / GB_F
}
pub fn get_fractional_mb(&self) -> f64 {
(self.get_total_bytes() as f64) / MB_F
}
pub fn get_fractional_kb(&self) -> f64 {
(self.get_total_bytes() as f64) / KB_F
}
}
impl PartialOrd for FileSize {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for FileSize {
fn cmp(&self, other: &Self) -> Ordering {
self.get_total_bytes().cmp(&other.get_total_bytes())
}
}
impl PartialEq for FileSize {
fn eq(&self, other: &Self) -> bool {
self.get_total_bytes() == other.get_total_bytes()
}
}
impl Eq for FileSize {}
impl fmt::Display for FileSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let data: (f64, &str) = if self.pb > 0 {
(self.get_fractional_pb(), "PiB")
} else if self.tb > 0 {
(self.get_fractional_tb(), "TiB")
} else if self.gb > 0 {
(self.get_fractional_gb(), "GiB")
} else if self.mb > 0 {
(self.get_fractional_mb(), "MiB")
} else if self.kb > 0 {
(self.get_fractional_kb(), "KiB")
} else {
return write!(f, "{}B", self.get_total_bytes());
};
write!(f, "{:.2}{}", data.0, data.1)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn filesize_frombytes_1048576() {
let fs = FileSize::from_total_bytes(1048576);
assert_eq!(fs.pb, 0);
assert_eq!(fs.tb, 0);
assert_eq!(fs.gb, 0);
assert_eq!(fs.mb, 1);
assert_eq!(fs.kb, 0);
assert_eq!(fs.b, 0);
}
#[test]
fn filesize_frombytes_1048726() {
let fs = FileSize::from_total_bytes(1048726);
assert_eq!(fs.pb, 0);
assert_eq!(fs.tb, 0);
assert_eq!(fs.gb, 0);
assert_eq!(fs.mb, 1);
assert_eq!(fs.kb, 0);
assert_eq!(fs.b, 150);
}
}