use derive_more::{Add, AddAssign, Deref, Div, DivAssign, From, Mul, MulAssign, Sub, SubAssign}; use serde::{Deserialize, Serialize}; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; enum DisplayKind { Plural(&'static str, &'static str), HumanBytes, } macro_rules! define_fmt_wrapper { ($name:ident, $ty:ty, $display_kind:expr) => { #[derive( Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign, From, Deref, Serialize, Deserialize, )] pub struct $name(pub $ty); impl $name { #[allow(dead_code)] pub fn new(value: $ty) -> Self { Self(value) } } impl Display for $name { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { match $display_kind { DisplayKind::Plural(singular, plural) => { let label = if self.0 == 1 { singular } else { plural }; write!(f, "{} {}", self.0, label) } DisplayKind::HumanBytes => { use humansize::{DECIMAL, format_size}; write!(f, "{}", format_size(self.0, DECIMAL)) } } } } impl Debug for $name { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { Display::fmt(self, f) } } }; } define_fmt_wrapper!(FmtThreads, u16, DisplayKind::Plural("Thread", "Threads")); define_fmt_wrapper!(FmtCores, usize, DisplayKind::Plural("Core", "Cores")); define_fmt_wrapper!(FmtBytes, u64, DisplayKind::HumanBytes);