Skip to content

Commit

Permalink
common/math: Cleanup and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
sophie-h committed Nov 8, 2024
1 parent b6bb687 commit fd31605
Showing 1 changed file with 38 additions and 62 deletions.
100 changes: 38 additions & 62 deletions gufo-common/src/math.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Math utils
#[derive(Debug, thiserror::Error, Clone, Copy)]
pub enum MathError {
#[error("Operation {0:?} + {1:?} failed")]
Expand All @@ -10,20 +12,21 @@ pub enum MathError {
DivFailed(Option<i128>, Option<i128>),
#[error("Conversion failed for value {0:?}")]
ConversionFailed(Option<i128>),
#[error("Division Not Finite")]
DivisionNotFinite,
#[error("Negation overflowed")]
NegationOverflow,
#[error("Division {0:?} / {1:?} not finite")]
DivisionNotFinite(Option<f64>, Option<f64>),
#[error("Negation overflowed for {0:?}")]
NegationOverflow(Option<i128>),
}

/// Container for safe integers operators
///
/// ```
/// # 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<T>(Result<T, MathError>);
Expand All @@ -33,6 +36,7 @@ impl<T> Checked<T> {
Self(Ok(val))
}

/// Returns the result of the calculation
pub fn check(self) -> Result<T, MathError> {
self.0
}
Expand All @@ -54,7 +58,7 @@ impl<T> std::ops::Deref for Checked<T> {

#[macro_export]
/**
* Rederines variables as [`Checked`].
* Redefines variables as [`Checked`].
*
* ```
* use gufo_common::math::checked;
Expand Down Expand Up @@ -90,6 +94,7 @@ macro_rules! checked [
};
];

/// Redefines variables as mutable [`Checked`].
#[doc(hidden)]
#[macro_export]
macro_rules! mut_checked [
Expand Down Expand Up @@ -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 {}
};
}

Expand All @@ -214,54 +225,40 @@ pub trait ToU16: Sized + TryInto<u16> + TryInto<i128> + 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<u32> + TryInto<i128> + Copy {
fn u32(self) -> Result<u32, MathError> {
self.try_into()
.map_err(|_| MathError::ConversionFailed(self.try_into().ok()))
}
}

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<i64> + TryInto<i128> + Copy {
fn i64(self) -> Result<i64, MathError> {
pub trait ToU64: Sized + TryInto<u64> + TryInto<i128> + Copy {
fn u64(self) -> Result<u64, MathError> {
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<i16> + TryInto<i128> + Copy {
fn i16(self) -> Result<i16, MathError> {
self.try_into()
.map_err(|_| MathError::ConversionFailed(self.try_into().ok()))
}
}

pub trait ToU64: Sized + TryInto<u64> + TryInto<i128> + Copy {
fn u64(self) -> Result<u64, MathError> {
pub trait ToI32: Sized + TryInto<i32> + TryInto<i128> + Copy {
fn i32(self) -> Result<i32, MathError> {
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<i64> + TryInto<i128> + Copy {
fn i64(self) -> Result<i64, MathError> {
self.try_into()
.map_err(|_| MathError::ConversionFailed(self.try_into().ok()))
}
}

pub trait ToUsize: Sized + TryInto<usize> + TryInto<i128> + Copy {
fn usize(self) -> Result<usize, MathError> {
Expand All @@ -270,13 +267,6 @@ pub trait ToUsize: Sized + TryInto<usize> + TryInto<i128> + 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<Self, MathError>;
Expand All @@ -292,6 +282,7 @@ pub trait SafeMul: Sized {
fn safe_mul(self, rhs: Self) -> Result<Self, MathError>;
}

/// Same as `checked_dev` functions but returns an error
pub trait SafeDiv: Sized {
fn safe_div(self, rhs: Self) -> Result<Self, MathError>;
}
Expand All @@ -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)
}
Expand All @@ -315,26 +306,11 @@ pub trait SafeNeg: Sized {

impl SafeNeg for i64 {
fn safe_neg(self) -> Result<Self, MathError> {
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
///
/// <https://en.wikipedia.org/wiki/APEX_system>
Expand Down

0 comments on commit fd31605

Please sign in to comment.