use std::{fmt, ops};
use compile_fmt::{clip, compile_panic};
use crate::metadata::SizeUnit;
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ByteSize(pub u64);
impl fmt::Debug for ByteSize {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, formatter)
}
}
impl fmt::Display for ByteSize {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0 == 0 {
formatter.write_str("0 B")
} else if self.0 % (1 << 30) == 0 {
write!(formatter, "{} GiB", self.0 >> 30)
} else if self.0 % (1 << 20) == 0 {
write!(formatter, "{} MiB", self.0 >> 20)
} else if self.0 % (1 << 10) == 0 {
write!(formatter, "{} KiB", self.0 >> 10)
} else {
write!(formatter, "{} B", self.0)
}
}
}
impl From<u64> for ByteSize {
fn from(value: u64) -> Self {
Self(value)
}
}
impl ByteSize {
pub const fn checked(val: u64, unit: SizeUnit) -> Option<Self> {
match val.checked_mul(unit.bytes_in_unit()) {
Some(val) => Some(Self(val)),
None => None,
}
}
pub const fn new(val: u64, unit: SizeUnit) -> Self {
if let Some(size) = Self::checked(val, unit) {
size
} else {
compile_panic!(
val => compile_fmt::fmt::<u64>(), " ", unit.plural() => clip(16, ""), " does not fit into a `u64` value"
);
}
}
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
match self.0.checked_add(rhs.0) {
Some(val) => Some(Self(val)),
None => None,
}
}
pub const fn checked_mul(self, factor: u64) -> Option<Self> {
match self.0.checked_mul(factor) {
Some(val) => Some(Self(val)),
None => None,
}
}
}
impl From<SizeUnit> for ByteSize {
fn from(unit: SizeUnit) -> Self {
Self(unit.bytes_in_unit())
}
}
impl ops::Mul<u64> for SizeUnit {
type Output = ByteSize;
fn mul(self, rhs: u64) -> Self::Output {
ByteSize::from(self)
.checked_mul(rhs)
.unwrap_or_else(|| panic!("Integer overflow getting {rhs} * {self}"))
}
}
impl ops::Mul<SizeUnit> for u64 {
type Output = ByteSize;
fn mul(self, rhs: SizeUnit) -> Self::Output {
ByteSize::from(rhs)
.checked_mul(self)
.unwrap_or_else(|| panic!("Integer overflow getting {self} * {rhs}"))
}
}
impl ops::Add for ByteSize {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
self.checked_add(rhs)
.unwrap_or_else(|| panic!("Integer overflow getting {self} + {rhs}"))
}
}
impl ops::Mul<u64> for ByteSize {
type Output = Self;
fn mul(self, rhs: u64) -> Self::Output {
self.checked_mul(rhs)
.unwrap_or_else(|| panic!("Integer overflow getting {self} * {rhs}"))
}
}