summaryrefslogtreecommitdiffstats
path: root/src/metric/temperature.rs
blob: 06c148936042b33e13e87a6e20f19e2836e23b88 (plain) (blame)
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
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<ThermodynamicTemperature> 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<CelsiusTemperature> 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<ThermodynamicTemperature> 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<ThermodynamicTemperature> 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<ThermodynamicTemperature> 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<ThermodynamicTemperature> 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")
        }
    }
}