From 226004b438850a2ff1ba76e036418d1237e94ca8 Mon Sep 17 00:00:00 2001 From: jRimbault Date: Thu, 23 Jul 2020 15:24:52 +0200 Subject: [PATCH 01/11] start implementing FromStr for ByteSize --- src/lib.rs | 6 ++++-- src/parse.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/parse.rs diff --git a/src/lib.rs b/src/lib.rs index e2d63c9c..2883ccd0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,8 @@ //! assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false)); //! ``` +mod parse; + #[cfg(feature = "serde")] #[macro_use] extern crate serde; @@ -58,8 +60,8 @@ pub const TIB: u64 = 1_099_511_627_776; /// bytes size for 1 pebibyte pub const PIB: u64 = 1_125_899_906_842_624; -static UNITS: &'static str = "KMGTPE"; -static UNITS_SI: &'static str = "kMGTPE"; +static UNITS: &str = "KMGTPE"; +static UNITS_SI: &str = "kMGTPE"; static LN_KB: f64 = 6.931471806; // ln 1024 static LN_KIB: f64 = 6.907755279; // ln 1000 diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 00000000..5bdcc827 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,43 @@ +use super::ByteSize; + +impl std::str::FromStr for ByteSize { + type Err = String; + + fn from_str(value: &str) -> Result { + match value.parse::() { + Ok(v) => return Ok(Self(v)), // simple case, bytes + Err(_) => {}, + }; + todo!() + } +} + +#[cfg(test)] +mod tests { + use super::super::*; + + #[test] + fn when_ok() { + // shortcut for writing test cases + fn parse(s: &str) -> u64 { + s.parse::().unwrap().0 + } + + assert_eq!("0".parse::().unwrap().0, 0); + assert_eq!(parse("0"), 0); + assert_eq!(parse("500"), 500); + assert_eq!(parse("1K"), 1 * MB); + assert_eq!(parse("1Ki"), 1 * KIB); + assert_eq!(parse("1.5Ki"), (1.5 * KIB as f64) as u64); + assert_eq!(parse("1KiB"), 1 * KIB); + assert_eq!(parse("1.5KiB"), (1.5 * KIB as f64) as u64); + assert_eq!(parse("3 MB"), 3 * MB); + assert_eq!(parse("4 MiB"), 4 * MIB); + assert_eq!(parse("6 GB"), 6 * GB); + assert_eq!(parse("4 GiB"), 4 * GIB); + assert_eq!(parse("88TB"), 88 * TB); + assert_eq!(parse("521TiB"), 521 * TIB); + assert_eq!(parse("8 PB"), 8 * PB); + assert_eq!(parse("12 PB"), 12 * PIB); + } +} From 199a74d8659057bbbd774882d2b3834405863db7 Mon Sep 17 00:00:00 2001 From: jRimbault Date: Thu, 23 Jul 2020 15:37:50 +0200 Subject: [PATCH 02/11] pass the test --- src/parse.rs | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/parse.rs b/src/parse.rs index 5bdcc827..7cf299ef 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -6,9 +6,41 @@ impl std::str::FromStr for ByteSize { fn from_str(value: &str) -> Result { match value.parse::() { Ok(v) => return Ok(Self(v)), // simple case, bytes - Err(_) => {}, + Err(_) => {} }; - todo!() + let number: String = value + .chars() + .take_while(|c| c.is_digit(10) || c == &'.') + .collect(); + match number.parse::() { + Ok(v) => { + let suffix: String = value + .chars() + .skip_while(|c| c.is_whitespace() || c.is_digit(10) || c == &'.') + .collect(); + Ok(Self((v * match_suffix(&suffix) as f64) as u64)) + } + Err(error) => Err(format!( + "couldn't parse {:?} into a ByteSize, {}", + value, error + )), + } + } +} + +fn match_suffix(unit: &str) -> u64 { + match unit.to_lowercase().as_str() { + "k" | "kb" => super::KB, + "ki" | "kib" => super::KIB, + "m" | "mb" => super::MB, + "mi" | "mib" => super::MIB, + "g" | "gb" => super::GB, + "gi" | "gib" => super::GIB, + "t" | "tb" => super::TB, + "ti" | "tib" => super::TIB, + "p" | "pb" => super::PB, + "pi" | "pib" => super::PIB, + _ => 1, } } @@ -26,7 +58,7 @@ mod tests { assert_eq!("0".parse::().unwrap().0, 0); assert_eq!(parse("0"), 0); assert_eq!(parse("500"), 500); - assert_eq!(parse("1K"), 1 * MB); + assert_eq!(parse("1K"), 1 * KB); assert_eq!(parse("1Ki"), 1 * KIB); assert_eq!(parse("1.5Ki"), (1.5 * KIB as f64) as u64); assert_eq!(parse("1KiB"), 1 * KIB); @@ -38,6 +70,6 @@ mod tests { assert_eq!(parse("88TB"), 88 * TB); assert_eq!(parse("521TiB"), 521 * TIB); assert_eq!(parse("8 PB"), 8 * PB); - assert_eq!(parse("12 PB"), 12 * PIB); + assert_eq!(parse("12 PiB"), 12 * PIB); } } From 3a123afd28055b57a1b51fe920f31309eb6e3b1e Mon Sep 17 00:00:00 2001 From: jRimbault Date: Thu, 23 Jul 2020 15:49:46 +0200 Subject: [PATCH 03/11] comment and precise imports --- src/parse.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/parse.rs b/src/parse.rs index 7cf299ef..936503a0 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -28,6 +28,7 @@ impl std::str::FromStr for ByteSize { } } +/// todo: maybe a Unit type would be appropriate fn match_suffix(unit: &str) -> u64 { match unit.to_lowercase().as_str() { "k" | "kb" => super::KB, @@ -46,7 +47,8 @@ fn match_suffix(unit: &str) -> u64 { #[cfg(test)] mod tests { - use super::super::*; + use super::*; + use super::super::{KB, KIB, MB, MIB, GB, GIB, TB, TIB, PB, PIB}; #[test] fn when_ok() { @@ -72,4 +74,15 @@ mod tests { assert_eq!(parse("8 PB"), 8 * PB); assert_eq!(parse("12 PiB"), 12 * PIB); } + + #[test] + fn when_err() { + // shortcut for writing test cases + fn parse(s: &str) -> Result { + s.parse::() + } + + assert!(parse("").is_err()); + assert!(parse("a124GB").is_err()); + } } From 856a0b7566096fc29836102af290f1e5e64dd892 Mon Sep 17 00:00:00 2001 From: jRimbault Date: Thu, 23 Jul 2020 16:02:22 +0200 Subject: [PATCH 04/11] impl a unit type --- src/parse.rs | 82 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/src/parse.rs b/src/parse.rs index 936503a0..a34ad4c8 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -18,7 +18,13 @@ impl std::str::FromStr for ByteSize { .chars() .skip_while(|c| c.is_whitespace() || c.is_digit(10) || c == &'.') .collect(); - Ok(Self((v * match_suffix(&suffix) as f64) as u64)) + match suffix.parse::() { + Ok(u) => Ok(Self((v * u.0 as f64) as u64)), + Err(error) => Err(format!( + "couldn't parse {:?} into a known SI unit, {}", + suffix, error + )), + } } Err(error) => Err(format!( "couldn't parse {:?} into a ByteSize, {}", @@ -28,27 +34,45 @@ impl std::str::FromStr for ByteSize { } } -/// todo: maybe a Unit type would be appropriate -fn match_suffix(unit: &str) -> u64 { - match unit.to_lowercase().as_str() { - "k" | "kb" => super::KB, - "ki" | "kib" => super::KIB, - "m" | "mb" => super::MB, - "mi" | "mib" => super::MIB, - "g" | "gb" => super::GB, - "gi" | "gib" => super::GIB, - "t" | "tb" => super::TB, - "ti" | "tib" => super::TIB, - "p" | "pb" => super::PB, - "pi" | "pib" => super::PIB, - _ => 1, +#[repr(transparent)] +struct Unit(pub(crate) u64); + +impl Unit { + const KB: u64 = super::KB; + const KIB: u64 = super::KIB; + const MB: u64 = super::MB; + const MIB: u64 = super::MIB; + const GB: u64 = super::GB; + const GIB: u64 = super::GIB; + const TB: u64 = super::TB; + const TIB: u64 = super::TIB; + const PB: u64 = super::PB; + const PIB: u64 = super::PIB; +} + +impl std::str::FromStr for Unit { + type Err = String; + + fn from_str(unit: &str) -> Result { + match unit.to_lowercase().as_str() { + "k" | "kb" => Ok(Self(Self::KB)), + "ki" | "kib" => Ok(Self(Self::KIB)), + "m" | "mb" => Ok(Self(Self::MB)), + "mi" | "mib" => Ok(Self(Self::MIB)), + "g" | "gb" => Ok(Self(Self::GB)), + "gi" | "gib" => Ok(Self(Self::GIB)), + "t" | "tb" => Ok(Self(Self::TB)), + "ti" | "tib" => Ok(Self(Self::TIB)), + "p" | "pb" => Ok(Self(Self::PB)), + "pi" | "pib" => Ok(Self(Self::PIB)), + _ => Err(format!("couldn't parse unit of {:?}", unit)), + } } } #[cfg(test)] mod tests { use super::*; - use super::super::{KB, KIB, MB, MIB, GB, GIB, TB, TIB, PB, PIB}; #[test] fn when_ok() { @@ -60,19 +84,19 @@ mod tests { assert_eq!("0".parse::().unwrap().0, 0); assert_eq!(parse("0"), 0); assert_eq!(parse("500"), 500); - assert_eq!(parse("1K"), 1 * KB); - assert_eq!(parse("1Ki"), 1 * KIB); - assert_eq!(parse("1.5Ki"), (1.5 * KIB as f64) as u64); - assert_eq!(parse("1KiB"), 1 * KIB); - assert_eq!(parse("1.5KiB"), (1.5 * KIB as f64) as u64); - assert_eq!(parse("3 MB"), 3 * MB); - assert_eq!(parse("4 MiB"), 4 * MIB); - assert_eq!(parse("6 GB"), 6 * GB); - assert_eq!(parse("4 GiB"), 4 * GIB); - assert_eq!(parse("88TB"), 88 * TB); - assert_eq!(parse("521TiB"), 521 * TIB); - assert_eq!(parse("8 PB"), 8 * PB); - assert_eq!(parse("12 PiB"), 12 * PIB); + assert_eq!(parse("1K"), 1 * Unit::KB); + assert_eq!(parse("1Ki"), 1 * Unit::KIB); + assert_eq!(parse("1.5Ki"), (1.5 * Unit::KIB as f64) as u64); + assert_eq!(parse("1KiB"), 1 * Unit::KIB); + assert_eq!(parse("1.5KiB"), (1.5 * Unit::KIB as f64) as u64); + assert_eq!(parse("3 MB"), 3 * Unit::MB); + assert_eq!(parse("4 MiB"), 4 * Unit::MIB); + assert_eq!(parse("6 GB"), 6 * Unit::GB); + assert_eq!(parse("4 GiB"), 4 * Unit::GIB); + assert_eq!(parse("88TB"), 88 * Unit::TB); + assert_eq!(parse("521TiB"), 521 * Unit::TIB); + assert_eq!(parse("8 PB"), 8 * Unit::PB); + assert_eq!(parse("12 PiB"), 12 * Unit::PIB); } #[test] From e3c74f6f408574bfeaffec9d725458a257a7b927 Mon Sep 17 00:00:00 2001 From: jRimbault Date: Thu, 23 Jul 2020 18:33:17 +0200 Subject: [PATCH 05/11] add feedback test --- src/parse.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/parse.rs b/src/parse.rs index a34ad4c8..82b65055 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -109,4 +109,22 @@ mod tests { assert!(parse("").is_err()); assert!(parse("a124GB").is_err()); } + + #[test] + fn to_and_from_str() { + assert_eq!( + format!("{}", "128GB".parse::().unwrap()) + .parse::() + .unwrap() + .0, + 128 * Unit::GB + ); + assert_eq!( + super::super::to_string("128.000 GiB".parse::().unwrap().0, true) + .parse::() + .unwrap() + .0, + 128 * Unit::GIB + ); + } } From 31ed55785d7477501e8ff0e48554555a9670aa46 Mon Sep 17 00:00:00 2001 From: jRimbault Date: Fri, 24 Jul 2020 10:31:15 +0200 Subject: [PATCH 06/11] use enum --- src/parse.rs | 62 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/src/parse.rs b/src/parse.rs index 82b65055..e3f7babb 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -19,7 +19,7 @@ impl std::str::FromStr for ByteSize { .skip_while(|c| c.is_whitespace() || c.is_digit(10) || c == &'.') .collect(); match suffix.parse::() { - Ok(u) => Ok(Self((v * u.0 as f64) as u64)), + Ok(u) => Ok(Self((v * u.factor() as f64) as u64)), Err(error) => Err(format!( "couldn't parse {:?} into a known SI unit, {}", suffix, error @@ -34,10 +34,24 @@ impl std::str::FromStr for ByteSize { } } -#[repr(transparent)] -struct Unit(pub(crate) u64); +enum Unit { + Byte, + // power of tens + KiloByte, + MegaByte, + GigaByte, + TeraByte, + PetaByte, + // power of twos + KibiByte, + MebiByte, + GibiByte, + TebiByte, + PebiByte, +} impl Unit { + const B: u64 = super::B; const KB: u64 = super::KB; const KIB: u64 = super::KIB; const MB: u64 = super::MB; @@ -48,6 +62,24 @@ impl Unit { const TIB: u64 = super::TIB; const PB: u64 = super::PB; const PIB: u64 = super::PIB; + + fn factor(&self) -> u64 { + match self { + Self::Byte => Self::B, + // power of tens + Self::KiloByte => Self::KB, + Self::MegaByte => Self::MB, + Self::GigaByte => Self::GB, + Self::TeraByte => Self::TB, + Self::PetaByte => Self::PB, + // power of twos + Self::KibiByte => Self::KIB, + Self::MebiByte => Self::MIB, + Self::GibiByte => Self::GIB, + Self::TebiByte => Self::TIB, + Self::PebiByte => Self::PIB, + } + } } impl std::str::FromStr for Unit { @@ -55,16 +87,19 @@ impl std::str::FromStr for Unit { fn from_str(unit: &str) -> Result { match unit.to_lowercase().as_str() { - "k" | "kb" => Ok(Self(Self::KB)), - "ki" | "kib" => Ok(Self(Self::KIB)), - "m" | "mb" => Ok(Self(Self::MB)), - "mi" | "mib" => Ok(Self(Self::MIB)), - "g" | "gb" => Ok(Self(Self::GB)), - "gi" | "gib" => Ok(Self(Self::GIB)), - "t" | "tb" => Ok(Self(Self::TB)), - "ti" | "tib" => Ok(Self(Self::TIB)), - "p" | "pb" => Ok(Self(Self::PB)), - "pi" | "pib" => Ok(Self(Self::PIB)), + "b" => Ok(Self::Byte), + // power of tens + "k" | "kb" => Ok(Self::KiloByte), + "m" | "mb" => Ok(Self::MegaByte), + "g" | "gb" => Ok(Self::GigaByte), + "t" | "tb" => Ok(Self::TeraByte), + "p" | "pb" => Ok(Self::PetaByte), + // power of twos + "ki" | "kib" => Ok(Self::KibiByte), + "mi" | "mib" => Ok(Self::MebiByte), + "gi" | "gib" => Ok(Self::GibiByte), + "ti" | "tib" => Ok(Self::TebiByte), + "pi" | "pib" => Ok(Self::PebiByte), _ => Err(format!("couldn't parse unit of {:?}", unit)), } } @@ -96,6 +131,7 @@ mod tests { assert_eq!(parse("88TB"), 88 * Unit::TB); assert_eq!(parse("521TiB"), 521 * Unit::TIB); assert_eq!(parse("8 PB"), 8 * Unit::PB); + assert_eq!(parse("8P"), 8 * Unit::PB); assert_eq!(parse("12 PiB"), 12 * Unit::PIB); } From 8fa1a2f05674cca0cff2437a24a52f389dd7a946 Mon Sep 17 00:00:00 2001 From: jRimbault Date: Fri, 24 Jul 2020 10:36:38 +0200 Subject: [PATCH 07/11] use a helper --- src/parse.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/parse.rs b/src/parse.rs index e3f7babb..79eded66 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -148,18 +148,14 @@ mod tests { #[test] fn to_and_from_str() { + // shortcut for writing test cases + fn parse(s: &str) -> u64 { + s.parse::().unwrap().0 + } + + assert_eq!(parse(&format!("{}", parse("128GB"))), 128 * Unit::GB); assert_eq!( - format!("{}", "128GB".parse::().unwrap()) - .parse::() - .unwrap() - .0, - 128 * Unit::GB - ); - assert_eq!( - super::super::to_string("128.000 GiB".parse::().unwrap().0, true) - .parse::() - .unwrap() - .0, + parse(&super::super::to_string(parse("128.000 GiB"), true)), 128 * Unit::GIB ); } From d61851ed7b9a12e783879eba20beaaf96ce0088b Mon Sep 17 00:00:00 2001 From: jRimbault Date: Fri, 24 Jul 2020 10:37:18 +0200 Subject: [PATCH 08/11] cosmetic --- src/parse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parse.rs b/src/parse.rs index 79eded66..32a2dc2c 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -155,7 +155,7 @@ mod tests { assert_eq!(parse(&format!("{}", parse("128GB"))), 128 * Unit::GB); assert_eq!( - parse(&super::super::to_string(parse("128.000 GiB"), true)), + parse(&crate::to_string(parse("128.000 GiB"), true)), 128 * Unit::GIB ); } From bde13d60d2ce1e0f22a98e800415990b9f2aa7d2 Mon Sep 17 00:00:00 2001 From: jRimbault Date: Fri, 24 Jul 2020 10:40:17 +0200 Subject: [PATCH 09/11] remove associated constants --- src/parse.rs | 66 +++++++++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/src/parse.rs b/src/parse.rs index 32a2dc2c..09fce70a 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -51,33 +51,21 @@ enum Unit { } impl Unit { - const B: u64 = super::B; - const KB: u64 = super::KB; - const KIB: u64 = super::KIB; - const MB: u64 = super::MB; - const MIB: u64 = super::MIB; - const GB: u64 = super::GB; - const GIB: u64 = super::GIB; - const TB: u64 = super::TB; - const TIB: u64 = super::TIB; - const PB: u64 = super::PB; - const PIB: u64 = super::PIB; - fn factor(&self) -> u64 { match self { - Self::Byte => Self::B, + Self::Byte => super::B, // power of tens - Self::KiloByte => Self::KB, - Self::MegaByte => Self::MB, - Self::GigaByte => Self::GB, - Self::TeraByte => Self::TB, - Self::PetaByte => Self::PB, + Self::KiloByte => super::KB, + Self::MegaByte => super::MB, + Self::GigaByte => super::GB, + Self::TeraByte => super::TB, + Self::PetaByte => super::PB, // power of twos - Self::KibiByte => Self::KIB, - Self::MebiByte => Self::MIB, - Self::GibiByte => Self::GIB, - Self::TebiByte => Self::TIB, - Self::PebiByte => Self::PIB, + Self::KibiByte => super::KIB, + Self::MebiByte => super::MIB, + Self::GibiByte => super::GIB, + Self::TebiByte => super::TIB, + Self::PebiByte => super::PIB, } } } @@ -119,20 +107,20 @@ mod tests { assert_eq!("0".parse::().unwrap().0, 0); assert_eq!(parse("0"), 0); assert_eq!(parse("500"), 500); - assert_eq!(parse("1K"), 1 * Unit::KB); - assert_eq!(parse("1Ki"), 1 * Unit::KIB); - assert_eq!(parse("1.5Ki"), (1.5 * Unit::KIB as f64) as u64); - assert_eq!(parse("1KiB"), 1 * Unit::KIB); - assert_eq!(parse("1.5KiB"), (1.5 * Unit::KIB as f64) as u64); - assert_eq!(parse("3 MB"), 3 * Unit::MB); - assert_eq!(parse("4 MiB"), 4 * Unit::MIB); - assert_eq!(parse("6 GB"), 6 * Unit::GB); - assert_eq!(parse("4 GiB"), 4 * Unit::GIB); - assert_eq!(parse("88TB"), 88 * Unit::TB); - assert_eq!(parse("521TiB"), 521 * Unit::TIB); - assert_eq!(parse("8 PB"), 8 * Unit::PB); - assert_eq!(parse("8P"), 8 * Unit::PB); - assert_eq!(parse("12 PiB"), 12 * Unit::PIB); + assert_eq!(parse("1K"), 1 * crate::KB); + assert_eq!(parse("1Ki"), 1 * crate::KIB); + assert_eq!(parse("1.5Ki"), (1.5 * crate::KIB as f64) as u64); + assert_eq!(parse("1KiB"), 1 * crate::KIB); + assert_eq!(parse("1.5KiB"), (1.5 * crate::KIB as f64) as u64); + assert_eq!(parse("3 MB"), 3 * crate::MB); + assert_eq!(parse("4 MiB"), 4 * crate::MIB); + assert_eq!(parse("6 GB"), 6 * crate::GB); + assert_eq!(parse("4 GiB"), 4 * crate::GIB); + assert_eq!(parse("88TB"), 88 * crate::TB); + assert_eq!(parse("521TiB"), 521 * crate::TIB); + assert_eq!(parse("8 PB"), 8 * crate::PB); + assert_eq!(parse("8P"), 8 * crate::PB); + assert_eq!(parse("12 PiB"), 12 * crate::PIB); } #[test] @@ -153,10 +141,10 @@ mod tests { s.parse::().unwrap().0 } - assert_eq!(parse(&format!("{}", parse("128GB"))), 128 * Unit::GB); + assert_eq!(parse(&format!("{}", parse("128GB"))), 128 * crate::GB); assert_eq!( parse(&crate::to_string(parse("128.000 GiB"), true)), - 128 * Unit::GIB + 128 * crate::GIB ); } } From c068943599a85119317f53947e334c6fe69ee7ba Mon Sep 17 00:00:00 2001 From: jRimbault Date: Fri, 24 Jul 2020 10:41:26 +0200 Subject: [PATCH 10/11] cosmetic --- src/parse.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/parse.rs b/src/parse.rs index 09fce70a..5c943267 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -4,10 +4,9 @@ impl std::str::FromStr for ByteSize { type Err = String; fn from_str(value: &str) -> Result { - match value.parse::() { - Ok(v) => return Ok(Self(v)), // simple case, bytes - Err(_) => {} - }; + if let Ok(v) = value.parse::() { + return Ok(Self(v)); + } let number: String = value .chars() .take_while(|c| c.is_digit(10) || c == &'.') From 3749005dc1028a5b6b658ca97f3642dcbad8326d Mon Sep 17 00:00:00 2001 From: jRimbault Date: Fri, 24 Jul 2020 11:02:35 +0200 Subject: [PATCH 11/11] impl ops --- src/parse.rs | 103 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 17 deletions(-) diff --git a/src/parse.rs b/src/parse.rs index 5c943267..9e72cf33 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -18,7 +18,7 @@ impl std::str::FromStr for ByteSize { .skip_while(|c| c.is_whitespace() || c.is_digit(10) || c == &'.') .collect(); match suffix.parse::() { - Ok(u) => Ok(Self((v * u.factor() as f64) as u64)), + Ok(u) => Ok(Self((v * u) as u64)), Err(error) => Err(format!( "couldn't parse {:?} into a known SI unit, {}", suffix, error @@ -69,6 +69,75 @@ impl Unit { } } +mod impl_ops { + use super::Unit; + use std::ops; + + impl ops::Add for Unit { + type Output = u64; + + fn add(self, other: u64) -> Self::Output { + self.factor() + other + } + } + + impl ops::Add for u64 { + type Output = u64; + + fn add(self, other: Unit) -> Self::Output { + self + other.factor() + } + } + + impl ops::Mul for Unit { + type Output = u64; + + fn mul(self, other: u64) -> Self::Output { + self.factor() * other + } + } + + impl ops::Mul for u64 { + type Output = u64; + + fn mul(self, other: Unit) -> Self::Output { + self * other.factor() + } + } + + impl ops::Add for Unit { + type Output = f64; + + fn add(self, other: f64) -> Self::Output { + self.factor() as f64 + other + } + } + + impl ops::Add for f64 { + type Output = f64; + + fn add(self, other: Unit) -> Self::Output { + other.factor() as f64 + self + } + } + + impl ops::Mul for Unit { + type Output = f64; + + fn mul(self, other: f64) -> Self::Output { + self.factor() as f64 * other + } + } + + impl ops::Mul for f64 { + type Output = f64; + + fn mul(self, other: Unit) -> Self::Output { + other.factor() as f64 * self + } + } +} + impl std::str::FromStr for Unit { type Err = String; @@ -106,20 +175,20 @@ mod tests { assert_eq!("0".parse::().unwrap().0, 0); assert_eq!(parse("0"), 0); assert_eq!(parse("500"), 500); - assert_eq!(parse("1K"), 1 * crate::KB); - assert_eq!(parse("1Ki"), 1 * crate::KIB); - assert_eq!(parse("1.5Ki"), (1.5 * crate::KIB as f64) as u64); - assert_eq!(parse("1KiB"), 1 * crate::KIB); - assert_eq!(parse("1.5KiB"), (1.5 * crate::KIB as f64) as u64); - assert_eq!(parse("3 MB"), 3 * crate::MB); - assert_eq!(parse("4 MiB"), 4 * crate::MIB); - assert_eq!(parse("6 GB"), 6 * crate::GB); - assert_eq!(parse("4 GiB"), 4 * crate::GIB); - assert_eq!(parse("88TB"), 88 * crate::TB); - assert_eq!(parse("521TiB"), 521 * crate::TIB); - assert_eq!(parse("8 PB"), 8 * crate::PB); - assert_eq!(parse("8P"), 8 * crate::PB); - assert_eq!(parse("12 PiB"), 12 * crate::PIB); + assert_eq!(parse("1K"), Unit::KiloByte * 1); + assert_eq!(parse("1Ki"), Unit::KibiByte * 1); + assert_eq!(parse("1.5Ki"), (1.5 * Unit::KibiByte) as u64); + assert_eq!(parse("1KiB"), 1 * Unit::KibiByte); + assert_eq!(parse("1.5KiB"), (1.5 * Unit::KibiByte) as u64); + assert_eq!(parse("3 MB"), Unit::MegaByte * 3); + assert_eq!(parse("4 MiB"), Unit::MebiByte * 4); + assert_eq!(parse("6 GB"), 6 * Unit::GigaByte); + assert_eq!(parse("4 GiB"), 4 * Unit::GibiByte); + assert_eq!(parse("88TB"), 88 * Unit::TeraByte); + assert_eq!(parse("521TiB"), 521 * Unit::TebiByte); + assert_eq!(parse("8 PB"), 8 * Unit::PetaByte); + assert_eq!(parse("8P"), 8 * Unit::PetaByte); + assert_eq!(parse("12 PiB"), 12 * Unit::PebiByte); } #[test] @@ -140,10 +209,10 @@ mod tests { s.parse::().unwrap().0 } - assert_eq!(parse(&format!("{}", parse("128GB"))), 128 * crate::GB); + assert_eq!(parse(&format!("{}", parse("128GB"))), 128 * Unit::GigaByte); assert_eq!( parse(&crate::to_string(parse("128.000 GiB"), true)), - 128 * crate::GIB + 128 * Unit::GibiByte ); } }