use std::{fmt, ops};
use compile_fmt::{clip, compile_panic};
use crate::metadata::{EtherUnit, 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.is_multiple_of(1 << 30) {
write!(formatter, "{} GiB", self.0 >> 30)
} else if self.0.is_multiple_of(1 << 20) {
write!(formatter, "{} MiB", self.0 >> 20)
} else if self.0.is_multiple_of(1 << 10) {
write!(formatter, "{} KiB", self.0 >> 10)
} else {
write!(formatter, "{} B", self.0)
}
}
}
macro_rules! impl_unit_conversions {
($ty:ident($raw:ty), $unit:ident) => {
impl From<$raw> for $ty {
fn from(value: $raw) -> Self {
Self(value)
}
}
impl $ty {
pub const fn checked(val: $raw, unit: $unit) -> Option<Self> {
match val.checked_mul(unit.value_in_unit()) {
Some(val) => Some(Self(val)),
None => None,
}
}
pub const fn new(val: $raw, unit: $unit) -> Self {
if let Some(size) = Self::checked(val, unit) {
size
} else {
compile_panic!(
val => compile_fmt::fmt::<$raw>(), " ", unit.as_str() => clip(16, ""), " does not fit into a 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: $raw) -> Option<Self> {
match self.0.checked_mul(factor) {
Some(val) => Some(Self(val)),
None => None,
}
}
}
impl From<$unit> for $ty {
fn from(unit: $unit) -> Self {
Self(unit.value_in_unit())
}
}
impl ops::Mul<$raw> for $unit {
type Output = $ty;
fn mul(self, rhs: $raw) -> Self::Output {
$ty::from(self)
.checked_mul(rhs)
.unwrap_or_else(|| panic!("Integer overflow getting {rhs} * {self}"))
}
}
impl ops::Mul<$unit> for $raw {
type Output = $ty;
fn mul(self, rhs: $unit) -> Self::Output {
$ty::from(rhs)
.checked_mul(self)
.unwrap_or_else(|| panic!("Integer overflow getting {self} * {rhs}"))
}
}
impl ops::Add for $ty {
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<$raw> for $ty {
type Output = Self;
fn mul(self, rhs: $raw) -> Self::Output {
self.checked_mul(rhs)
.unwrap_or_else(|| panic!("Integer overflow getting {self} * {rhs}"))
}
}
};
}
impl_unit_conversions!(ByteSize(u64), SizeUnit);
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EtherAmount(pub u128);
impl fmt::Debug for EtherAmount {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, formatter)
}
}
impl fmt::Display for EtherAmount {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0.is_multiple_of(EtherUnit::Ether.value_in_unit()) {
write!(
formatter,
"{} ether",
self.0 / EtherUnit::Ether.value_in_unit()
)
} else if self.0.is_multiple_of(EtherUnit::Gwei.value_in_unit()) {
write!(
formatter,
"{} gwei",
self.0 / EtherUnit::Gwei.value_in_unit()
)
} else {
write!(formatter, "{} wei", self.0)
}
}
}
impl_unit_conversions!(EtherAmount(u128), EtherUnit);