|
1 | 1 | //! Types and constants for handling areas.
|
2 | 2 |
|
3 |
| -use super::measurement::*; |
4 | 3 | use super::length;
|
| 4 | +use super::measurement::*; |
| 5 | +#[cfg(feature = "from_str")] |
| 6 | +use regex::Regex; |
| 7 | +#[cfg(feature = "from_str")] |
| 8 | +use std::str::FromStr; |
5 | 9 |
|
6 | 10 | /// Number of acres in a square meter
|
7 | 11 | const SQUARE_METER_ACRE_FACTOR: f64 = 1.0 / 4046.86;
|
@@ -303,6 +307,56 @@ impl Measurement for Area {
|
303 | 307 | }
|
304 | 308 | }
|
305 | 309 |
|
| 310 | +#[cfg(feature = "from_str")] |
| 311 | +impl FromStr for Area { |
| 312 | + type Err = std::num::ParseFloatError; |
| 313 | + |
| 314 | + /// Create a new Area from a string |
| 315 | + /// Plain numbers in string are considered to be square meters |
| 316 | + fn from_str(val: &str) -> Result<Self, Self::Err> { |
| 317 | + if val.is_empty() { |
| 318 | + return Ok(Area::from_square_meters(0.0)); |
| 319 | + } |
| 320 | + |
| 321 | + let re = Regex::new(r"(?i)\s*([0-9.]*)\s?([a-z2\u{00B2}\u{00B5} ]{1,5})\s*$").unwrap(); |
| 322 | + if let Some(caps) = re.captures(val) { |
| 323 | + println!("{:?}", caps); |
| 324 | + let float_val = caps.get(1).unwrap().as_str(); |
| 325 | + return Ok( |
| 326 | + match caps.get(2).unwrap().as_str().trim().to_lowercase().as_str() { |
| 327 | + "nm\u{00B2}" | "nm2" => Area::from_square_nanometers(float_val.parse::<f64>()?), |
| 328 | + "\u{00B5}m\u{00B2}" | "\u{00B5}m2" | "um\u{00B2}" | "um2" => { |
| 329 | + Area::from_square_micrometers(float_val.parse::<f64>()?) |
| 330 | + } |
| 331 | + "mm\u{00B2}" | "mm2" => { |
| 332 | + Area::from_square_millimeters(float_val.parse::<f64>()?) |
| 333 | + } |
| 334 | + "cm\u{00B2}" | "cm2" => { |
| 335 | + Area::from_square_centimeters(float_val.parse::<f64>()?) |
| 336 | + } |
| 337 | + "dm\u{00B2}" | "dm2" => Area::from_square_decimeters(float_val.parse::<f64>()?), |
| 338 | + "m\u{00B2}" | "m2" => Area::from_square_meters(float_val.parse::<f64>()?), |
| 339 | + "km\u{00B2}" | "km2" => Area::from_square_kilometers(float_val.parse::<f64>()?), |
| 340 | + "ha" | "hm\u{00B2}" | "hm2" => Area::from_hectares(float_val.parse::<f64>()?), |
| 341 | + "acre" | "ac" => Area::from_acres(float_val.parse::<f64>()?), |
| 342 | + "ft\u{00B2}" | "ft2" | "sq ft" => { |
| 343 | + Area::from_square_feet(float_val.parse::<f64>()?) |
| 344 | + } |
| 345 | + "yd\u{00B2}" | "yd2" | "sq yd" => { |
| 346 | + Area::from_square_yards(float_val.parse::<f64>()?) |
| 347 | + } |
| 348 | + "mi\u{00B2}" | "mi2" | "sq mi" => { |
| 349 | + Area::from_square_miles(float_val.parse::<f64>()?) |
| 350 | + } |
| 351 | + _ => Area::from_square_meters(val.parse::<f64>()?), |
| 352 | + }, |
| 353 | + ); |
| 354 | + } |
| 355 | + |
| 356 | + Ok(Area::from_square_meters(val.parse::<f64>()?)) |
| 357 | + } |
| 358 | +} |
| 359 | + |
306 | 360 | implement_measurement! { Area }
|
307 | 361 |
|
308 | 362 | #[cfg(test)]
|
@@ -530,4 +584,102 @@ mod test {
|
530 | 584 | assert_almost_eq(r2, 258998704.7);
|
531 | 585 | }
|
532 | 586 |
|
| 587 | + #[test] |
| 588 | + #[cfg(feature = "from_str")] |
| 589 | + fn empty_str() { |
| 590 | + let t = Area::from_str(""); |
| 591 | + assert!(t.is_ok()); |
| 592 | + let o = t.unwrap().as_square_meters(); |
| 593 | + assert_eq!(o, 0.0); |
| 594 | + } |
| 595 | + |
| 596 | + #[test] |
| 597 | + #[cfg(feature = "from_str")] |
| 598 | + fn invalid_str() { |
| 599 | + let t = Area::from_str("abcd"); |
| 600 | + assert!(t.is_err()); |
| 601 | + } |
| 602 | + |
| 603 | + #[test] |
| 604 | + #[cfg(feature = "from_str")] |
| 605 | + fn square_nanometer_str() { |
| 606 | + let t = Area::from_str(" 100.0 nm2"); |
| 607 | + assert_almost_eq(t.unwrap().as_square_nanometers(), 100.0); |
| 608 | + } |
| 609 | + |
| 610 | + #[test] |
| 611 | + #[cfg(feature = "from_str")] |
| 612 | + fn square_micrometer_str() { |
| 613 | + let t = Area::from_str(" 100.0 um2"); |
| 614 | + assert_almost_eq(t.unwrap().as_square_micrometers(), 100.0); |
| 615 | + } |
| 616 | + |
| 617 | + #[test] |
| 618 | + #[cfg(feature = "from_str")] |
| 619 | + fn square_millimeter_str() { |
| 620 | + let t = Area::from_str(" 100.0 mm2"); |
| 621 | + assert_almost_eq(t.unwrap().as_square_millimeters(), 100.0); |
| 622 | + } |
| 623 | + |
| 624 | + #[test] |
| 625 | + #[cfg(feature = "from_str")] |
| 626 | + fn square_centimeter_str() { |
| 627 | + let t = Area::from_str(" 100.0 cm2 "); |
| 628 | + assert_almost_eq(t.unwrap().as_square_centimeters(), 100.0); |
| 629 | + } |
| 630 | + #[test] |
| 631 | + #[cfg(feature = "from_str")] |
| 632 | + fn square_decimeter_str() { |
| 633 | + let t = Area::from_str(" 100.0 dm2"); |
| 634 | + assert_almost_eq(t.unwrap().as_square_decimeters(), 100.0); |
| 635 | + } |
| 636 | + |
| 637 | + #[test] |
| 638 | + #[cfg(feature = "from_str")] |
| 639 | + fn square_meter_str() { |
| 640 | + let t = Area::from_str(" 100.0 m2 "); |
| 641 | + assert_almost_eq(t.unwrap().as_square_meters(), 100.0); |
| 642 | + } |
| 643 | + |
| 644 | + #[test] |
| 645 | + #[cfg(feature = "from_str")] |
| 646 | + fn square_hectometer_str() { |
| 647 | + let t = Area::from_str(" 100.0 ha "); |
| 648 | + assert_almost_eq(t.unwrap().as_square_hectometers(), 100.0); |
| 649 | + } |
| 650 | + |
| 651 | + #[test] |
| 652 | + #[cfg(feature = "from_str")] |
| 653 | + fn square_kilometer_str() { |
| 654 | + let t = Area::from_str(" 100.0 km\u{00B2} "); |
| 655 | + assert_almost_eq(t.unwrap().as_square_kilometers(), 100.0); |
| 656 | + } |
| 657 | + |
| 658 | + #[test] |
| 659 | + #[cfg(feature = "from_str")] |
| 660 | + fn square_feet_str() { |
| 661 | + let t = Area::from_str(" 100.0 ft\u{00B2} "); |
| 662 | + assert_almost_eq(t.unwrap().as_square_feet(), 100.0); |
| 663 | + } |
| 664 | + |
| 665 | + #[test] |
| 666 | + #[cfg(feature = "from_str")] |
| 667 | + fn square_yard_str() { |
| 668 | + let t = Area::from_str(" 100.0 sq yd "); |
| 669 | + assert_almost_eq(t.unwrap().as_square_yards(), 100.0); |
| 670 | + } |
| 671 | + |
| 672 | + #[test] |
| 673 | + #[cfg(feature = "from_str")] |
| 674 | + fn square_mile_str() { |
| 675 | + let t = Area::from_str(" 100.0 sq mi "); |
| 676 | + assert_almost_eq(t.unwrap().as_square_miles(), 100.0); |
| 677 | + } |
| 678 | + |
| 679 | + #[test] |
| 680 | + #[cfg(feature = "from_str")] |
| 681 | + fn acre_str() { |
| 682 | + let t = Area::from_str(" 100.0 acre "); |
| 683 | + assert_almost_eq(t.unwrap().as_acres(), 100.0); |
| 684 | + } |
533 | 685 | }
|
0 commit comments