|
1 | 1 | //! Types and constants for handling temperature.
|
2 | 2 |
|
3 | 3 | use super::measurement::*;
|
| 4 | +#[cfg(feature = "from_str")] |
| 5 | +use std::str::FromStr; |
| 6 | +#[cfg(feature = "from_str")] |
| 7 | +use regex::Regex; |
4 | 8 |
|
5 | 9 | /// The `Temperature` struct can be used to deal with absolute temperatures in
|
6 | 10 | /// a common way.
|
@@ -204,6 +208,35 @@ impl ::std::cmp::PartialOrd for Temperature {
|
204 | 208 | }
|
205 | 209 | }
|
206 | 210 |
|
| 211 | +#[cfg(feature = "from_str")] |
| 212 | +impl FromStr for Temperature { |
| 213 | + type Err = std::num::ParseFloatError; |
| 214 | + |
| 215 | + /// Create a new Temperature from a string |
| 216 | + /// Plain numbers in string are considered to be Celsius |
| 217 | + fn from_str(val: &str) -> Result<Self, Self::Err> { |
| 218 | + if val.is_empty() { |
| 219 | + return Ok(Temperature::from_celsius(0.0)); |
| 220 | + } |
| 221 | + |
| 222 | + let re = Regex::new(r"\s*([0-9.]*)\s?(deg|\u{00B0}|)?\s?([fckrFCKR]{1})\s*$").unwrap(); |
| 223 | + if let Some(caps) = re.captures(val) { |
| 224 | + let float_val = caps.get(1).unwrap().as_str(); |
| 225 | + return Ok( |
| 226 | + match caps.get(3).unwrap().as_str().to_uppercase().as_str() { |
| 227 | + "F" => Temperature::from_fahrenheit(float_val.parse::<f64>()?), |
| 228 | + "C" => Temperature::from_celsius(float_val.parse::<f64>()?), |
| 229 | + "K" => Temperature::from_kelvin(float_val.parse::<f64>()?), |
| 230 | + "R" => Temperature::from_rankine(float_val.parse::<f64>()?), |
| 231 | + _ => Temperature::from_celsius(val.parse::<f64>()?), |
| 232 | + }, |
| 233 | + ); |
| 234 | + } |
| 235 | + |
| 236 | + Ok(Temperature::from_celsius(val.parse::<f64>()?)) |
| 237 | + } |
| 238 | +} |
| 239 | + |
207 | 240 | implement_display!(Temperature);
|
208 | 241 | implement_measurement!(TemperatureDelta);
|
209 | 242 |
|
@@ -245,6 +278,113 @@ mod test {
|
245 | 278 | assert_almost_eq(o, 180.0);
|
246 | 279 | }
|
247 | 280 |
|
| 281 | + #[test] |
| 282 | + #[cfg(feature = "from_str")] |
| 283 | + fn empty_str() { |
| 284 | + let t = Temperature::from_str(""); |
| 285 | + assert!(t.is_ok()); |
| 286 | + |
| 287 | + let o = t.unwrap().as_celsius(); |
| 288 | + assert_eq!(o, 0.0); |
| 289 | + } |
| 290 | + |
| 291 | + #[test] |
| 292 | + #[cfg(feature = "from_str")] |
| 293 | + fn celsius_str() { |
| 294 | + let t = Temperature::from_str("100C"); |
| 295 | + assert!(t.is_ok()); |
| 296 | + |
| 297 | + let o = t.unwrap().as_celsius(); |
| 298 | + assert_almost_eq(o, 100.0); |
| 299 | + } |
| 300 | + |
| 301 | + #[test] |
| 302 | + #[cfg(feature = "from_str")] |
| 303 | + fn celsius_space_str() { |
| 304 | + let t = Temperature::from_str("100 C"); |
| 305 | + assert!(t.is_ok()); |
| 306 | + |
| 307 | + let o = t.unwrap().as_celsius(); |
| 308 | + assert_almost_eq(o, 100.0); |
| 309 | + } |
| 310 | + |
| 311 | + #[test] |
| 312 | + #[cfg(feature = "from_str")] |
| 313 | + fn celsius_degree_str() { |
| 314 | + let t = Temperature::from_str("100°C"); |
| 315 | + assert!(t.is_ok()); |
| 316 | + |
| 317 | + let o = t.unwrap().as_celsius(); |
| 318 | + assert_almost_eq(o, 100.0); |
| 319 | + } |
| 320 | + |
| 321 | + #[test] |
| 322 | + #[cfg(feature = "from_str")] |
| 323 | + fn fahrenheit_str() { |
| 324 | + let t = Temperature::from_str("100F"); |
| 325 | + assert!(t.is_ok()); |
| 326 | + |
| 327 | + let o = t.unwrap().as_fahrenheit(); |
| 328 | + assert_almost_eq(o, 100.0); |
| 329 | + } |
| 330 | + |
| 331 | + #[test] |
| 332 | + #[cfg(feature = "from_str")] |
| 333 | + fn fahrenheit_lc_str() { |
| 334 | + let t = Temperature::from_str("100 f"); |
| 335 | + assert!(t.is_ok()); |
| 336 | + |
| 337 | + let o = t.unwrap().as_fahrenheit(); |
| 338 | + assert_almost_eq(o, 100.0); |
| 339 | + } |
| 340 | + |
| 341 | + #[test] |
| 342 | + #[cfg(feature = "from_str")] |
| 343 | + fn fahrenheit_degree_str() { |
| 344 | + let t = Temperature::from_str("100 deg f"); |
| 345 | + assert!(t.is_ok()); |
| 346 | + |
| 347 | + let o = t.unwrap().as_fahrenheit(); |
| 348 | + assert_almost_eq(o, 100.0); |
| 349 | + } |
| 350 | + |
| 351 | + #[test] |
| 352 | + #[cfg(feature = "from_str")] |
| 353 | + fn rankine_str() { |
| 354 | + let t = Temperature::from_str("100R"); |
| 355 | + assert!(t.is_ok()); |
| 356 | + |
| 357 | + let o = t.unwrap().as_rankine(); |
| 358 | + assert_almost_eq(o, 100.0); |
| 359 | + } |
| 360 | + |
| 361 | + #[test] |
| 362 | + #[cfg(feature = "from_str")] |
| 363 | + fn rankine_degree_str() { |
| 364 | + let t = Temperature::from_str("100 °R"); |
| 365 | + assert!(t.is_ok()); |
| 366 | + |
| 367 | + let o = t.unwrap().as_rankine(); |
| 368 | + assert_almost_eq(o, 100.0); |
| 369 | + } |
| 370 | + |
| 371 | + #[test] |
| 372 | + #[cfg(feature = "from_str")] |
| 373 | + fn number_str() { |
| 374 | + let t = Temperature::from_str("100.5"); |
| 375 | + assert!(t.is_ok()); |
| 376 | + |
| 377 | + let o = t.unwrap().as_celsius(); |
| 378 | + assert_almost_eq(o, 100.5); |
| 379 | + } |
| 380 | + |
| 381 | + #[test] |
| 382 | + #[cfg(feature = "from_str")] |
| 383 | + fn invalid_str() { |
| 384 | + let t = Temperature::from_str("abcd"); |
| 385 | + assert!(t.is_err()); |
| 386 | + } |
| 387 | + |
248 | 388 | // Traits
|
249 | 389 | #[test]
|
250 | 390 | fn add() {
|
|
0 commit comments