use std::fmt::{Display, Formatter, Result}; use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; use crate::metric::Unit; use crate::metric::Primitive; use crate::declare_unit_basics; #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] pub enum ThermodynamicTemperature { Base(f64, fn(f64) -> f64, &'static str), Canonical(f64), Kelvin(f64), } impl Unit for ThermodynamicTemperature { fn to_si_unit(&self) -> ThermodynamicTemperature { match self { ThermodynamicTemperature::Base(_, _, _) => self.clone(), ThermodynamicTemperature::Canonical(value) => ThermodynamicTemperature::Base(value.clone(), |x| x, "K"), ThermodynamicTemperature::Kelvin(value) => ThermodynamicTemperature::Base(value.clone(), |x| x, "K"), } } } declare_unit_basics!(ThermodynamicTemperature); #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] pub enum CelsiusTemperature { Base(f64, fn(f64) -> f64, &'static str), Canonical(f64), Celsius(f64), Fahrenheit(f64), } impl Unit for CelsiusTemperature { fn to_si_unit(&self) -> CelsiusTemperature { match self { CelsiusTemperature::Base(_, _, _) => self.clone(), CelsiusTemperature::Canonical(value) => CelsiusTemperature::Base(value.clone(), |x| x, "K"), CelsiusTemperature::Celsius(value) => CelsiusTemperature::Base(value.clone(), |x| x, "°C"), CelsiusTemperature::Fahrenheit(value) => CelsiusTemperature::Base((value - 32.0) / 1.8 , |x| x * 1.8 + 32.0, "°F"), } } } declare_unit_basics!(CelsiusTemperature); /* --- temperature interoperability: C +/- K --- */ impl Add for CelsiusTemperature { type Output = CelsiusTemperature; fn add(self, rhs: ThermodynamicTemperature) -> Self::Output { match self.to_si_unit() { CelsiusTemperature::Base(value, from_si, symbol) => CelsiusTemperature::Base(value + rhs.to_si_primitive(), from_si, symbol), _ => panic!("non si unit post to_si_unit() call") } } } impl AddAssign for CelsiusTemperature { fn add_assign(&mut self, rhs: ThermodynamicTemperature) { match self.to_si_unit() { CelsiusTemperature::Base(value, from_si, symbol) => *self = CelsiusTemperature::Base(value + rhs.to_si_primitive(), from_si, symbol), _ => panic!("non si unit post to_si_unit() call") } } } impl Sub for CelsiusTemperature { type Output = CelsiusTemperature; fn sub(self, rhs: ThermodynamicTemperature) -> Self::Output { match self.to_si_unit() { CelsiusTemperature::Base(value, from_si, symbol) => CelsiusTemperature::Base(value + rhs.to_si_primitive(), from_si, symbol), _ => panic!("non si unit post to_si_unit() call") } } } impl SubAssign for CelsiusTemperature { fn sub_assign(&mut self, rhs: ThermodynamicTemperature) { match self.to_si_unit() { CelsiusTemperature::Base(value, from_si, symbol) => *self = CelsiusTemperature::Base(value - rhs.to_si_primitive(), from_si, symbol), _ => panic!("non si unit post to_si_unit() call") } } }