diff --git a/Cargo.toml b/Cargo.toml index bc10045..017a533 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kube_quantity" -version = "0.7.1" +version = "0.8.0" authors = ["Thomas Kosiewski "] description = "kube_quantity is a library adding arithmetic operations to the Quantity type from the k8s-openapi crate." diff --git a/src/lib.rs b/src/lib.rs index ed3b641..88f4265 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,8 +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 crate::{ParseQuantityError, ParsedQuantity}; + use crate::format::Format; + use crate::scale::Scale; #[test] fn test_quantity_addition() { @@ -158,4 +162,101 @@ mod tests { assert!(q.is_err()); assert_eq!(q.unwrap_err().to_string(), "quantity parsing failed"); } + + + #[test] + fn test_div() { + let exp_result = ParsedQuantity { + value: Decimal::from_f32(2.0).unwrap(), + scale: Scale::Kilo, + format: Format::BinarySI, + }; + + let q1 = ParsedQuantity { + value: Decimal::from_f32(4.0).unwrap(), + scale: Scale::Kilo, + format: Format::BinarySI, + }; + let q2 = ParsedQuantity { + value: Decimal::from_f32(2.0).unwrap(), + scale: Scale::One, + format: Format::BinarySI, + }; + + 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::Kilo, + format: Format::BinarySI, + }; + + let mut q1 = ParsedQuantity { + value: Decimal::from_f32(4.0).unwrap(), + scale: Scale::Kilo, + format: Format::BinarySI, + }; + let q2 = ParsedQuantity { + value: Decimal::from_f32(2.0).unwrap(), + scale: Scale::One, + format: Format::BinarySI, + }; + + q1 /= q2; + + assert_eq!(q1, exp_result); + } + + #[test] + fn test_mul() { + let exp_result = ParsedQuantity { + value: Decimal::from_f32(8.0).unwrap(), + scale: Scale::Kilo, + format: Format::BinarySI, + }; + + let q1 = ParsedQuantity { + value: Decimal::from_f32(4.0).unwrap(), + scale: Scale::Kilo, + format: Format::BinarySI, + }; + let q2 = ParsedQuantity { + value: Decimal::from_f32(2.0).unwrap(), + scale: Scale::One, + format: Format::BinarySI, + }; + + let result = q1 * q2; + + assert_eq!(result, exp_result); + } + + #[test] + fn test_mul_assign() { + let exp_result = ParsedQuantity { + value: Decimal::from_f32(8.0).unwrap(), + 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 = ParsedQuantity { + value: Decimal::from_f32(2.0).unwrap(), + scale: Scale::One, + format: Format::BinarySI, + }; + + q1 *= q2; + + assert_eq!(q1, exp_result); + } } diff --git a/src/quantity.rs b/src/quantity.rs index fc10194..f68ace7 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, Neg, Sub, SubAssign}, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign, Div, DivAssign}, }; use rust_decimal::prelude::*; @@ -102,6 +102,60 @@ impl Sub for ParsedQuantity { } } +impl Div for ParsedQuantity { + 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(); + + Self { + value, + scale: lhs.scale, + format: lhs.format, + } + } +} + +impl Mul for ParsedQuantity { + 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(); + + Self { + value, + scale: lhs.scale, + format: lhs.format, + } + } +} + impl Neg for ParsedQuantity { type Output = Self; @@ -136,6 +190,28 @@ 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); + + self.value.mul_assign(rhs.value); + } +} + +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); + + self.value.div_assign(rhs.value); + } +} + impl PartialEq for ParsedQuantity { fn eq(&self, other: &Self) -> bool { let mut lhs = self.clone();