1use crate::units::{FromUnits, Unit};
8
9#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
12#[non_exhaustive]
13pub enum TemperatureUnits {
14 #[default]
17 Kelvin,
18
19 Celsius,
23
24 Fahrenheit,
28
29 Rankine,
32}
33macro_rules! scale {
34 ($val:expr,$factor:expr,$type:ident) => {
35 $val * $factor as $type
36 };
37}
38macro_rules! offset {
39 ($val:expr,$shift:expr,$type:ident) => {
40 $val + $shift as $type
41 };
42}
43
44macro_rules! from_units_length {
45 ($type:ident) => {
46 impl crate::units::FromUnits<$type> for TemperatureUnits {
47 fn from(&self, value: $type, source_unit: Self) -> $type {
48 match self {
49 TemperatureUnits::Kelvin => match source_unit {
51 TemperatureUnits::Kelvin => value,
53 TemperatureUnits::Celsius => offset!(value, CELSIUS_KELVIN_OFFSET, $type),
54 TemperatureUnits::Fahrenheit => scale!(
55 offset!(value, FAHRENHEIT_RANKINE_OFFSET, $type),
56 (1.0 / CELSIUS_FAHRENHEIT_FACTOR),
57 $type
58 ),
59 TemperatureUnits::Rankine => {
60 scale!(value, (1.0 / CELSIUS_FAHRENHEIT_FACTOR), $type)
61 }
62 },
63 TemperatureUnits::Celsius => match source_unit {
64 TemperatureUnits::Kelvin => offset!(value, -CELSIUS_KELVIN_OFFSET, $type),
65 TemperatureUnits::Celsius => value,
66 TemperatureUnits::Fahrenheit => scale!(
67 offset!(value, -CELSIUS_FAHRENHEIT_OFFSET, $type),
68 (1.0 / CELSIUS_FAHRENHEIT_FACTOR),
69 $type
70 ),
71 TemperatureUnits::Rankine => offset!(
72 scale!(value, (1.0 / CELSIUS_FAHRENHEIT_FACTOR), $type),
73 -CELSIUS_KELVIN_OFFSET,
74 $type
75 ),
76 },
77 TemperatureUnits::Fahrenheit => match source_unit {
78 TemperatureUnits::Kelvin => offset!(
79 scale!(value, CELSIUS_FAHRENHEIT_FACTOR, $type),
80 -FAHRENHEIT_RANKINE_OFFSET,
81 $type
82 ),
83 TemperatureUnits::Celsius => offset!(
84 scale!(value, CELSIUS_FAHRENHEIT_FACTOR, $type),
85 CELSIUS_FAHRENHEIT_OFFSET,
86 $type
87 ),
88 TemperatureUnits::Fahrenheit => value,
89 TemperatureUnits::Rankine => {
90 offset!(value, -FAHRENHEIT_RANKINE_OFFSET, $type)
91 }
92 },
93 TemperatureUnits::Rankine => match source_unit {
94 TemperatureUnits::Kelvin => scale!(value, CELSIUS_FAHRENHEIT_FACTOR, $type),
95 TemperatureUnits::Celsius => scale!(
96 offset!(value, CELSIUS_KELVIN_OFFSET, $type),
97 CELSIUS_FAHRENHEIT_FACTOR,
98 $type
99 ),
100 TemperatureUnits::Fahrenheit => {
101 offset!(value, FAHRENHEIT_RANKINE_OFFSET, $type)
102 }
103 TemperatureUnits::Rankine => value,
104 },
105 }
106 }
107 }
108 };
109}
110
111basic_unit!(Temperature, TemperatureUnits, Kelvin);
112from_units_length!(f32);
113from_units_length!(f64);
114
115impl Temperature {
116 #[must_use]
117 pub fn new_celsius(value: f64) -> Temperature {
118 Self::new(value, TemperatureUnits::Celsius)
119 }
120
121 #[must_use]
122 pub fn new_fahrenheit(value: f64) -> Temperature {
123 Self::new(value, TemperatureUnits::Fahrenheit)
124 }
125
126 #[must_use]
127 pub fn new_kelvin(value: f64) -> Temperature {
128 Self::new(value, TemperatureUnits::Kelvin)
129 }
130
131 #[must_use]
132 pub fn new_rankine(value: f64) -> Temperature {
133 Self::new(value, TemperatureUnits::Rankine)
134 }
135
136 #[must_use]
137 pub fn as_celsius(&self) -> Temperature {
138 self.as_unit(TemperatureUnits::Celsius)
139 }
140
141 #[must_use]
142 pub fn as_kelvin(&self) -> Temperature {
143 self.as_unit(TemperatureUnits::Kelvin)
144 }
145
146 #[must_use]
147 pub fn as_fahrenheit(&self) -> Temperature {
148 self.as_unit(TemperatureUnits::Fahrenheit)
149 }
150
151 #[must_use]
152 pub fn as_rankine(&self) -> Temperature {
153 self.as_unit(TemperatureUnits::Rankine)
154 }
155}
156
157pub const CELSIUS_KELVIN_OFFSET: f64 = 273.15;
158pub const CELSIUS_FAHRENHEIT_OFFSET: f64 = 32.;
159pub const CELSIUS_FAHRENHEIT_FACTOR: f64 = 1.8;
160pub const FAHRENHEIT_RANKINE_OFFSET: f64 = 459.67;
161
162#[cfg(test)]
163mod test {
164 use crate::units::temperature::Temperature;
165
166 #[test]
167 pub fn tests() {
168 let abs_k = Temperature::new_kelvin(0.0);
169 assert_eq!(abs_k.as_kelvin().value, 0.0);
170 assert_eq!(abs_k.as_celsius().value, -273.15);
171 assert_eq!(abs_k.as_fahrenheit().value, -459.67);
172 assert_eq!(abs_k.as_rankine().value, 0.0);
173
174 let zerof = Temperature::new_fahrenheit(0.0);
175 assert_eq!(zerof.as_kelvin().value, 255.37222222222223);
176 assert_eq!(zerof.as_celsius().value, -17.77777777777778);
177 assert_eq!(zerof.as_fahrenheit().value, 0.0);
178 assert_eq!(zerof.as_rankine().value, 459.67);
179
180 let zeroc = Temperature::new_celsius(0.0);
181 assert_eq!(zeroc.as_kelvin().value, 273.15);
182 assert_eq!(zeroc.as_celsius().value, 0.0);
183 assert_eq!(zeroc.as_fahrenheit().value, 32.0);
184 assert_eq!(zeroc.as_rankine().value, 491.66999999999996);
185
186 let zeror = Temperature::new_rankine(0.0);
187 assert_eq!(zeror.as_kelvin().value, 0.0);
188 assert_eq!(zeror.as_celsius().value, -273.15);
189 assert_eq!(zeror.as_fahrenheit().value, -459.67);
190 assert_eq!(zeror.as_rankine().value, 0.0);
191
192 let stp = Temperature::new_celsius(15.0);
193 assert_eq!(stp.as_kelvin().value, 288.15);
194 assert_eq!(stp.as_celsius().value, 15.0);
195 assert_eq!(stp.as_fahrenheit().value, 59.);
196 assert_eq!(stp.as_rankine().value, 518.67);
197
198 let boil = Temperature::new_kelvin(373.1339);
199 assert_eq!(boil.as_kelvin().value, 373.1339);
200 assert_eq!(boil.as_celsius().value, 99.9839);
201 assert_eq!(boil.as_fahrenheit().value, 211.97102);
202 assert_eq!(boil.as_rankine().value, 671.64102);
203
204 let boil = Temperature::new_celsius(99.9839);
205 assert_eq!(boil.as_kelvin().value, 373.1339);
206 assert_eq!(boil.as_celsius().value, 99.9839);
207 assert_eq!(boil.as_fahrenheit().value, 211.97102);
208 assert_eq!(boil.as_rankine().value, 671.64102);
209
210 let boil = Temperature::new_fahrenheit(211.97102);
211 assert_eq!(boil.as_kelvin().value, 373.13390000000004);
212 assert_eq!(boil.as_celsius().value, 99.9839);
213 assert_eq!(boil.as_fahrenheit().value, 211.97102);
214 assert_eq!(boil.as_rankine().value, 671.64102);
215
216 let boil = Temperature::new_rankine(671.64102);
217 assert_eq!(boil.as_kelvin().value, 373.13390000000004);
218 assert_eq!(boil.as_celsius().value, 99.98390000000006);
219 assert_eq!(boil.as_fahrenheit().value, 211.97102);
220 assert_eq!(boil.as_rankine().value, 671.64102);
221 }
222}