use rust_decimal::Decimal; use rust_decimal::prelude::*; use std::ops::{Add, Div, Mul}; /// This trait houses various methods for making instructions /// more generic instead of declaring a separate function for each /// stack. In a way I'm doing that here, but in a more Rusty way. /// /// Trig functions named safe rather than checked to not overlap /// with Decimal library's checked function names. pub trait NumericTrait: Sized + Add + Mul + Div + Ord { fn checked_div(self, v: Self) -> Option; fn checked_mod(self, v: Self) -> Option; fn increment(self) -> Self; fn decrement(self) -> Self; fn safe_sin(self) -> Option; fn safe_cos(self) -> Option; fn safe_tan(self) -> Option; fn inverse(self) -> Option; fn safe_exp(self) -> Option; fn absolute(self) -> Self; fn safe_log10(self) -> Option; fn safe_sqrt(self) -> Option; fn sign_reverse(self) -> Self; fn square(self) -> Self; fn zero() -> Self; fn from_usize(num: usize) -> Self; } impl NumericTrait for Decimal { fn checked_div(self, v: Self) -> Option { if v == dec!(0.0) { None } else { Some(self / v) } } fn checked_mod(self, v: Self) -> Option { if v == dec!(0.0) { None } else { Some(self % v) } } fn increment(self) -> Self { self + dec!(1.0) } fn decrement(self) -> Self { self - dec!(1.0) } fn safe_sin(self) -> Option { self.checked_sin() } fn safe_cos(self) -> Option { self.checked_cos() } fn safe_tan(self) -> Option { self.checked_tan() } fn inverse(self) -> Option { dec!(1.0).checked_div(self) } fn safe_exp(self) -> Option { self.checked_exp() } fn absolute(self) -> Self { self.abs() } fn safe_log10(self) -> Option { self.absolute().checked_log10() } fn safe_sqrt(self) -> Option { self.absolute().sqrt() } fn sign_reverse(self) -> Self { self * dec!(-1) } fn square(self) -> Self { self * self } fn zero() -> Self { dec!(0.0) } fn from_usize(num: usize) -> Self { rust_decimal::prelude::FromPrimitive::from_usize(num).unwrap() } } impl NumericTrait for i128 { fn checked_div(self, v: Self) -> Option { if v == 0 { None } else { Some(self / v) } } fn checked_mod(self, v: Self) -> Option { if v == 0 { None } else { Some(self % v) } } fn increment(self) -> Self { self + 1 } fn decrement(self) -> Self { self - 1 } /// Casts the i128 to a Decimal and takes the checked_sin /// of the value. Casts the calculated value back to an i128. fn safe_sin(self) -> Option { Decimal::from_i128(self)?.checked_sin()?.to_i128() } fn safe_cos(self) -> Option { Decimal::from_i128(self)?.checked_cos()?.to_i128() } fn safe_tan(self) -> Option { Decimal::from_i128(self)?.checked_tan()?.to_i128() } fn inverse(self) -> Option { if self == 0 { None } else { Some(1 / self) } } fn safe_exp(self) -> Option { Decimal::from_i128(self)?.checked_exp()?.to_i128() } fn absolute(self) -> Self { self.abs() } fn safe_log10(self) -> Option { Decimal::from_i128(self)? .absolute() .checked_log10()? .to_i128() } fn safe_sqrt(self) -> Option { Decimal::from_i128(self)?.absolute().sqrt()?.to_i128() } fn sign_reverse(self) -> Self { -1 * self } fn square(self) -> Self { self * self } fn zero() -> Self { 0 } fn from_usize(num: usize) -> Self { num as Self } } /// A trait for types to implement logical functions that work /// for push types. pub trait LogicalTrait { fn logical_and(self, v: Self) -> Self; fn logical_or(self, v: Self) -> Self; fn logical_not(self) -> Self; fn logical_xor(self, v: Self) -> Self; } impl LogicalTrait for bool { fn logical_and(self, v: Self) -> Self { self && v } fn logical_or(self, v: Self) -> Self { self || v } fn logical_not(self) -> Self { !self } fn logical_xor(self, v: Self) -> Self { match (self, v) { (true, true) | (false, false) => false, _ => true, } } } /// A trait for uniform conversions between types. pub trait CastingTrait: Sized { fn from_bool(v: bool) -> Option; fn from_int(v: i128) -> Option; fn from_float(v: Decimal) -> Option; } impl CastingTrait for i128 { fn from_bool(v: bool) -> Option { Some(if v { 1 } else { 0 }) } fn from_int(v: i128) -> Option { Some(v) } fn from_float(v: Decimal) -> Option { v.to_i128() } } impl CastingTrait for Decimal { fn from_bool(v: bool) -> Option { Some(if v { dec!(1.0) } else { dec!(0.0) }) } fn from_int(v: i128) -> Option { Decimal::from_i128(v) } fn from_float(v: Decimal) -> Option { Some(v) } } impl CastingTrait for bool { fn from_bool(v: bool) -> Option { Some(v) } fn from_int(v: i128) -> Option { Some(v != 0) } fn from_float(v: Decimal) -> Option { Some(v != dec!(0.0)) } }