use core::cmp::Ordering;
use crate::ErrorKind;
pub trait Number: Copy + Default {
fn parse(literal: &str) -> Option<Self>;
fn add(self, rhs: Self) -> Result<Self, ErrorKind>;
fn subtract(self, rhs: Self) -> Result<Self, ErrorKind>;
fn multiply(self, rhs: Self) -> Result<Self, ErrorKind>;
fn divide(self, rhs: Self) -> Result<Self, ErrorKind>;
fn remainder(self, rhs: Self) -> Result<Self, ErrorKind>;
fn power(self, rhs: Self) -> Result<Self, ErrorKind>;
fn negate(self) -> Result<Self, ErrorKind>;
fn compare(self, rhs: Self) -> Result<Ordering, ErrorKind> {
let _ = rhs;
Err(ErrorKind::Unsupported)
}
fn is_zero(self) -> Result<bool, ErrorKind> {
self.compare(Self::default())
.map(|ordering| ordering == Ordering::Equal)
}
fn from_bool(value: bool) -> Result<Self, ErrorKind> {
Self::parse(if value { "1" } else { "0" }).ok_or(ErrorKind::Unsupported)
}
fn factorial(self) -> Result<Self, ErrorKind> {
factorial(self)
}
}
pub(crate) const MAX_FACTORIAL: usize = 10_000;
fn factorial<N: Number>(n: N) -> Result<N, ErrorKind> {
let one = N::from_bool(true)?;
let mut count = N::from_bool(false)?;
let mut ordering = count.compare(n)?;
if ordering == Ordering::Greater || !n.remainder(one)?.is_zero()? {
return Err(ErrorKind::Domain);
}
let mut product = one;
let mut steps = 0;
while ordering == Ordering::Less {
if steps == MAX_FACTORIAL {
return Err(ErrorKind::Overflow);
}
steps += 1;
count = count.add(one)?;
ordering = count.compare(n)?;
if ordering == Ordering::Greater {
break;
}
product = product.multiply(count)?;
}
match ordering {
Ordering::Equal => Ok(product),
_ => Err(ErrorKind::Domain),
}
}
#[cfg(feature = "libm")]
macro_rules! float {
($type:ty, $power:path) => {
impl Number for $type {
fn parse(literal: &str) -> Option<Self> {
literal
.parse()
.ok()
.filter(|value: &$type| value.is_finite())
}
fn add(self, rhs: Self) -> Result<Self, ErrorKind> {
check(self, rhs, self + rhs)
}
fn subtract(self, rhs: Self) -> Result<Self, ErrorKind> {
check(self, rhs, self - rhs)
}
fn multiply(self, rhs: Self) -> Result<Self, ErrorKind> {
check(self, rhs, self * rhs)
}
fn divide(self, rhs: Self) -> Result<Self, ErrorKind> {
if rhs == 0.0 {
return Err(ErrorKind::DivisionByZero);
}
check(self, rhs, self / rhs)
}
fn remainder(self, rhs: Self) -> Result<Self, ErrorKind> {
if rhs == 0.0 {
return Err(ErrorKind::DivisionByZero);
}
check(self, rhs, self % rhs)
}
fn power(self, rhs: Self) -> Result<Self, ErrorKind> {
if self == 0.0 && rhs < 0.0 {
return Err(ErrorKind::DivisionByZero);
}
check(self, rhs, $power(self, rhs))
}
fn negate(self) -> Result<Self, ErrorKind> {
Ok(-self)
}
fn compare(self, rhs: Self) -> Result<Ordering, ErrorKind> {
self.partial_cmp(&rhs).ok_or(ErrorKind::Domain)
}
fn is_zero(self) -> Result<bool, ErrorKind> {
if self.is_nan() {
return Err(ErrorKind::Domain);
}
Ok(self == 0.0)
}
fn from_bool(value: bool) -> Result<Self, ErrorKind> {
Ok(if value { 1.0 } else { 0.0 })
}
}
impl Checked for $type {
fn is_nan(self) -> bool {
<$type>::is_nan(self)
}
fn is_infinite(self) -> bool {
<$type>::is_infinite(self)
}
}
};
}
#[cfg(feature = "libm")]
trait Checked: Copy {
fn is_nan(self) -> bool;
fn is_infinite(self) -> bool;
}
#[cfg(feature = "libm")]
fn check<T: Checked>(left: T, right: T, result: T) -> Result<T, ErrorKind> {
let finite = |value: T| !value.is_nan() && !value.is_infinite();
if finite(left) && finite(right) {
if result.is_nan() {
return Err(ErrorKind::Domain);
}
if result.is_infinite() {
return Err(ErrorKind::Overflow);
}
}
Ok(result)
}
#[cfg(feature = "libm")]
float!(f32, libm::powf);
#[cfg(feature = "libm")]
float!(f64, libm::pow);
macro_rules! integer {
($($type:ty),*) => {$(
impl Number for $type {
fn parse(literal: &str) -> Option<Self> {
literal.parse().ok()
}
fn add(self, rhs: Self) -> Result<Self, ErrorKind> {
self.checked_add(rhs).ok_or(ErrorKind::Overflow)
}
fn subtract(self, rhs: Self) -> Result<Self, ErrorKind> {
self.checked_sub(rhs).ok_or(ErrorKind::Overflow)
}
fn multiply(self, rhs: Self) -> Result<Self, ErrorKind> {
self.checked_mul(rhs).ok_or(ErrorKind::Overflow)
}
fn divide(self, rhs: Self) -> Result<Self, ErrorKind> {
if rhs == 0 {
return Err(ErrorKind::DivisionByZero);
}
self.checked_div(rhs).ok_or(ErrorKind::Overflow)
}
fn remainder(self, rhs: Self) -> Result<Self, ErrorKind> {
if rhs == 0 {
return Err(ErrorKind::DivisionByZero);
}
self.checked_rem(rhs).ok_or(ErrorKind::Overflow)
}
#[allow(unused_comparisons)]
fn power(self, rhs: Self) -> Result<Self, ErrorKind> {
if rhs < 0 {
return Err(ErrorKind::Domain);
}
let exponent = u32::try_from(rhs).map_err(|_| ErrorKind::Overflow)?;
self.checked_pow(exponent).ok_or(ErrorKind::Overflow)
}
fn negate(self) -> Result<Self, ErrorKind> {
(0 as $type).checked_sub(self).ok_or(ErrorKind::Overflow)
}
fn compare(self, rhs: Self) -> Result<Ordering, ErrorKind> {
Ok(self.cmp(&rhs))
}
fn is_zero(self) -> Result<bool, ErrorKind> {
Ok(self == 0)
}
fn from_bool(value: bool) -> Result<Self, ErrorKind> {
Ok(Self::from(value))
}
}
)*};
}
integer!(
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn integers_report_overflow_and_division_by_zero() {
assert_eq!(i8::MAX.add(1), Err(ErrorKind::Overflow));
assert_eq!(i8::MIN.divide(-1), Err(ErrorKind::Overflow));
assert_eq!(7_i32.divide(0), Err(ErrorKind::DivisionByZero));
assert_eq!(7_i32.remainder(0), Err(ErrorKind::DivisionByZero));
assert_eq!(1_u8.negate(), Err(ErrorKind::Overflow));
assert_eq!(0_u8.negate(), Ok(0));
assert_eq!(i8::MIN.negate(), Err(ErrorKind::Overflow));
}
#[test]
fn integers_raise_to_non_negative_powers() {
assert_eq!(2_i32.power(10), Ok(1024));
assert_eq!(2_i32.power(-1), Err(ErrorKind::Domain));
assert_eq!(2_i32.power(31), Err(ErrorKind::Overflow));
assert_eq!(1_u64.power(u64::MAX), Err(ErrorKind::Overflow));
}
#[test]
fn integers_reject_fractional_literals() {
assert_eq!(i32::parse("42"), Some(42));
assert_eq!(i32::parse("4.2"), None);
assert_eq!(u8::parse("256"), None);
}
#[cfg(feature = "libm")]
#[test]
fn floats_report_errors_instead_of_special_values() {
assert_eq!(1.0_f64.divide(0.0), Err(ErrorKind::DivisionByZero));
assert_eq!(1.0_f64.remainder(0.0), Err(ErrorKind::DivisionByZero));
assert_eq!(f64::MAX.multiply(2.0), Err(ErrorKind::Overflow));
assert_eq!((-8.0_f64).power(0.5), Err(ErrorKind::Domain));
assert_eq!(0.0_f64.power(-1.0), Err(ErrorKind::DivisionByZero));
assert_eq!(2.0_f32.power(3.0), Ok(8.0));
assert_eq!(f64::parse("1e3"), Some(1000.0));
}
#[test]
fn integers_compare_and_convert_booleans() {
assert_eq!(3_u8.compare(4), Ok(Ordering::Less));
assert_eq!((-1_i64).compare(-1), Ok(Ordering::Equal));
assert_eq!(0_u128.is_zero(), Ok(true));
assert_eq!((-5_i8).is_zero(), Ok(false));
assert_eq!(i16::from_bool(true), Ok(1));
assert_eq!(usize::from_bool(false), Ok(0));
}
#[cfg(feature = "libm")]
#[test]
fn floats_compare_and_reject_nan() {
assert_eq!(1.5_f64.compare(-2.0), Ok(Ordering::Greater));
assert_eq!((-0.0_f32).compare(0.0), Ok(Ordering::Equal));
assert_eq!(f64::NAN.compare(1.0), Err(ErrorKind::Domain));
assert_eq!(1.0_f32.compare(f32::NAN), Err(ErrorKind::Domain));
assert_eq!((-0.0_f64).is_zero(), Ok(true));
assert_eq!(f64::INFINITY.is_zero(), Ok(false));
assert_eq!(f32::NAN.is_zero(), Err(ErrorKind::Domain));
assert_eq!(f64::from_bool(true), Ok(1.0));
assert_eq!(f32::from_bool(false), Ok(0.0));
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
struct Plain(i32);
impl Number for Plain {
fn parse(literal: &str) -> Option<Self> {
literal.parse().ok().map(Self)
}
fn add(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0 + rhs.0))
}
fn subtract(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0 - rhs.0))
}
fn multiply(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0 * rhs.0))
}
fn divide(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0 / rhs.0))
}
fn remainder(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0 % rhs.0))
}
fn power(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0.pow(rhs.0.unsigned_abs())))
}
fn negate(self) -> Result<Self, ErrorKind> {
Ok(Self(-self.0))
}
}
#[test]
fn defaults_report_unsupported_comparisons() {
assert_eq!(Plain(1).compare(Plain(2)), Err(ErrorKind::Unsupported));
assert_eq!(Plain(1).is_zero(), Err(ErrorKind::Unsupported));
assert_eq!(Plain::from_bool(true), Ok(Plain(1)));
assert_eq!(Plain::from_bool(false), Ok(Plain(0)));
assert_eq!(Plain(3).factorial(), Err(ErrorKind::Unsupported));
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
struct Saturating(u64);
impl Number for Saturating {
fn parse(literal: &str) -> Option<Self> {
literal.parse().ok().map(Self)
}
fn add(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0.saturating_add(rhs.0)))
}
fn subtract(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0.saturating_sub(rhs.0)))
}
fn multiply(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0.saturating_mul(rhs.0)))
}
fn divide(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0 / rhs.0))
}
fn remainder(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0 % rhs.0))
}
fn power(self, rhs: Self) -> Result<Self, ErrorKind> {
Ok(Self(self.0.saturating_pow(rhs.0 as u32)))
}
fn negate(self) -> Result<Self, ErrorKind> {
Ok(self)
}
fn compare(self, rhs: Self) -> Result<Ordering, ErrorKind> {
Ok(self.0.cmp(&rhs.0))
}
}
#[test]
fn factorials_stop_after_a_bounded_number_of_steps() {
assert_eq!(Saturating(0).factorial(), Ok(Saturating(1)));
assert_eq!(Saturating(4).factorial(), Ok(Saturating(24)));
let last = MAX_FACTORIAL as u64;
assert_eq!(Saturating(last).factorial(), Ok(Saturating(u64::MAX)));
assert_eq!(Saturating(last + 1).factorial(), Err(ErrorKind::Overflow));
assert_eq!(Saturating(u64::MAX).factorial(), Err(ErrorKind::Overflow));
}
#[cfg(feature = "libm")]
#[test]
fn floats_propagate_non_finite_operands() {
assert_eq!(f64::INFINITY.add(1.0), Ok(f64::INFINITY));
assert!(f64::NAN.add(1.0).unwrap().is_nan());
}
}