bxvl 0.1.1

A datatype library that allows for measurement unit association, conversion, and operations for values.
Documentation
use crate::errors::V3Error;

use super::Metric;

impl Metric {
    /// Returns the numeric scaling of a given metric prefix
    pub fn scale(&self) -> f64 {
        match self {
            Metric::Quetta => 1.0e30,
            Metric::Ronna => 1.0e27,
            Metric::Yotta => 1.0e24,
            Metric::Zetta => 1.0e21,
            Metric::Exa => 1.0e18,
            Metric::Peta => 1.0e15,
            Metric::Tera => 1.0e12,
            Metric::Giga => 1.0e9,
            Metric::Mega => 1.0e6,
            Metric::Kilo => 1.0e3,
            Metric::Hecto => 1.0e2,
            Metric::Deca => 10.0,
            Metric::None => 1.0,
            Metric::Deci => 0.1,
            Metric::Centi => 0.01,
            Metric::Milli => 1.0e-3,
            Metric::Micro => 1.0e-6,
            Metric::Nano => 1.0e-9,
            Metric::Pico => 1.0e-12,
            Metric::Femto => 1.0e-15,
            Metric::Atto => 1.0e-18,
            Metric::Zepto => 1.0e-21,
            Metric::Yocto => 1.0e-24,
            Metric::Ronto => 1.0e-27,
            Metric::Quecto => 1.0e-30,
        }
    }

    /// Returns the string representation of the metric prefix
    pub fn as_str(&self) -> &str {
        match self {
            Metric::Quetta => "Q",
            Metric::Ronna => "R",
            Metric::Yotta => "Y",
            Metric::Zetta => "Z",
            Metric::Exa => "E",
            Metric::Peta => "P",
            Metric::Tera => "T",
            Metric::Giga => "G",
            Metric::Mega => "M",
            Metric::Kilo => "k",
            Metric::Hecto => "h",
            Metric::Deca => "da",
            Metric::None => "",
            Metric::Deci => "d",
            Metric::Centi => "c",
            Metric::Milli => "m",
            Metric::Micro => "μ",
            Metric::Nano => "n",
            Metric::Pico => "p",
            Metric::Femto => "f",
            Metric::Atto => "a",
            Metric::Zepto => "z",
            Metric::Yocto => "y",
            Metric::Ronto => "r",
            Metric::Quecto => "q",
        }
    }
}

impl TryFrom<&str> for Metric {
    type Error = V3Error;
    fn try_from(m: &str) -> Result<Self, Self::Error> {
        if m.chars().count() > 2 {
            Err(V3Error::ParsingError("Invalid metric prefix".into()))
        } else if m.chars().count() > 1 {
            if m.chars().nth(0) == Some('d') && m.chars().nth(1) == Some('a') {
                Ok(Metric::Deca)
            } else {
                Err(V3Error::ParsingError("Invalid metric prefix".into()))
            }
        } else {
            match m.chars().nth(0).unwrap() {
                'Q' => Ok(Metric::Quetta),
                'R' => Ok(Metric::Ronna),
                'Y' => Ok(Metric::Yotta),
                'Z' => Ok(Metric::Zetta),
                'E' => Ok(Metric::Exa),
                'P' => Ok(Metric::Peta),
                'T' => Ok(Metric::Tera),
                'G' => Ok(Metric::Giga),
                'M' => Ok(Metric::Mega),
                'k' => Ok(Metric::Kilo),
                'h' => Ok(Metric::Hecto),
                'd' => Ok(Metric::Deci),
                'c' => Ok(Metric::Centi),
                'm' => Ok(Metric::Milli),
                'u' | 'μ' => Ok(Metric::Micro),
                'n' => Ok(Metric::Nano),
                'p' => Ok(Metric::Pico),
                'f' => Ok(Metric::Femto),
                'a' => Ok(Metric::Atto),
                'z' => Ok(Metric::Zepto),
                'y' => Ok(Metric::Yocto),
                'r' => Ok(Metric::Ronto),
                'q' => Ok(Metric::Quecto),
                _ => Err(V3Error::ParsingError("Invalid metric prefix".into())),
            }
        }
    }
}

#[cfg(test)]
mod metric_testing {
    use crate::units::Metric;

    #[test]
    fn metric_comparison() {
        assert!(Metric::Quecto < Metric::Ronto);
        assert!(Metric::Ronto < Metric::Yocto);
        assert!(Metric::Yocto < Metric::Zepto);
        assert!(Metric::Zepto < Metric::Atto);
        assert!(Metric::Atto < Metric::Femto);
        assert!(Metric::Femto < Metric::Pico);
        assert!(Metric::Pico < Metric::Nano);
        assert!(Metric::Nano < Metric::Micro);
        assert!(Metric::Micro < Metric::Milli);
        assert!(Metric::Milli < Metric::Centi);
        assert!(Metric::Centi < Metric::Deci);
        assert!(Metric::Deci < Metric::None);
        assert!(Metric::None < Metric::Deca);
        assert!(Metric::Deca < Metric::Hecto);
        assert!(Metric::Hecto < Metric::Kilo);
        assert!(Metric::Kilo < Metric::Mega);
        assert!(Metric::Mega < Metric::Giga);
        assert!(Metric::Giga < Metric::Tera);
        assert!(Metric::Tera < Metric::Peta);
        assert!(Metric::Peta < Metric::Exa);
        assert!(Metric::Exa < Metric::Zetta);
        assert!(Metric::Zetta < Metric::Yotta);
        assert!(Metric::Yotta < Metric::Ronna);
        assert!(Metric::Ronna < Metric::Quetta);
    }

