Skip to content

Commit 8df4f80

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

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

src/mass.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
//! Types and constants for handling masses.
22
33
use super::measurement::*;
4+
#[cfg(feature = "from_str")]
5+
use regex::Regex;
6+
#[cfg(feature = "from_str")]
7+
use std::str::FromStr;
48

59
// Constants, metric
610

@@ -252,6 +256,42 @@ impl Measurement for Mass {
252256
}
253257
}
254258

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+
255295
implement_measurement! { Mass }
256296

257297
#[cfg(test)]
@@ -485,4 +525,91 @@ mod test {
485525
assert_eq!(a >= b, false);
486526
}
487527

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

0 commit comments

Comments
 (0)