unit_prefix/
parse.rs

1use core::{fmt, str};
2
3use super::{NumberPrefix, Prefix};
4
5
6impl<T: str::FromStr> str::FromStr for NumberPrefix<T> {
7    type Err = NumberPrefixParseError;
8
9    fn from_str(s: &str) -> Result<Self, Self::Err> {
10        let splitted = s.find(|p| {
11            p == 'k' || p == 'K' || p == 'M' || p == 'G' || p == 'T' || p == 'P' || p == 'E' || p == 'Z' || p == 'Y'
12        });
13
14        let num_prefix = s.split_at(splitted.unwrap_or(s.len()));
15        let num = match num_prefix.0.trim().parse::<T>() {
16            Ok(n) => n,
17            Err(_) => return Err(NumberPrefixParseError(())),
18        };
19
20        let prefix_unit = num_prefix.1.trim_matches(|p| p == 'b' || p == 'B' || p == 'm');
21
22        let prefix = match prefix_unit {
23            "k" | "K" => Prefix::Kilo,
24            "M" => Prefix::Mega,
25            "G" => Prefix::Giga,
26            "T" => Prefix::Tera,
27            "P" => Prefix::Peta,
28            "E" => Prefix::Exa,
29            "Z" => Prefix::Zetta,
30            "Y" => Prefix::Yotta,
31            "Ki" => Prefix::Kibi,
32            "Mi" => Prefix::Mebi,
33            "Gi" => Prefix::Gibi,
34            "Ti" => Prefix::Tebi,
35            "Pi" => Prefix::Pebi,
36            "Ei" => Prefix::Exbi,
37            "Zi" => Prefix::Zebi,
38            "Yi" => Prefix::Yobi,
39            "" => return Ok(NumberPrefix::Standalone(num)),
40            _ => return Err(NumberPrefixParseError(())),
41        };
42
43        Ok(NumberPrefix::Prefixed(prefix, num))
44    }
45}
46
47
48/// The error returned when a `NumberPrefix` is failed to be parsed.
49#[derive(Debug, Copy, Clone, PartialEq, Eq)]
50pub struct NumberPrefixParseError(());
51
52impl fmt::Display for NumberPrefixParseError {
53    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
54        fmt.write_str("invalid prefix syntax")
55    }
56}
57
58#[cfg(feature = "std")]
59impl std::error::Error for NumberPrefixParseError {}
60
61#[cfg(test)]
62mod test {
63    use super::*;
64
65    #[test]
66    fn parse_examples() {
67        let parse_example_a = "7.05E".parse::<NumberPrefix<f64>>();
68        let parse_example_b = "7.05".parse::<NumberPrefix<f64>>();
69        let parse_example_c = "7.05 GiB".parse::<NumberPrefix<f64>>();
70
71        assert_eq!(parse_example_a, Ok(NumberPrefix::Prefixed(Prefix::Exa, 7.05_f64)));
72        assert_eq!(parse_example_b, Ok(NumberPrefix::Standalone(7.05_f64)));
73        assert_eq!(parse_example_c, Ok(NumberPrefix::Prefixed(Prefix::Gibi, 7.05_f64)));
74    }
75
76    #[test]
77    fn bad_parse() {
78        let parsed = "bogo meters per second".parse::<NumberPrefix<f64>>();
79
80        assert_ne!(parsed, Ok(NumberPrefix::Prefixed(Prefix::Kilo, 7.05_f64)));
81    }
82}