From fd31605dc70efa6896f72898525977a845446a42 Mon Sep 17 00:00:00 2001 From: Sophie Herold Date: Fri, 8 Nov 2024 23:09:02 +0100 Subject: [PATCH] common/math: Cleanup and docs --- gufo-common/src/math.rs | 100 +++++++++++++++------------------------- 1 file changed, 38 insertions(+), 62 deletions(-) diff --git a/gufo-common/src/math.rs b/gufo-common/src/math.rs index 40788c6..346a3ca 100644 --- a/gufo-common/src/math.rs +++ b/gufo-common/src/math.rs @@ -1,3 +1,5 @@ +//! Math utils + #[derive(Debug, thiserror::Error, Clone, Copy)] pub enum MathError { #[error("Operation {0:?} + {1:?} failed")] @@ -10,10 +12,10 @@ pub enum MathError { DivFailed(Option, Option), #[error("Conversion failed for value {0:?}")] ConversionFailed(Option), - #[error("Division Not Finite")] - DivisionNotFinite, - #[error("Negation overflowed")] - NegationOverflow, + #[error("Division {0:?} / {1:?} not finite")] + DivisionNotFinite(Option, Option), + #[error("Negation overflowed for {0:?}")] + NegationOverflow(Option), } /// Container for safe integers operators @@ -21,9 +23,10 @@ pub enum MathError { /// ``` /// # use gufo_common::math::Checked; /// let x = Checked::new(2_u32); -/// let y = Checked::new(3_u32); /// -/// assert_eq!((x + y).unwrap(), 5); +/// assert_eq!((x + 3).unwrap(), 5); +/// assert!(matches!((x + 4).check(), Ok(6))); +/// assert!((x + u32::MAX).is_err()); /// ``` #[derive(Debug, Clone, Copy)] pub struct Checked(Result); @@ -33,6 +36,7 @@ impl Checked { Self(Ok(val)) } + /// Returns the result of the calculation pub fn check(self) -> Result { self.0 } @@ -54,7 +58,7 @@ impl std::ops::Deref for Checked { #[macro_export] /** - * Rederines variables as [`Checked`]. + * Redefines variables as [`Checked`]. * * ``` * use gufo_common::math::checked; @@ -90,6 +94,7 @@ macro_rules! checked [ }; ]; +/// Redefines variables as mutable [`Checked`]. #[doc(hidden)] #[macro_export] macro_rules! mut_checked [ @@ -188,6 +193,12 @@ macro_rules! impl_casts { impl_cast!($t, i32); impl_cast!($t, i64); impl_cast!($t, usize); + + impl ToU16 for $t {} + impl ToU32 for $t {} + impl ToU64 for $t {} + impl ToI64 for $t {} + impl ToUsize for $t {} }; } @@ -214,13 +225,6 @@ pub trait ToU16: Sized + TryInto + TryInto + Copy { } } -impl ToU16 for i16 {} -impl ToU16 for i32 {} -impl ToU16 for u32 {} -impl ToU16 for i64 {} -impl ToU16 for u64 {} -impl ToU16 for usize {} - pub trait ToU32: Sized + TryInto + TryInto + Copy { fn u32(self) -> Result { self.try_into() @@ -228,40 +232,33 @@ pub trait ToU32: Sized + TryInto + TryInto + Copy { } } -impl ToU32 for i16 {} -impl ToU32 for u16 {} -impl ToU32 for i32 {} -impl ToU32 for i64 {} -impl ToU32 for u64 {} -impl ToU32 for usize {} - -pub trait ToI64: Sized + TryInto + TryInto + Copy { - fn i64(self) -> Result { +pub trait ToU64: Sized + TryInto + TryInto + Copy { + fn u64(self) -> Result { self.try_into() .map_err(|_| MathError::ConversionFailed(self.try_into().ok())) } } -impl ToI64 for i16 {} -impl ToI64 for u16 {} -impl ToI64 for i32 {} -impl ToI64 for u32 {} -impl ToI64 for u64 {} -impl ToI64 for usize {} +pub trait ToI16: Sized + TryInto + TryInto + Copy { + fn i16(self) -> Result { + self.try_into() + .map_err(|_| MathError::ConversionFailed(self.try_into().ok())) + } +} -pub trait ToU64: Sized + TryInto + TryInto + Copy { - fn u64(self) -> Result { +pub trait ToI32: Sized + TryInto + TryInto + Copy { + fn i32(self) -> Result { self.try_into() .map_err(|_| MathError::ConversionFailed(self.try_into().ok())) } } -impl ToU64 for i16 {} -impl ToU64 for u16 {} -impl ToU64 for i32 {} -impl ToU64 for u32 {} -impl ToU64 for i64 {} -impl ToU64 for usize {} +pub trait ToI64: Sized + TryInto + TryInto + Copy { + fn i64(self) -> Result { + self.try_into() + .map_err(|_| MathError::ConversionFailed(self.try_into().ok())) + } +} pub trait ToUsize: Sized + TryInto + TryInto + Copy { fn usize(self) -> Result { @@ -270,13 +267,6 @@ pub trait ToUsize: Sized + TryInto + TryInto + Copy { } } -impl ToUsize for i16 {} -impl ToUsize for u16 {} -impl ToUsize for i32 {} -impl ToUsize for u32 {} -impl ToUsize for i64 {} -impl ToUsize for u64 {} - /// Same as `checked_add` functions but returns an error pub trait SafeAdd: Sized { fn safe_add(self, rhs: Self) -> Result; @@ -292,6 +282,7 @@ pub trait SafeMul: Sized { fn safe_mul(self, rhs: Self) -> Result; } +/// Same as `checked_dev` functions but returns an error pub trait SafeDiv: Sized { fn safe_div(self, rhs: Self) -> Result; } @@ -301,7 +292,7 @@ impl SafeDiv for f64 { let value = self / rhs; if value.is_infinite() { - Err(MathError::DivisionNotFinite) + Err(MathError::DivisionNotFinite(Some(self), Some(rhs))) } else { Ok(value) } @@ -315,26 +306,11 @@ pub trait SafeNeg: Sized { impl SafeNeg for i64 { fn safe_neg(self) -> Result { - self.checked_neg().ok_or(MathError::NegationOverflow) + self.checked_neg() + .ok_or_else(|| MathError::NegationOverflow(self.try_into().ok())) } } -#[derive(Debug, Clone, thiserror::Error)] -pub enum MathError12 { - #[error("Addition overflowed")] - AdditionOverflowError, - #[error("Type conversion overflowed")] - ConversionOverflowError, - #[error("Substraction overflowed")] - SubstractionOverflowError, - #[error("Multiplication overflowed")] - MultiplicationOverflowError, - #[error("Negation overflowed")] - NegationOverflowError, - #[error("Division gave non-finite float")] - DivisionNotFinite, -} - /// Converts and APEX value to an F-Number /// ///