use std::{ fmt::{self, Display, Formatter}, ops::Mul, }; #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] pub enum Unit { #[default] CubicMetre, Litre, } impl Unit { pub const ALL: [Self; 2] = [Self::CubicMetre, Self::Litre]; } impl Display for Unit { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, "{}", match self { Self::CubicMetre => "m³", Self::Litre => "L", } ) } } #[derive(Debug, Default, PartialEq)] pub struct CubicMetre(pub f64); impl CubicMetre { pub fn from_unit>(unit: Unit, value: F) -> Self { match unit { Unit::CubicMetre => Self(value.into()), Unit::Litre => Self::from(Litre(value.into())), } } } impl From for CubicMetre { fn from(value: Litre) -> Self { Self(value.0 * 10_f64.powi(-3)) } } #[derive(Debug, PartialEq)] struct Litre(f64); impl> From for Litre { fn from(value: F) -> Self { Self(value.into()) } } impl From for Litre { fn from(value: CubicMetre) -> Self { Self(value.0 * 10_f64.powi(3)) } } impl> Mul for Litre { type Output = Self; fn mul(self, rhs: F) -> Self::Output { Self(self.0 * rhs.into()) } } pub fn convert>(val: F, from: Unit, to: Unit) -> f64 { match from { Unit::CubicMetre => match to { Unit::CubicMetre => val.into(), Unit::Litre => Litre::from(CubicMetre(val.into())).0, }, Unit::Litre => match to { Unit::Litre => val.into(), Unit::CubicMetre => CubicMetre::from(Litre(val.into())).0, }, } } #[cfg(test)] mod tests { use super::{CubicMetre, Litre}; #[test] fn litre_to_cubic_metre() { assert_eq!(CubicMetre::from(Litre(1000.)), CubicMetre(1.)) } #[test] fn cubic_metre_to_litre() { assert_eq!(Litre::from(CubicMetre(1.)), Litre(1000.)) } }