Skip to content

Commit eeda61f

Browse files
drodileldruin
authored andcommitted
Add support to create Area from string
Again behind the from_str feature. Tests included.
1 parent 8df4f80 commit eeda61f

File tree

1 file changed

+153
-1
lines changed

1 file changed

+153
-1
lines changed

src/area.rs

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
//! Types and constants for handling areas.
22
3-
use super::measurement::*;
43
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;
59

610
/// Number of acres in a square meter
711
const SQUARE_METER_ACRE_FACTOR: f64 = 1.0 / 4046.86;
@@ -303,6 +307,56 @@ impl Measurement for Area {
303307
}
304308
}
305309

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+
306360
implement_measurement! { Area }
307361

308362
#[cfg(test)]
@@ -530,4 +584,102 @@ mod test {
530584
assert_almost_eq(r2, 258998704.7);
531585
}
532586

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+
}
533685
}

0 commit comments

Comments
 (0)