use std::{cmp::Ordering, fmt};
#[derive(Debug)]
pub enum Unit {
Numeric,
Joule,
MilliJoule,
MicroJoule,
MegaWatt,
KiloWatt,
Watt,
MilliWatt,
MicroWatt,
Percentage,
Bytes,
KiloBytes,
MegaBytes,
GigaBytes,
MegaHertz,
}
impl Unit {
pub fn to(measure: f64, source_unit: &Unit, dest_unit: &Unit) -> Result<f64, String> {
let energy_order = [Unit::Joule, Unit::MilliJoule, Unit::MicroJoule];
let power_order = [
Unit::MegaWatt,
Unit::KiloWatt,
Unit::Watt,
Unit::MilliWatt,
Unit::MicroWatt,
];
let pos_source_energy = energy_order.iter().position(|x| x == source_unit);
let pos_dest_energy = energy_order.iter().position(|x| x == dest_unit);
let pos_source_power = power_order.iter().position(|x| x == source_unit);
let pos_dest_power = power_order.iter().position(|x| x == dest_unit);
if let (Some(pos_source), Some(pos_dest)) = (pos_source_energy, pos_dest_energy) {
Ok(measure * Unit::get_mult(pos_source, pos_dest))
} else if let (Some(pos_source), Some(pos_dest)) = (pos_source_power, pos_dest_power) {
Ok(measure * Unit::get_mult(pos_source, pos_dest))
} else {
panic!("Unimplemented or impossible conversion (if asked from energy value to power value without time dimension).");
}
}
fn get_mult(pos_source: usize, pos_dest: usize) -> f64 {
let mut mult: f64 = 1.0;
match pos_dest.cmp(&pos_source) {
Ordering::Greater => mult *= 1000.0_f64.powf((pos_dest - pos_source) as f64),
Ordering::Less => mult /= 1000.0_f64.powf((pos_source - pos_dest) as f64),
Ordering::Equal => (),
}
mult
}
}
impl fmt::Display for Unit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Unit::Joule => write!(f, "Joules"),
Unit::MilliJoule => write!(f, "MilliJoules"),
Unit::MicroJoule => write!(f, "MicroJoules"),
Unit::MilliWatt => write!(f, "MilliWatts"),
Unit::MicroWatt => write!(f, "MicroWatts"),
Unit::Watt => write!(f, "Watts"),
Unit::KiloWatt => write!(f, "KiloWatts"),
Unit::MegaWatt => write!(f, "MegaWatts"),
Unit::Percentage => write!(f, "Percentage"),
Unit::Bytes => write!(f, "Bytes"),
Unit::KiloBytes => write!(f, "KiloBytes"),
Unit::MegaBytes => write!(f, "MegaBytes"),
Unit::GigaBytes => write!(f, "GigaBytes"),
Unit::MegaHertz => write!(f, "MegaHertz"),
Unit::Numeric => write!(f, ""),
}
}
}
impl Eq for Unit {}
impl PartialEq for Unit {
fn eq(&self, other: &Self) -> bool {
format!("{self:?}") == format!("{other:?}")
}
}
impl Copy for Unit {}
impl Clone for Unit {
fn clone(&self) -> Self {
*self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn kw_equals_1000w() {
let value = 1.0;
let source = Unit::KiloWatt;
let dest = Unit::Watt;
assert_eq!(Unit::to(value, &source, &dest).unwrap(), 1000.0);
}
#[test]
fn kw_equals_0001megawatt() {
let value = 1.0;
let source = Unit::KiloWatt;
let dest = Unit::MegaWatt;
assert_eq!(Unit::to(value, &source, &dest).unwrap(), 0.001);
}
#[test]
fn kw_to_milliwatt() {
let value = 2.0;
let source = Unit::KiloWatt;
let dest = Unit::MilliWatt;
assert_eq!(Unit::to(value, &source, &dest).unwrap(), 2000000.0);
}
#[test]
fn milliwatt_to_watt() {
let value = 6.0;
let source = Unit::MilliWatt;
let dest = Unit::Watt;
assert_eq!(Unit::to(value, &source, &dest).unwrap(), 0.006);
}
#[test]
fn megawatt_to_microwatt() {
let value = 12.0;
let source = Unit::MegaWatt;
let dest = Unit::MicroWatt;
assert_eq!(Unit::to(value, &source, &dest).unwrap(), 12000000000000.0);
}
#[test]
fn joule_equals_1000000microjoules() {
let value = 1.0;
let source = Unit::Joule;
let dest = Unit::MicroJoule;
assert_eq!(Unit::to(value, &source, &dest).unwrap(), 1000000.0);
}
#[test]
fn joule_to_milijoules() {
let value = 2.0;
let source = Unit::Joule;
let dest = Unit::MilliJoule;
assert_eq!(Unit::to(value, &source, &dest).unwrap(), 2000.0);
}
#[test]
fn milijoule_to_joules() {
let value = 4000.0;
let source = Unit::MilliJoule;
let dest = Unit::Joule;
assert_eq!(Unit::to(value, &source, &dest).unwrap(), 4.0);
}
}