1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use std::{cmp::Ordering, fmt};

// !!!!!!!!!!!!!!!!! Unit !!!!!!!!!!!!!!!!!!!!!!!
#[derive(Debug)]
pub enum Unit {
    Joule,
    MilliJoule,
    MicroJoule,
    MegaWatt,
    KiloWatt,
    Watt,
    MilliWatt,
    MicroWatt,
}

impl Unit {
    /// Converts either an energy measurement (Joule, MilliJoule or MicroJoule) to another energy Unit (Joule, MilliJoule or MicroJoule)
    /// or a power measurement (MilliWatt, MicroWatt, Watt, KiloWatt) to another power 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::MicroWatt,
            Unit::MilliWatt,
        ];
        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!("Impossible conversion asked from energy value to power value (without time dimension).");
        }
    }

    /// Helper func to compute the multiplicative factor needed for a conversion
    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 * (pos_dest - pos_source) as f64,
            Ordering::Less => mult /= 1000.0 * (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"),
        }
    }
}

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 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);
    }
}

//  Copyright 2020 The scaphandre authors.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.