From 45d79d8ce078a4f8e794ffb8d8b37efc165cd56e Mon Sep 17 00:00:00 2001 From: Thomas Kosiewski Date: Sat, 28 Sep 2024 11:38:21 +0200 Subject: [PATCH] Removed parsed quantity multiplication Signed-off-by: Thomas Kosiewski --- Cargo.toml | 8 ++-- README.md | 94 +++++++++++++++++++++++++++++++++++++-- src/lib.rs | 99 +++++++++++++++++++++++++++++++++-------- src/quantity.rs | 114 ++++++++++++++++++------------------------------ 4 files changed, 218 insertions(+), 97 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3453b59..7ac8c50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,16 +18,16 @@ categories = ["algorithms", "data-structures", "encoding"] [dependencies] k8s-openapi = { version = "0.23.0", default-features = false } nom = "7.1.3" -rust_decimal = "1.32.0" +rust_decimal = "1.36.0" thiserror = "1.0.64" [dev-dependencies] k8s-openapi = { version = "0.23.0", default-features = false, features = [ - "v1_29", + "latest", ] } [features] -__check = ["k8s-openapi/v1_29"] +__check = ["k8s-openapi/latest"] [package.metadata.docs.rs] -features = ["k8s-openapi/v1_29"] +features = ["k8s-openapi/latest"] diff --git a/README.md b/README.md index bd12380..5d31ef2 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,13 @@ [![Crates.io](https://img.shields.io/crates/v/kube_quantity)](https://crates.io/crates/kube_quantity) -`kube_quantity` is a library adding arithmetic operations to the [`Quantity`](https://arnavion.github.io/k8s-openapi/v0.17.x/k8s_openapi/apimachinery/pkg/api/resource/struct.Quantity.html#) type from the [`k8s-openapi`](https://crates.io/crates/k8s-openapi) crate. +`kube_quantity` is a library adding arithmetic operations to the [`Quantity`](https://arnavion.github.io/k8s-openapi/v0.17.x/k8s_openapi/apimachinery/pkg/api/resource/struct.Quantity.html#) +type from the [`k8s-openapi`](https://crates.io/crates/k8s-openapi) crate. ## Installation -Run the following Cargo command in your project directory to add the latest stable version: +Run the following Cargo command in your project directory to add the latest +stable version: ```bash cargo add kube_quantity @@ -21,7 +23,8 @@ kube_quantity = "0.7.1" ## Upgrading -Please check the [CHANGELOG](https://github.com/ThomasK33/kube-quantity-rs/blob/main/CHANGELOG.md) when upgrading. +Please check the [CHANGELOG](https://github.com/ThomasK33/kube-quantity-rs/blob/main/CHANGELOG.md) +when upgrading. ## Usage @@ -69,6 +72,22 @@ assert_eq!(q3.0, "3Ki"); use k8s_openapi::apimachinery::pkg::api::resource::Quantity; use kube_quantity::{ParseQuantityError, ParsedQuantity}; +// Try parsing k8s quantities +let q1: Result = Quantity("4.2Ki".to_string()).try_into(); +let q2: Result = Quantity("2.1Ki".to_string()).try_into(); + +// Add parsed quantities +let q3: ParsedQuantity = q1.unwrap() + q2.unwrap(); +// Convert parsed quantity back into a k8s quantity +let q3: Quantity = q3.into(); + +assert_eq!(q3.0, "6.3Ki"); +``` + +```rust +use k8s_openapi::apimachinery::pkg::api::resource::Quantity; +use kube_quantity::{ParseQuantityError, ParsedQuantity}; + let q1: Result = Quantity("5M".to_string()).try_into(); let q2: Result = Quantity("7M".to_string()).try_into(); @@ -81,6 +100,72 @@ assert_eq!(q1.0, "12M"); ``` +### Multiplication of quantities + +```rust +use k8s_openapi::apimachinery::pkg::api::resource::Quantity; +use kube_quantity::{ParseQuantityError, ParsedQuantity}; + +// Try parsing k8s quantities +let q1: Result = Quantity("3k".to_string()).try_into(); + +// Multiply parsed quantities +let q1: ParsedQuantity = q1.unwrap() * 2; +// Convert parsed quantity back into a k8s quantity +let q2: Quantity = q1.into(); + +assert_eq!(q2.0, "6k"); +``` + +```rust +use k8s_openapi::apimachinery::pkg::api::resource::Quantity; +use kube_quantity::{ParseQuantityError, ParsedQuantity}; + +// Try parsing k8s quantities +let q1: Result = Quantity("3k".to_string()).try_into(); +let mut q1: ParsedQuantity = q1.unwrap(); + +// Multiply parsed quantities +q1 *= 2; +// Convert parsed quantity back into a k8s quantity +let q2: Quantity = q1.into(); + +assert_eq!(q2.0, "6k"); +``` + +### Division of quantities + +```rust +use k8s_openapi::apimachinery::pkg::api::resource::Quantity; +use kube_quantity::{ParseQuantityError, ParsedQuantity}; + +// Try parsing k8s quantities +let q1: Result = Quantity("4k".to_string()).try_into(); + +// Multiply parsed quantities +let q1: ParsedQuantity = q1.unwrap() / 2; +// Convert parsed quantity back into a k8s quantity +let q2: Quantity = q1.into(); + +assert_eq!(q2.0, "2k"); +``` + +```rust +use k8s_openapi::apimachinery::pkg::api::resource::Quantity; +use kube_quantity::{ParseQuantityError, ParsedQuantity}; + +// Try parsing k8s quantities +let q1: Result = Quantity("3k".to_string()).try_into(); +let mut q1: ParsedQuantity = q1.unwrap(); + +// Multiply parsed quantities +q1 /= 3; +// Convert parsed quantity back into a k8s quantity +let q2: Quantity = q1.into(); + +assert_eq!(q2.0, "1k"); +``` + ### Subtraction of quantities ```rust @@ -159,4 +244,5 @@ assert_eq!(q1, q2); ## License -Apache 2.0 licensed. See [LICENSE](https://github.com/ThomasK33/kube-quantity-rs/blob/main/LICENSE) for details. +Apache 2.0 licensed. See [LICENSE](https://github.com/ThomasK33/kube-quantity-rs/blob/main/LICENSE) +for details. diff --git a/src/lib.rs b/src/lib.rs index 88f4265..422df37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,12 +54,12 @@ impl From for Quantity { #[cfg(test)] mod tests { use k8s_openapi::apimachinery::pkg::api::resource::Quantity; - use rust_decimal::Decimal; use rust_decimal::prelude::FromPrimitive; + use rust_decimal::Decimal; - use crate::{ParseQuantityError, ParsedQuantity}; use crate::format::Format; use crate::scale::Scale; + use crate::{ParseQuantityError, ParsedQuantity}; #[test] fn test_quantity_addition() { @@ -163,7 +163,6 @@ mod tests { assert_eq!(q.unwrap_err().to_string(), "quantity parsing failed"); } - #[test] fn test_div() { let exp_result = ParsedQuantity { @@ -177,11 +176,27 @@ mod tests { scale: Scale::Kilo, format: Format::BinarySI, }; - let q2 = ParsedQuantity { + let q2 = Decimal::from_f32(2.0).unwrap(); + + let result = q1 / q2; + + assert_eq!(result, exp_result); + } + + #[test] + fn test_div_decimal_f32() { + let exp_result = ParsedQuantity { value: Decimal::from_f32(2.0).unwrap(), - scale: Scale::One, + scale: Scale::Kilo, + format: Format::BinarySI, + }; + + let q1 = ParsedQuantity { + value: Decimal::from_f32(5.0).unwrap(), + scale: Scale::Kilo, format: Format::BinarySI, }; + let q2 = Decimal::from_f32(2.5).unwrap(); let result = q1 / q2; @@ -189,24 +204,40 @@ mod tests { } #[test] - fn test_div_assign() { + fn test_div_decimal_u8() { let exp_result = ParsedQuantity { value: Decimal::from_f32(2.0).unwrap(), scale: Scale::Kilo, format: Format::BinarySI, }; - let mut q1 = ParsedQuantity { - value: Decimal::from_f32(4.0).unwrap(), + let q1 = ParsedQuantity { + value: Decimal::from_f32(6.0).unwrap(), scale: Scale::Kilo, format: Format::BinarySI, }; - let q2 = ParsedQuantity { + let q2 = 3; + + let result = q1 / q2; + + assert_eq!(result, exp_result); + } + + #[test] + fn test_div_assign() { + let exp_result = ParsedQuantity { value: Decimal::from_f32(2.0).unwrap(), - scale: Scale::One, + scale: Scale::Kilo, format: Format::BinarySI, }; + let mut q1 = ParsedQuantity { + value: Decimal::from_f32(4.0).unwrap(), + scale: Scale::Kilo, + format: Format::BinarySI, + }; + let q2 = Decimal::from_f32(2.0).unwrap(); + q1 /= q2; assert_eq!(q1, exp_result); @@ -225,12 +256,48 @@ mod tests { scale: Scale::Kilo, format: Format::BinarySI, }; - let q2 = ParsedQuantity { - value: Decimal::from_f32(2.0).unwrap(), - scale: Scale::One, + let q2 = Decimal::from_f32(2.0).unwrap(); + + let result = q1 * q2; + + assert_eq!(result, exp_result); + } + + #[test] + fn test_mul_f32() { + let exp_result = ParsedQuantity { + value: Decimal::from_f32(10.0).unwrap(), + scale: Scale::Kilo, + format: Format::BinarySI, + }; + + let q1 = ParsedQuantity { + value: Decimal::from_f32(5.0).unwrap(), + scale: Scale::Kilo, + format: Format::BinarySI, + }; + let q2 = Decimal::from_f32(2.0).unwrap(); + + let result = q1 * q2; + + assert_eq!(result, exp_result); + } + + #[test] + fn test_mul_u8() { + let exp_result = ParsedQuantity { + value: Decimal::from_f32(9.0).unwrap(), + scale: Scale::Kilo, format: Format::BinarySI, }; + let q1 = ParsedQuantity { + value: Decimal::from_f32(4.5).unwrap(), + scale: Scale::Kilo, + format: Format::BinarySI, + }; + let q2 = 2; + let result = q1 * q2; assert_eq!(result, exp_result); @@ -249,11 +316,7 @@ mod tests { scale: Scale::Kilo, format: Format::BinarySI, }; - let q2 = ParsedQuantity { - value: Decimal::from_f32(2.0).unwrap(), - scale: Scale::One, - format: Format::BinarySI, - }; + let q2 = Decimal::from_f32(2.0).unwrap(); q1 *= q2; diff --git a/src/quantity.rs b/src/quantity.rs index f68ace7..3af50c8 100644 --- a/src/quantity.rs +++ b/src/quantity.rs @@ -2,7 +2,7 @@ use std::{ cmp::{Eq, Ord, PartialEq, PartialOrd}, default::Default, fmt::Display, - ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign, Div, DivAssign}, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; use rust_decimal::prelude::*; @@ -47,6 +47,16 @@ impl Display for ParsedQuantity { } } +impl From for ParsedQuantity { + fn from(value: Decimal) -> Self { + Self { + value, + format: Format::DecimalSI, + scale: Scale::One, + } + } +} + // Standard operations on parsed quantities impl Add for ParsedQuantity { type Output = Self; @@ -102,56 +112,36 @@ impl Sub for ParsedQuantity { } } -impl Div for ParsedQuantity { +impl Div for ParsedQuantity +where + T: Into, +{ type Output = Self; - fn div(self, rhs: Self) -> Self::Output { - let mut lhs = self; - let mut rhs = rhs; - - // Bring both quantities to the same format - // - If the formats are different, use the lhs format as output format and - // multiply the rhs value by the format multiplier - normalize_formats(&mut lhs, &mut rhs); - - // Bring both scales to the same ones - // - If the scales are different, use the smaller scale as output scale - normalize_scales(&mut lhs, &mut rhs); - - // Divide the normalized values - let value = lhs.value.div(rhs.value).normalize(); + fn div(self, rhs: T) -> Self::Output { + let rhs: Decimal = rhs.into(); Self { - value, - scale: lhs.scale, - format: lhs.format, + value: self.value / rhs, + scale: self.scale, + format: self.format, } } } -impl Mul for ParsedQuantity { +impl Mul for ParsedQuantity +where + T: Into, +{ type Output = Self; - fn mul(self, rhs: Self) -> Self::Output { - let mut lhs = self; - let mut rhs = rhs; - - // Bring both quantities to the same format - // - If the formats are different, use the lhs format as output format and - // multiply the rhs value by the format multiplier - normalize_formats(&mut lhs, &mut rhs); - - // Bring both scales to the same ones - // - If the scales are different, use the smaller scale as output scale - normalize_scales(&mut lhs, &mut rhs); - - // Multiply the normalized values - let value = lhs.value.mul(rhs.value).normalize(); + fn mul(self, rhs: T) -> Self::Output { + let rhs: Decimal = rhs.into(); Self { - value, - scale: lhs.scale, - format: lhs.format, + value: self.value * rhs, + scale: self.scale, + format: self.format, } } } @@ -190,25 +180,25 @@ impl SubAssign for ParsedQuantity { } } -impl MulAssign for ParsedQuantity { - fn mul_assign(&mut self, rhs: Self) { - let mut rhs = rhs; - - normalize_formats(self, &mut rhs); - normalize_scales(self, &mut rhs); +impl MulAssign for ParsedQuantity +where + T: Into, +{ + fn mul_assign(&mut self, rhs: T) { + let rhs: Decimal = rhs.into(); - self.value.mul_assign(rhs.value); + self.value.mul_assign(rhs); } } -impl DivAssign for ParsedQuantity { - fn div_assign(&mut self, rhs: Self) { - let mut rhs = rhs; - - normalize_formats(self, &mut rhs); - normalize_scales(self, &mut rhs); +impl DivAssign for ParsedQuantity +where + T: Into, +{ + fn div_assign(&mut self, rhs: T) { + let rhs: Decimal = rhs.into(); - self.value.div_assign(rhs.value); + self.value.div_assign(rhs); } } @@ -527,18 +517,6 @@ fn normalize_scales(lhs: &mut ParsedQuantity, rhs: &mut ParsedQuantity) { fn normalize_formats(lhs: &mut ParsedQuantity, rhs: &mut ParsedQuantity) { match (&lhs.format, &rhs.format) { (Format::BinarySI, Format::BinarySI) => {} - // (Format::BinarySI, Format::DecimalExponent) => { - // let value = (rhs.value) - // .mul( - // Decimal::from_f32((1024_f32 / 1000_f32).pow(rhs.scale.clone().into())) - // .unwrap_or_default() - // .normalize(), - // ) - // .normalize(); - - // rhs.value = value; - // rhs.format = Format::BinarySI; - // } (Format::BinarySI, Format::DecimalSI) => { let value = rhs .value @@ -552,9 +530,6 @@ fn normalize_formats(lhs: &mut ParsedQuantity, rhs: &mut ParsedQuantity) { rhs.value = value; rhs.format = Format::BinarySI; } - // (Format::DecimalExponent, Format::BinarySI) => todo!(), - // (Format::DecimalExponent, Format::DecimalExponent) => {} - // (Format::DecimalExponent, Format::DecimalSI) => todo!(), (Format::DecimalSI, Format::BinarySI) => { let value = rhs .value @@ -568,9 +543,6 @@ fn normalize_formats(lhs: &mut ParsedQuantity, rhs: &mut ParsedQuantity) { rhs.value = value; rhs.format = Format::DecimalSI; } - // (Format::DecimalSI, Format::DecimalExponent) => { - // rhs.format = Format::DecimalSI; - // } (Format::DecimalSI, Format::DecimalSI) => {} }; }