    #[test]
    fn metric_comparison_scale() {
        assert!(Metric::Quecto.scale() < Metric::Ronto.scale());
        assert!(Metric::Ronto.scale() < Metric::Yocto.scale());
        assert!(Metric::Yocto.scale() < Metric::Zepto.scale());
        assert!(Metric::Zepto.scale() < Metric::Atto.scale());
        assert!(Metric::Atto.scale() < Metric::Femto.scale());
        assert!(Metric::Femto.scale() < Metric::Pico.scale());
        assert!(Metric::Pico.scale() < Metric::Nano.scale());
        assert!(Metric::Nano.scale() < Metric::Micro.scale());
        assert!(Metric::Micro.scale() < Metric::Milli.scale());
        assert!(Metric::Milli.scale() < Metric::Centi.scale());
        assert!(Metric::Centi.scale() < Metric::Deci.scale());
        assert!(Metric::Deci.scale() < Metric::None.scale());
        assert!(Metric::None.scale() < Metric::Deca.scale());
        assert!(Metric::Deca.scale() < Metric::Hecto.scale());
        assert!(Metric::Hecto.scale() < Metric::Kilo.scale());
        assert!(Metric::Kilo.scale() < Metric::Mega.scale());
        assert!(Metric::Mega.scale() < Metric::Giga.scale());
        assert!(Metric::Giga.scale() < Metric::Tera.scale());
        assert!(Metric::Tera.scale() < Metric::Peta.scale());
        assert!(Metric::Peta.scale() < Metric::Exa.scale());
        assert!(Metric::Exa.scale() < Metric::Zetta.scale());
        assert!(Metric::Zetta.scale() < Metric::Yotta.scale());
        assert!(Metric::Yotta.scale() < Metric::Ronna.scale());
        assert!(Metric::Ronna.scale() < Metric::Quetta.scale());
    }

    #[test]
    fn metric_string_scale() {
        assert_eq!(Metric::try_from("Q").unwrap(), Metric::Quetta);
        assert_eq!(Metric::try_from("R").unwrap(), Metric::Ronna);
        assert_eq!(Metric::try_from("Y").unwrap(), Metric::Yotta);
        assert_eq!(Metric::try_from("Z").unwrap(), Metric::Zetta);
        assert_eq!(Metric::try_from("E").unwrap(), Metric::Exa);
        assert_eq!(Metric::try_from("P").unwrap(), Metric::Peta);
        assert_eq!(Metric::try_from("T").unwrap(), Metric::Tera);
        assert_eq!(Metric::try_from("G").unwrap(), Metric::Giga);
        assert_eq!(Metric::try_from("M").unwrap(), Metric::Mega);
        assert_eq!(Metric::try_from("k").unwrap(), Metric::Kilo);
        assert_eq!(Metric::try_from("h").unwrap(), Metric::Hecto);
        assert_eq!(Metric::try_from("d").unwrap(), Metric::Deci);
        assert_eq!(Metric::try_from("c").unwrap(), Metric::Centi);
        assert_eq!(Metric::try_from("μ").unwrap(), Metric::Micro);
        assert_eq!(Metric::try_from("u").unwrap(), Metric::Micro);
        assert_eq!(Metric::try_from("n").unwrap(), Metric::Nano);
        assert_eq!(Metric::try_from("p").unwrap(), Metric::Pico);
        assert_eq!(Metric::try_from("f").unwrap(), Metric::Femto);
        assert_eq!(Metric::try_from("a").unwrap(), Metric::Atto);
        assert_eq!(Metric::try_from("z").unwrap(), Metric::Zepto);
        assert_eq!(Metric::try_from("y").unwrap(), Metric::Yocto);
        assert_eq!(Metric::try_from("da").unwrap(), Metric::Deca);
        assert_eq!(Metric::try_from("m").unwrap(), Metric::Milli);
        assert_eq!(Metric::try_from("r").unwrap(), Metric::Ronto);
        assert_eq!(Metric::try_from("q").unwrap(), Metric::Quecto);
    }

    #[test]
    fn metric_string_scale_fails() {
        assert!(Metric::try_from("bb").is_err());
        assert!(Metric::try_from("K").is_err());
        assert!(Metric::try_from("aaa").is_err());
        assert!(Metric::try_from("de").is_err());
        assert!(Metric::try_from("fa").is_err());
    }
}