#[macro_export] macro_rules! declare_simple_unit { ($unit_enum:ident, $si_unit:ident, $si_symbol:literal) => { #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] pub enum $unit_enum { Base(f64, fn(f64) -> f64, &'static str), Canonical(f64), $si_unit(f64) } impl Unit<$unit_enum> for $unit_enum { fn to_si_unit(&self) -> $unit_enum { match self { $unit_enum::Base(_, _, _) => self.clone(), $unit_enum::Canonical(value) => $unit_enum::Base(value.clone(), |x| x, $si_symbol), $unit_enum::$si_unit(value) => $unit_enum::Base(value.clone(), |x| x, $si_symbol), } } } declare_unit_basics!($unit_enum); }; } #[macro_export] macro_rules! declare_unit_basics { ($unit_enum:ident) => { impl Primitive for $unit_enum { fn to_si_primitive(&self) -> f64 { match self.to_si_unit() { $unit_enum::Base(value, _, _) => value, _ => panic!("non si unit post to_si_unit() call"), } } } impl Add for $unit_enum { type Output = $unit_enum; fn add(self, rhs: Self) -> Self::Output { match self.to_si_unit() { $unit_enum::Base(value, from_si, symbol) => $unit_enum::Base(value + rhs.to_si_primitive(), from_si, symbol), _ => panic!("non si unit post to_si_unit() call"), } } } impl AddAssign for $unit_enum { fn add_assign(&mut self, rhs: Self) { match self.to_si_unit() { $unit_enum::Base(value, from_si, symbol) => *self = $unit_enum::Base(value + rhs.to_si_primitive(), from_si, symbol), _ => panic!("non si unit post to_si_unit() call"), } } } impl Sub for $unit_enum { type Output = $unit_enum; fn sub(self, rhs: Self) -> Self::Output { match self.to_si_unit() { $unit_enum::Base(value, from_si, symbol) => $unit_enum::Base(value - rhs.to_si_primitive(), from_si, symbol), _ => panic!("non si unit post to_si_unit() call"), } } } impl SubAssign for $unit_enum { fn sub_assign(&mut self, rhs: Self) { match self.to_si_unit() { $unit_enum::Base(value, from_si, symbol) => *self = $unit_enum::Base(value - rhs.to_si_primitive(), from_si, symbol), _ => panic!("non si unit post to_si_unit() call"), } } } impl Mul<$unit_enum> for f64 { type Output = $unit_enum; fn mul(self, rhs: $unit_enum) -> Self::Output { match rhs.to_si_unit() { $unit_enum::Base(value, from_si, symbol) => $unit_enum::Base(self * value, from_si, symbol), _ => panic!("non si unit post to_si_unit() call"), } } } impl Mul for $unit_enum { type Output = $unit_enum; fn mul(self, rhs: f64) -> Self::Output { match self.to_si_unit() { $unit_enum::Base(value, from_si, symbol) => $unit_enum::Base(value * rhs, from_si, symbol), _ => panic!("non si unit post to_si_unit() call"), } } } impl MulAssign for $unit_enum { fn mul_assign(&mut self, rhs: f64) { match self.to_si_unit() { $unit_enum::Base(value, from_si, symbol) => *self = $unit_enum::Base(rhs * value, from_si, symbol), _ => panic!("non si unit post to_si_unit() call"), } } } impl Div for $unit_enum { type Output = $unit_enum; fn div(self, rhs: f64) -> Self::Output { match self.to_si_unit() { $unit_enum::Base(value, from_si, symbol) => $unit_enum::Base(value / rhs, from_si, symbol), _ => panic!("non si unit post to_si_unit() call"), } } } impl DivAssign for $unit_enum { fn div_assign(&mut self, rhs: f64) { match self.to_si_unit() { $unit_enum::Base(value, from_si, symbol) => *self = $unit_enum::Base(value / rhs, from_si, symbol), _ => panic!("non si unit post to_si_unit() call"), } } } impl Div<$unit_enum> for $unit_enum { type Output = f64; fn div(self, rhs: $unit_enum) -> Self::Output { self.to_si_primitive() / rhs.to_si_primitive() } } impl Display for $unit_enum { fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self.to_si_unit() { $unit_enum::Base(value, from_si, symbol) => write!(f, "{}[{}]", from_si(value), symbol), _ => panic!("Display: non si unit post to_si_unit() call"), } } } pub use $unit_enum::*; }; } #[macro_export] macro_rules! declare_unit_square { ($base:ident, $product:ident) => { impl Mul<$base> for $base { type Output = $product; fn mul(self, rhs: $base) -> Self::Output { $product::Canonical(self.to_si_primitive() * rhs.to_si_primitive()) } } impl Div<$base> for $product { type Output = $base; fn div(self, rhs: $base) -> Self::Output { $base::Canonical(self.to_si_primitive() / rhs.to_si_primitive()) } } }; } #[macro_export] macro_rules! declare_unit_multiplication { ($factor_a:ident, $factor_b:ident, $product:ident) => { impl Mul<$factor_a> for $factor_b { type Output = $product; fn mul(self, rhs: $factor_a) -> Self::Output { $product::Canonical(self.to_si_primitive() * rhs.to_si_primitive()) } } impl Mul<$factor_b> for $factor_a { type Output = $product; fn mul(self, rhs: $factor_b) -> Self::Output { $product::Canonical(self.to_si_primitive() * rhs.to_si_primitive()) } } impl Div<$factor_a> for $product { type Output = $factor_b; fn div(self, rhs: $factor_a) -> Self::Output { $factor_b::Canonical(self.to_si_primitive() / rhs.to_si_primitive()) } } impl Div<$factor_b> for $product { type Output = $factor_a; fn div(self, rhs: $factor_b) -> Self::Output { $factor_a::Canonical(self.to_si_primitive() / rhs.to_si_primitive()) } } }; }