|
1 | 1 | //! Types and constants for handling masses.
|
2 | 2 |
|
3 | 3 | use super::measurement::*;
|
| 4 | +#[cfg(feature = "from_str")] |
| 5 | +use regex::Regex; |
| 6 | +#[cfg(feature = "from_str")] |
| 7 | +use std::str::FromStr; |
4 | 8 |
|
5 | 9 | // Constants, metric
|
6 | 10 |
|
@@ -252,6 +256,42 @@ impl Measurement for Mass {
|
252 | 256 | }
|
253 | 257 | }
|
254 | 258 |
|
| 259 | +#[cfg(feature = "from_str")] |
| 260 | +impl FromStr for Mass { |
| 261 | + type Err = std::num::ParseFloatError; |
| 262 | + |
| 263 | + /// Create a new Mass from a string |
| 264 | + /// Plain numbers in string are considered to be Kilograms |
| 265 | + fn from_str(val: &str) -> Result<Self, Self::Err> { |
| 266 | + if val.is_empty() { |
| 267 | + return Ok(Mass::from_kilograms(0.0)); |
| 268 | + } |
| 269 | + |
| 270 | + let re = Regex::new(r"(?i)\s*([0-9.]*)\s?([a-zμ]{1,3})\s*$").unwrap(); |
| 271 | + if let Some(caps) = re.captures(val) { |
| 272 | + let float_val = caps.get(1).unwrap().as_str(); |
| 273 | + return Ok( |
| 274 | + match caps.get(2).unwrap().as_str().to_lowercase().as_str() { |
| 275 | + "ug" | "μg" => Mass::from_micrograms(float_val.parse::<f64>()?), |
| 276 | + "mg" => Mass::from_milligrams(float_val.parse::<f64>()?), |
| 277 | + "ct" => Mass::from_carats(float_val.parse::<f64>()?), |
| 278 | + "g" => Mass::from_grams(float_val.parse::<f64>()?), |
| 279 | + "kg" => Mass::from_kilograms(float_val.parse::<f64>()?), |
| 280 | + "t" => Mass::from_metric_tons(float_val.parse::<f64>()?), |
| 281 | + "gr" => Mass::from_grains(float_val.parse::<f64>()?), |
| 282 | + "dwt" => Mass::from_pennyweights(float_val.parse::<f64>()?), |
| 283 | + "oz" => Mass::from_ounces(float_val.parse::<f64>()?), |
| 284 | + "st" => Mass::from_stones(float_val.parse::<f64>()?), |
| 285 | + "lbs" => Mass::from_pounds(float_val.parse::<f64>()?), |
| 286 | + _ => Mass::from_grams(float_val.parse::<f64>()?), |
| 287 | + }, |
| 288 | + ); |
| 289 | + } |
| 290 | + |
| 291 | + Ok(Mass::from_kilograms(val.parse::<f64>()?)) |
| 292 | + } |
| 293 | +} |
| 294 | + |
255 | 295 | implement_measurement! { Mass }
|
256 | 296 |
|
257 | 297 | #[cfg(test)]
|
@@ -485,4 +525,91 @@ mod test {
|
485 | 525 | assert_eq!(a >= b, false);
|
486 | 526 | }
|
487 | 527 |
|
| 528 | + #[test] |
| 529 | + #[cfg(feature = "from_str")] |
| 530 | + fn number_str() { |
| 531 | + let t = Mass::from_str("100.5"); |
| 532 | + assert!(t.is_ok()); |
| 533 | + let o = t.unwrap().as_kilograms(); |
| 534 | + assert_almost_eq(o, 100.5); |
| 535 | + } |
| 536 | + |
| 537 | + #[test] |
| 538 | + #[cfg(feature = "from_str")] |
| 539 | + fn micrograms_from_string() { |
| 540 | + assert_almost_eq(123.0, Mass::from_str(" 123ug ").unwrap().as_micrograms()); |
| 541 | + assert_almost_eq(123.0, Mass::from_str("123 ug ").unwrap().as_micrograms()); |
| 542 | + assert_almost_eq(123.0, Mass::from_str(" 123μg").unwrap().as_micrograms()); |
| 543 | + assert_almost_eq(123.0, Mass::from_str("123 μg").unwrap().as_micrograms()); |
| 544 | + } |
| 545 | + |
| 546 | + #[test] |
| 547 | + #[cfg(feature = "from_str")] |
| 548 | + fn milligrams_from_string() { |
| 549 | + assert_almost_eq(123.0, Mass::from_str("123mg").unwrap().as_milligrams()); |
| 550 | + assert_almost_eq(123.0, Mass::from_str("123 mg").unwrap().as_milligrams()); |
| 551 | + } |
| 552 | + |
| 553 | + #[test] |
| 554 | + #[cfg(feature = "from_str")] |
| 555 | + fn carats_from_string() { |
| 556 | + assert_almost_eq(123.0, Mass::from_str("123ct").unwrap().as_carats()); |
| 557 | + assert_almost_eq(123.0, Mass::from_str("123 ct").unwrap().as_carats()); |
| 558 | + } |
| 559 | + |
| 560 | + #[test] |
| 561 | + #[cfg(feature = "from_str")] |
| 562 | + fn grams_from_string() { |
| 563 | + assert_almost_eq(123.0, Mass::from_str("123g").unwrap().as_grams()); |
| 564 | + assert_almost_eq(123.0, Mass::from_str("123 g").unwrap().as_grams()); |
| 565 | + } |
| 566 | + |
| 567 | + #[test] |
| 568 | + #[cfg(feature = "from_str")] |
| 569 | + fn kilograms_from_string() { |
| 570 | + assert_almost_eq(123.0, Mass::from_str("123kg").unwrap().as_kilograms()); |
| 571 | + assert_almost_eq(123.0, Mass::from_str("123 kg").unwrap().as_kilograms()); |
| 572 | + } |
| 573 | + |
| 574 | + #[test] |
| 575 | + #[cfg(feature = "from_str")] |
| 576 | + fn tonnes_from_string() { |
| 577 | + assert_almost_eq(123.0, Mass::from_str("123T").unwrap().as_tonnes()); |
| 578 | + assert_almost_eq(123.0, Mass::from_str("123 T").unwrap().as_tonnes()); |
| 579 | + } |
| 580 | + |
| 581 | + #[test] |
| 582 | + #[cfg(feature = "from_str")] |
| 583 | + fn grains_from_string() { |
| 584 | + assert_almost_eq(123.0, Mass::from_str("123gr").unwrap().as_grains()); |
| 585 | + assert_almost_eq(123.0, Mass::from_str("123 gr").unwrap().as_grains()); |
| 586 | + } |
| 587 | + |
| 588 | + #[test] |
| 589 | + #[cfg(feature = "from_str")] |
| 590 | + fn pennyweights_from_string() { |
| 591 | + assert_almost_eq(123.0, Mass::from_str("123dwt").unwrap().as_pennyweights()); |
| 592 | + assert_almost_eq(123.0, Mass::from_str("123 dwt").unwrap().as_pennyweights()); |
| 593 | + } |
| 594 | + |
| 595 | + #[test] |
| 596 | + #[cfg(feature = "from_str")] |
| 597 | + fn ounces_from_string() { |
| 598 | + assert_almost_eq(123.0, Mass::from_str("123oz").unwrap().as_ounces()); |
| 599 | + assert_almost_eq(123.0, Mass::from_str("123 oz").unwrap().as_ounces()); |
| 600 | + } |
| 601 | + |
| 602 | + #[test] |
| 603 | + #[cfg(feature = "from_str")] |
| 604 | + fn pounds_from_string() { |
| 605 | + assert_almost_eq(123.0, Mass::from_str("123lbs").unwrap().as_pounds()); |
| 606 | + assert_almost_eq(123.0, Mass::from_str("123 lbs").unwrap().as_pounds()); |
| 607 | + } |
| 608 | + |
| 609 | + #[test] |
| 610 | + #[cfg(feature = "from_str")] |
| 611 | + fn invalid_str() { |
| 612 | + let t = Mass::from_str("abcd"); |
| 613 | + assert!(t.is_err()); |
| 614 | + } |
488 | 615 | }
|
0 commit comments