unit-prefix-0.5.1/.cargo_vcs_info.json0000644000000001360000000000100133110ustar { "git": { "sha1": "c90eb3c404755da92e22a2893c66892b3339d5c6" }, "path_in_vcs": "" }unit-prefix-0.5.1/.gitignore000064400000000000000000000000241046102023000140650ustar 00000000000000/target /Cargo.lock unit-prefix-0.5.1/Cargo.lock0000644000000002330000000000100112620ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "unit-prefix" version = "0.5.1" unit-prefix-0.5.1/Cargo.toml0000644000000023160000000000100113110ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.31.0" name = "unit-prefix" version = "0.5.1" authors = [ "Fabio Valentini ", "Benjamin Sago ", ] build = false exclude = [ "/Cargo.lock", "/rustfmt.toml", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Format numbers with metric and binary unit prefixes" readme = "README.md" keywords = [ "mathematics", "numerics", ] categories = [ "algorithms", "no-std", ] license = "MIT" repository = "https://github.com/commons-rs/unit-prefix" [lib] name = "unit_prefix" path = "src/lib.rs" [[example]] name = "conversions" path = "examples/conversions.rs" [features] default = ["std"] std = [] unit-prefix-0.5.1/Cargo.toml.orig000064400000000000000000000010541046102023000147700ustar 00000000000000[package] name = "unit-prefix" description = "Format numbers with metric and binary unit prefixes" license = "MIT" version = "0.5.1" edition = "2018" rust-version = "1.31.0" authors = [ "Fabio Valentini ", "Benjamin Sago ", ] readme = "README.md" exclude = [ "/Cargo.lock", "/rustfmt.toml", ] categories = ["algorithms", "no-std"] keywords = ["mathematics", "numerics"] repository = "https://github.com/commons-rs/unit-prefix" [[example]] name = "conversions" [features] default = ["std"] std = [] unit-prefix-0.5.1/LICENSE000064400000000000000000000020771046102023000131140ustar 00000000000000MIT License Copyright (c) 2024 Benjamin Sago, Fabio Valentini Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. unit-prefix-0.5.1/README.md000064400000000000000000000005111046102023000133550ustar 00000000000000# unit-prefix This project is a fork / continuation of the unmaintained [number_prefix](https://crates.io/crates/number_prefix) crate. The minimum supported Rust version is currently 1.31 (matching the release of the 2018 edition). API documentation and usage examples are available on [docs.rs](https://docs.rs/unit-prefix). unit-prefix-0.5.1/examples/conversions.rs000064400000000000000000000041351046102023000166400ustar 00000000000000//! This example prints out the conversions for increasingly-large numbers, to //! showcase how the numbers change as the input gets bigger. //! It results in this: //! //! ```text //! 1000 bytes is 1.000 kB and 1000 bytes //! 1000000 bytes is 1.000 MB and 976.562 KiB //! 1000000000 bytes is 1.000 GB and 953.674 MiB //! 1000000000000 bytes is 1.000 TB and 931.323 GiB //! 1000000000000000 bytes is 1.000 PB and 909.495 TiB //! 1000000000000000000 bytes is 1.000 EB and 888.178 PiB //! 1000000000000000000000 bytes is 1.000 ZB and 867.362 EiB //! 1000000000000000000000000 bytes is 1.000 YB and 847.033 ZiB //! //! 1024 bytes is 1.000 KiB and 1.024 kB //! 1048576 bytes is 1.000 MiB and 1.049 MB //! 1073741824 bytes is 1.000 GiB and 1.074 GB //! 1099511627776 bytes is 1.000 TiB and 1.100 TB //! 1125899906842624 bytes is 1.000 PiB and 1.126 PB //! 1152921504606847000 bytes is 1.000 EiB and 1.153 EB //! 1180591620717411300000 bytes is 1.000 ZiB and 1.181 ZB //! 1208925819614629200000000 bytes is 1.000 YiB and 1.209 YB //! ``` use core::fmt::Display; use unit_prefix::NumberPrefix; fn main() { // part one, decimal prefixes let mut n = 1_f64; for _ in 0..8 { n *= 1000_f64; let decimal = format_prefix(NumberPrefix::decimal(n)); let binary = format_prefix(NumberPrefix::binary(n)); println!("{:26} bytes is {} and {:10}", n, decimal, binary); } println!(); // part two, binary prefixes let mut n = 1_f64; for _ in 0..8 { n *= 1024_f64; let decimal = format_prefix(NumberPrefix::decimal(n)); let binary = format_prefix(NumberPrefix::binary(n)); println!("{:26} bytes is {} and {:10}", n, binary, decimal); } } fn format_prefix(np: NumberPrefix) -> String { match np { NumberPrefix::Prefixed(prefix, n) => format!("{:.3} {}B", n, prefix), NumberPrefix::Standalone(bytes) => format!("{} bytes", bytes), } } unit-prefix-0.5.1/src/lib.rs000064400000000000000000000427241046102023000140150ustar 00000000000000#![deny(unsafe_code)] #![warn(missing_copy_implementations)] #![warn(missing_debug_implementations)] #![warn(missing_docs)] #![warn(nonstandard_style)] #![warn(trivial_numeric_casts)] #![warn(unreachable_pub)] #![warn(unused)] //! This is a library for formatting numbers with numeric prefixes, such as //! turning “3000 metres” into “3 kilometres”, or “8705 bytes” into “8.5 KiB”. //! //! //! # Usage //! //! The function [`NumberPrefix::decimal`](enum.NumberPrefix.html#method.decimal) //! returns either a pair of the resulting number and its prefix, or a //! notice that the number was too small to have any prefix applied to it. For //! example: //! //! ``` //! use unit_prefix::NumberPrefix; //! //! let amount = 8542_f32; //! let result = match NumberPrefix::decimal(amount) { //! NumberPrefix::Standalone(bytes) => { //! format!("The file is {} bytes in size", bytes) //! }, //! NumberPrefix::Prefixed(prefix, n) => { //! format!("The file is {:.1} {}B in size", n, prefix) //! }, //! }; //! //! assert_eq!("The file is 8.5 kB in size", result); //! ``` //! //! The `{:.1}` part of the formatting string tells it to restrict the //! output to only one decimal place. This value is calculated by repeatedly //! dividing the number by 1000 until it becomes less than that, which in this //! case results in 8.542, which gets rounded down. Because only one division //! had to take place, the function also returns the decimal prefix `Kilo`, //! which gets converted to its internationally-recognised symbol when //! formatted as a string. //! //! If the value is too small to have any prefixes applied to it — in this case, //! if it’s under 1000 — then the standalone value will be returned: //! //! ``` //! use unit_prefix::NumberPrefix; //! //! let amount = 705_f32; //! let result = match NumberPrefix::decimal(amount) { //! NumberPrefix::Standalone(bytes) => { //! format!("The file is {} bytes in size", bytes) //! }, //! NumberPrefix::Prefixed(prefix, n) => { //! format!("The file is {:.1} {}B in size", n, prefix) //! }, //! }; //! //! assert_eq!("The file is 705 bytes in size", result); //! ``` //! //! In this particular example, the user expects different formatting for //! both bytes and kilobytes: while prefixed values are given more precision, //! there’s no point using anything other than whole numbers for just byte //! amounts. This is why the function pays attention to values without any //! prefixes — they often need to be special-cased. //! //! //! ## Binary Prefixes //! //! This library also allows you to use the *binary prefixes*, which use the //! number 1024 (210) as the multiplier, rather than the more common 1000 //! (103). This uses the //! [`NumberPrefix::binary`](enum.NumberPrefix.html#method.binary) function. //! For example: //! //! ``` //! use unit_prefix::NumberPrefix; //! //! let amount = 8542_f32; //! let result = match NumberPrefix::binary(amount) { //! NumberPrefix::Standalone(bytes) => { //! format!("The file is {} bytes in size", bytes) //! }, //! NumberPrefix::Prefixed(prefix, n) => { //! format!("The file is {:.1} {}B in size", n, prefix) //! }, //! }; //! //! assert_eq!("The file is 8.3 KiB in size", result); //! ``` //! //! A kibibyte is slightly larger than a kilobyte, so the number is smaller //! in the result; but other than that, it works in exactly the same way, with //! the binary prefix being converted to a symbol automatically. //! //! //! ## Which type of prefix should I use? //! //! There is no correct answer this question! Common practice is to use //! the binary prefixes for numbers of *bytes*, while still using the decimal //! prefixes for everything else. Computers work with powers of two, rather than //! powers of ten, and by using the binary prefixes, you get a more accurate //! representation of the amount of data. //! //! //! ## Prefix Names //! //! If you need to describe your unit in actual words, rather than just with the //! symbol, use one of the `upper`, `caps`, `lower`, or `symbol`, which output the //! prefix in a variety of formats. For example: //! //! ``` //! use unit_prefix::NumberPrefix; //! //! let amount = 8542_f32; //! let result = match NumberPrefix::decimal(amount) { //! NumberPrefix::Standalone(bytes) => { //! format!("The file is {} bytes in size", bytes) //! }, //! NumberPrefix::Prefixed(prefix, n) => { //! format!("The file is {:.1} {}bytes in size", n, prefix.lower()) //! }, //! }; //! //! assert_eq!("The file is 8.5 kilobytes in size", result); //! ``` //! //! //! ## String Parsing //! //! There is a `FromStr` implementation for `NumberPrefix` that parses //! strings containing numbers and trailing prefixes, such as `7.5E`. //! //! Currently, the only supported units are `b` and `B` for bytes, and `m` for //! metres. Whitespace is allowed between the number and the rest of the string. //! //! ``` //! use unit_prefix::{NumberPrefix, Prefix}; //! //! assert_eq!( //! "7.05E".parse::>(), //! Ok(NumberPrefix::Prefixed(Prefix::Exa, 7.05_f64)) //! ); //! //! assert_eq!( //! "7.05".parse::>(), //! Ok(NumberPrefix::Standalone(7.05_f64)) //! ); //! //! assert_eq!( //! "7.05 GiB".parse::>(), //! Ok(NumberPrefix::Prefixed(Prefix::Gibi, 7.05_f64)) //! ); //! ``` #![cfg_attr(not(feature = "std"), no_std)] mod parse; use core::{ fmt, ops::{Div, Neg}, }; /// A numeric prefix, either binary or decimal. #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum Prefix { /// _kilo_, 103 or 10001. /// From the Greek ‘χίλιοι’ (‘chilioi’), meaning ‘thousand’. Kilo, /// _mega_, 106 or 10002. /// From the Ancient Greek ‘μέγας’ (‘megas’), meaning ‘great’. Mega, /// _giga_, 109 or 10003. /// From the Greek ‘γίγας’ (‘gigas’), meaning ‘giant’. Giga, /// _tera_, 1012 or 10004. /// From the Greek ‘τέρας’ (‘teras’), meaning ‘monster’. Tera, /// _peta_, 1015 or 10005. /// From the Greek ‘πέντε’ (‘pente’), meaning ‘five’. Peta, /// _exa_, 1018 or 10006. /// From the Greek ‘ἕξ’ (‘hex’), meaning ‘six’. Exa, /// _zetta_, 1021 or 10007. /// From the Latin ‘septem’, meaning ‘seven’. Zetta, /// _yotta_, 1024 or 10008. /// From the Green ‘οκτώ’ (‘okto’), meaning ‘eight’. Yotta, /// _kibi_, 210 or 10241. /// The binary version of _kilo_. Kibi, /// _mebi_, 220 or 10242. /// The binary version of _mega_. Mebi, /// _gibi_, 230 or 10243. /// The binary version of _giga_. Gibi, /// _tebi_, 240 or 10244. /// The binary version of _tera_. Tebi, /// _pebi_, 250 or 10245. /// The binary version of _peta_. Pebi, /// _exbi_, 260 or 10246. /// The binary version of _exa_. Exbi, // you can download exa binaries at https://exa.website/#installation /// _zebi_, 270 or 10247. /// The binary version of _zetta_. Zebi, /// _yobi_, 280 or 10248. /// The binary version of _yotta_. Yobi, } /// The result of trying to apply a prefix to a floating-point value. #[derive(PartialEq, Eq, Clone, Debug)] pub enum NumberPrefix { /// A **standalone** value is returned when the number is too small to /// have any prefixes applied to it. This is commonly a special case, so /// is handled separately. Standalone(F), /// A **prefixed** value *is* large enough for prefixes. This holds the /// prefix, as well as the resulting value. Prefixed(Prefix, F), } impl NumberPrefix { /// Formats the given floating-point number using **decimal** prefixes. /// /// This function accepts both `f32` and `f64` values. If you’re trying to /// format an integer, you’ll have to cast it first. /// /// # Examples /// /// ``` /// use unit_prefix::{NumberPrefix, Prefix}; /// /// assert_eq!( /// NumberPrefix::decimal(1_000_000_000_f32), /// NumberPrefix::Prefixed(Prefix::Giga, 1_f32) /// ); /// ``` pub fn decimal(amount: F) -> Self { use self::Prefix::*; Self::format_number( amount, Amounts::NUM_1000, [Kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta], ) } /// Formats the given floating-point number using **binary** prefixes. /// /// This function accepts both `f32` and `f64` values. If you’re trying to /// format an integer, you’ll have to cast it first. /// /// # Examples /// /// ``` /// use unit_prefix::{NumberPrefix, Prefix}; /// /// assert_eq!( /// NumberPrefix::binary(1_073_741_824_f64), /// NumberPrefix::Prefixed(Prefix::Gibi, 1_f64) /// ); /// ``` pub fn binary(amount: F) -> Self { use self::Prefix::*; Self::format_number( amount, Amounts::NUM_1024, [Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi], ) } fn format_number(mut amount: F, kilo: F, prefixes: [Prefix; 8]) -> Self { // For negative numbers, flip it to positive, do the processing, then // flip it back to negative again afterwards. let was_negative = if amount.is_negative() { amount = -amount; true } else { false }; let mut prefix = 0; while amount >= kilo && prefix < 8 { amount = amount / kilo; prefix += 1; } if was_negative { amount = -amount; } if prefix == 0 { NumberPrefix::Standalone(amount) } else { NumberPrefix::Prefixed(prefixes[prefix - 1], amount) } } } impl fmt::Display for Prefix { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.symbol()) } } impl Prefix { /// Returns the name in uppercase, such as “KILO”. /// /// # Examples /// /// ``` /// use unit_prefix::Prefix; /// /// assert_eq!("GIGA", Prefix::Giga.upper()); /// assert_eq!("GIBI", Prefix::Gibi.upper()); /// ``` pub fn upper(self) -> &'static str { use self::Prefix::*; match self { Kilo => "KILO", Mega => "MEGA", Giga => "GIGA", Tera => "TERA", Peta => "PETA", Exa => "EXA", Zetta => "ZETTA", Yotta => "YOTTA", Kibi => "KIBI", Mebi => "MEBI", Gibi => "GIBI", Tebi => "TEBI", Pebi => "PEBI", Exbi => "EXBI", Zebi => "ZEBI", Yobi => "YOBI", } } /// Returns the name with the first letter capitalised, such as “Mega”. /// /// # Examples /// /// ``` /// use unit_prefix::Prefix; /// /// assert_eq!("Giga", Prefix::Giga.caps()); /// assert_eq!("Gibi", Prefix::Gibi.caps()); /// ``` pub fn caps(self) -> &'static str { use self::Prefix::*; match self { Kilo => "Kilo", Mega => "Mega", Giga => "Giga", Tera => "Tera", Peta => "Peta", Exa => "Exa", Zetta => "Zetta", Yotta => "Yotta", Kibi => "Kibi", Mebi => "Mebi", Gibi => "Gibi", Tebi => "Tebi", Pebi => "Pebi", Exbi => "Exbi", Zebi => "Zebi", Yobi => "Yobi", } } /// Returns the name in lowercase, such as “giga”. /// /// # Examples /// /// ``` /// use unit_prefix::Prefix; /// /// assert_eq!("giga", Prefix::Giga.lower()); /// assert_eq!("gibi", Prefix::Gibi.lower()); /// ``` pub fn lower(self) -> &'static str { use self::Prefix::*; match self { Kilo => "kilo", Mega => "mega", Giga => "giga", Tera => "tera", Peta => "peta", Exa => "exa", Zetta => "zetta", Yotta => "yotta", Kibi => "kibi", Mebi => "mebi", Gibi => "gibi", Tebi => "tebi", Pebi => "pebi", Exbi => "exbi", Zebi => "zebi", Yobi => "yobi", } } /// Returns the short-hand symbol, such as “T” (for “tera”). /// /// # Examples /// /// ``` /// use unit_prefix::Prefix; /// /// assert_eq!("G", Prefix::Giga.symbol()); /// assert_eq!("Gi", Prefix::Gibi.symbol()); /// ``` pub fn symbol(self) -> &'static str { use self::Prefix::*; match self { Kilo => "k", Mega => "M", Giga => "G", Tera => "T", Peta => "P", Exa => "E", Zetta => "Z", Yotta => "Y", Kibi => "Ki", Mebi => "Mi", Gibi => "Gi", Tebi => "Ti", Pebi => "Pi", Exbi => "Ei", Zebi => "Zi", Yobi => "Yi", } } } /// Traits for floating-point values for both the possible multipliers. They /// need to be Copy, have defined 1000 and 1024s, and implement a bunch of /// operators. pub trait Amounts: Copy + Sized + PartialOrd + Div + Neg { /// The constant representing 1000, for decimal prefixes. const NUM_1000: Self; /// The constant representing 1024, for binary prefixes. const NUM_1024: Self; /// Whether this number is negative. /// This is used internally. fn is_negative(self) -> bool; } impl Amounts for f32 { const NUM_1000: Self = 1000_f32; const NUM_1024: Self = 1024_f32; fn is_negative(self) -> bool { self.is_sign_negative() } } impl Amounts for f64 { const NUM_1000: Self = 1000_f64; const NUM_1024: Self = 1024_f64; fn is_negative(self) -> bool { self.is_sign_negative() } } #[cfg(test)] mod test { use super::{NumberPrefix, Prefix}; #[test] fn decimal_minus_one_billion() { assert_eq!( NumberPrefix::decimal(-1_000_000_000_f64), NumberPrefix::Prefixed(Prefix::Giga, -1f64) ) } #[test] fn decimal_minus_one() { assert_eq!(NumberPrefix::decimal(-1f64), NumberPrefix::Standalone(-1f64)) } #[test] fn decimal_0() { assert_eq!(NumberPrefix::decimal(0f64), NumberPrefix::Standalone(0f64)) } #[test] fn decimal_999() { assert_eq!(NumberPrefix::decimal(999f32), NumberPrefix::Standalone(999f32)) } #[test] fn decimal_1000() { assert_eq!( NumberPrefix::decimal(1000f32), NumberPrefix::Prefixed(Prefix::Kilo, 1f32) ) } #[test] fn decimal_1030() { assert_eq!( NumberPrefix::decimal(1030f32), NumberPrefix::Prefixed(Prefix::Kilo, 1.03f32) ) } #[test] fn decimal_1100() { assert_eq!( NumberPrefix::decimal(1100f64), NumberPrefix::Prefixed(Prefix::Kilo, 1.1f64) ) } #[test] fn decimal_1111() { assert_eq!( NumberPrefix::decimal(1111f64), NumberPrefix::Prefixed(Prefix::Kilo, 1.111f64) ) } #[test] fn binary_126456() { assert_eq!( NumberPrefix::binary(126_456f32), NumberPrefix::Prefixed(Prefix::Kibi, 123.492_19f32) ) } #[test] fn binary_1048576() { assert_eq!( NumberPrefix::binary(1_048_576f64), NumberPrefix::Prefixed(Prefix::Mebi, 1f64) ) } #[test] fn binary_1073741824() { assert_eq!( NumberPrefix::binary(2_147_483_648f32), NumberPrefix::Prefixed(Prefix::Gibi, 2f32) ) } #[test] fn giga() { assert_eq!( NumberPrefix::decimal(1_000_000_000f64), NumberPrefix::Prefixed(Prefix::Giga, 1f64) ) } #[test] fn tera() { assert_eq!( NumberPrefix::decimal(1_000_000_000_000f64), NumberPrefix::Prefixed(Prefix::Tera, 1f64) ) } #[test] fn peta() { assert_eq!( NumberPrefix::decimal(1_000_000_000_000_000f64), NumberPrefix::Prefixed(Prefix::Peta, 1f64) ) } #[test] fn exa() { assert_eq!( NumberPrefix::decimal(1_000_000_000_000_000_000f64), NumberPrefix::Prefixed(Prefix::Exa, 1f64) ) } #[test] fn zetta() { assert_eq!( NumberPrefix::decimal(1_000_000_000_000_000_000_000f64), NumberPrefix::Prefixed(Prefix::Zetta, 1f64) ) } #[test] fn yotta() { assert_eq!( NumberPrefix::decimal(1_000_000_000_000_000_000_000_000f64), NumberPrefix::Prefixed(Prefix::Yotta, 1f64) ) } #[test] fn and_so_on() { // When you hit yotta, don't keep going assert_eq!( NumberPrefix::decimal(1_000_000_000_000_000_000_000_000_000f64), NumberPrefix::Prefixed(Prefix::Yotta, 1000f64) ) } } unit-prefix-0.5.1/src/parse.rs000064400000000000000000000050621046102023000143530ustar 00000000000000use core::{fmt, str}; use super::{NumberPrefix, Prefix}; impl str::FromStr for NumberPrefix { type Err = NumberPrefixParseError; fn from_str(s: &str) -> Result { let splitted = s.find(|p| { p == 'k' || p == 'K' || p == 'M' || p == 'G' || p == 'T' || p == 'P' || p == 'E' || p == 'Z' || p == 'Y' }); let num_prefix = s.split_at(splitted.unwrap_or(s.len())); let num = match num_prefix.0.trim().parse::() { Ok(n) => n, Err(_) => return Err(NumberPrefixParseError(())), }; let prefix_unit = num_prefix.1.trim_matches(|p| p == 'b' || p == 'B' || p == 'm'); let prefix = match prefix_unit { "k" | "K" => Prefix::Kilo, "M" => Prefix::Mega, "G" => Prefix::Giga, "T" => Prefix::Tera, "P" => Prefix::Peta, "E" => Prefix::Exa, "Z" => Prefix::Zetta, "Y" => Prefix::Yotta, "Ki" => Prefix::Kibi, "Mi" => Prefix::Mebi, "Gi" => Prefix::Gibi, "Ti" => Prefix::Tebi, "Pi" => Prefix::Pebi, "Ei" => Prefix::Exbi, "Zi" => Prefix::Zebi, "Yi" => Prefix::Yobi, "" => return Ok(NumberPrefix::Standalone(num)), _ => return Err(NumberPrefixParseError(())), }; Ok(NumberPrefix::Prefixed(prefix, num)) } } /// The error returned when a `NumberPrefix` is failed to be parsed. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct NumberPrefixParseError(()); impl fmt::Display for NumberPrefixParseError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.write_str("invalid prefix syntax") } } #[cfg(feature = "std")] impl std::error::Error for NumberPrefixParseError {} #[cfg(test)] mod test { use super::*; #[test] fn parse_examples() { let parse_example_a = "7.05E".parse::>(); let parse_example_b = "7.05".parse::>(); let parse_example_c = "7.05 GiB".parse::>(); assert_eq!(parse_example_a, Ok(NumberPrefix::Prefixed(Prefix::Exa, 7.05_f64))); assert_eq!(parse_example_b, Ok(NumberPrefix::Standalone(7.05_f64))); assert_eq!(parse_example_c, Ok(NumberPrefix::Prefixed(Prefix::Gibi, 7.05_f64))); } #[test] fn bad_parse() { let parsed = "bogo meters per second".parse::>(); assert_ne!(parsed, Ok(NumberPrefix::Prefixed(Prefix::Kilo, 7.05_f64))); } }