#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::module_inception)]
mod non_negative;
pub use non_negative::NonNegative;
mod non_positive;
pub use non_positive::NonPositive;
mod any_sign;
pub use any_sign::AnySign;
mod positive;
pub use positive::Positive;
mod negative;
pub use negative::Negative;
mod integer;
pub use integer::*;
mod min_max;
pub use min_max::*;
mod abs;
pub use abs::Abs;
mod signum;
pub use signum::Signum;
mod reciprocal;
pub use reciprocal::Reciprocal;
mod sqrt;
pub use sqrt::Sqrt;
mod exponent;
pub use exponent::*;
mod log;
pub use log::*;
mod rounding;
pub use rounding::*;
mod trig;
pub use trig::*;
mod nan;
pub use nan::*;
mod infinity;
pub use infinity::*;
mod epsilon;
pub use epsilon::*;
mod clamp;
pub use clamp::Clamp;
mod saturating_ops;
pub use saturating_ops::*;
mod checked_ops;
pub use checked_ops::*;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn one_trait_returns_one() {
assert_eq!(<i32 as One>::one(), 1);
assert_eq!(<f64 as One>::one(), 1.0);
}
#[test]
fn two_trait_returns_two() {
assert_eq!(<i32 as Two>::two(), 2);
assert_eq!(<f64 as Two>::two(), 2.0);
}
#[test]
fn abs_trait_matches_std() {
assert_eq!(<i32 as Abs>::abs(-5), 5);
assert_eq!(<u32 as Abs>::abs(7), 7);
assert_eq!(<f32 as Abs>::abs(-1.5), 1.5);
}
#[test]
fn signum_trait_matches_std() {
assert_eq!(<i32 as Signum>::signum(10), 1);
assert_eq!(<i32 as Signum>::signum(-10), -1);
assert_eq!(<f32 as Signum>::signum(-0.25), -1.0);
assert_eq!(<f32 as Signum>::signum(0.25), 1.0);
assert_eq!(<f32 as Signum>::signum(0.0), 1.0);
}
#[test]
fn epsilon_trait_matches_consts() {
assert_eq!(<f32 as Epsilon>::epsilon(), f32::EPSILON);
assert_eq!(<f64 as Epsilon>::epsilon(), f64::EPSILON);
}
#[test]
fn epsilon_markers_hold() {
fn assert_non_epsilon<T: NonEpsilon>() {}
fn assert_has_epsilon<T: HasEpsilon>() {}
assert_non_epsilon::<i32>();
assert_non_epsilon::<u64>();
assert_has_epsilon::<f32>();
assert_has_epsilon::<f64>();
}
#[test]
fn positive_trait_applies_to_nonzero_unsigned() {
fn assert_positive<T: Positive>() {}
assert_positive::<core::num::NonZeroU8>();
assert_positive::<core::num::NonZeroUsize>();
}
#[test]
fn reciprocal_trait_inverts_floats() {
assert!((<f32 as Reciprocal>::reciprocal(4.0) - 0.25).abs() < f32::EPSILON);
}
#[test]
fn clamp_trait_limits_values() {
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
struct Wrap(f32);
impl Clamp for Wrap {
fn clamp(self, min: Self, max: Self) -> Self {
debug_assert!(min <= max, "invalid clamp bounds");
if self < min {
min
} else if self > max {
max
} else {
self
}
}
}
let value = Wrap(5.0);
let min = Wrap(0.0);
let max = Wrap(3.0);
assert_eq!(value.clamp(min, max), Wrap(3.0));
assert_eq!(Wrap(-1.0).clamp(min, max), Wrap(0.0));
assert_eq!(Wrap(2.0).clamp(min, max), Wrap(2.0));
}
#[test]
fn saturating_add_clamps_unsigned_overflow() {
let value = <u8 as SaturatingAdd>::saturating_add(250, 10);
assert_eq!(value, u8::MAX);
}
#[test]
fn saturating_sub_clamps_signed_underflow() {
let value = <i32 as SaturatingSub>::saturating_sub(i32::MIN, 1);
assert_eq!(value, i32::MIN);
}
#[test]
fn saturating_mul_clamps_positive_overflow() {
let value = <u8 as SaturatingMul>::saturating_mul(20, 20);
assert_eq!(value, u8::MAX);
}
#[test]
fn checked_sub_returns_none_on_underflow() {
let value = <u8 as CheckedSub>::checked_sub(1, 2);
assert_eq!(value, None);
let ok = <u8 as CheckedSub>::checked_sub(5, 2);
assert_eq!(ok, Some(3));
}
#[test]
fn checked_add_returns_none_on_overflow() {
let value = <u8 as CheckedAdd>::checked_add(u8::MAX, 1);
assert_eq!(value, None);
}
#[test]
fn checked_mul_returns_none_on_overflow() {
let value = <u8 as CheckedMul>::checked_mul(20, 20);
assert_eq!(value, None);
}
#[test]
fn checked_div_returns_none_on_zero_division() {
let value = <u8 as CheckedDiv>::checked_div(1, 0);
assert_eq!(value, None);
let ok = <u8 as CheckedDiv>::checked_div(8, 2);
assert_eq!(ok, Some(4));
}
#[test]
fn checked_rem_returns_none_on_zero_division() {
let value = <u8 as CheckedRem>::checked_rem(1, 0);
assert_eq!(value, None);
let ok = <u8 as CheckedRem>::checked_rem(7, 4);
assert_eq!(ok, Some(3));
}
#[test]
fn checked_neg_returns_none_on_min_value() {
let value = <i32 as CheckedNeg>::checked_neg(i32::MIN);
assert_eq!(value, None);
let ok = <i32 as CheckedNeg>::checked_neg(5);
assert_eq!(ok, Some(-5));
}
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn sqrt_matches_std() {
assert_eq!(<f32 as Sqrt>::sqrt(4.0), 2.0);
}
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn pow_matches_std() {
assert_eq!(<f32 as Pow>::pow(2.0, 3.0), 8.0);
assert_eq!(<i32 as Pow<u32>>::pow(2, 3), 8);
}
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn root_matches_std() {
let result = <f32 as Root>::root(27.0, 3.0);
assert!((result - 3.0).abs() < 1e-3);
}
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn exp_matches_std() {
assert!((<f32 as Exp>::exp(1.0) - core::f32::consts::E).abs() < 1e-3);
}
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn log_matches_std() {
let v = <f32 as Log>::ln(core::f32::consts::E);
assert!((v - 1.0).abs() < 1e-3);
}
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn log_variants_match_std() {
let v2 = <f32 as Log2>::log2(8.0);
assert!((v2 - 3.0).abs() < 1e-6);
let v10 = <f32 as Log10>::log10(100.0);
assert!((v10 - 2.0).abs() < 1e-6);
let v_base = <f32 as LogBase>::log_base(27.0, 3.0);
assert!((v_base - 3.0).abs() < 1e-6);
}
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn cbrt_matches_std() {
let v = <f64 as Cbrt>::cbrt(27.0);
assert!((v - 3.0).abs() < 1e-9);
}
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn hypot_matches_std() {
let v = <f32 as Hypot>::hypot(3.0, 4.0);
assert!((v - 5.0).abs() < 1e-6);
}
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn rounding_matches_std() {
assert_eq!(<f32 as Floor>::floor(1.9), 1.0);
assert_eq!(<f32 as Ceil>::ceil(1.1), 2.0);
assert_eq!(<f32 as Round>::round(1.5), 2.0);
assert_eq!(<f32 as Trunc>::trunc(-1.9), -1.0);
}
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn trig_matches_std() {
let v = <f32 as Sin>::sin(core::f32::consts::FRAC_PI_2);
assert!((v - 1.0).abs() < 1e-6);
let v = <f32 as Cos>::cos(core::f32::consts::PI);
assert!((v + 1.0).abs() < 1e-6);
let v = <f32 as Tan>::tan(0.0);
assert!(v.abs() < 1e-6);
let v = <f32 as Asin>::asin(0.0);
assert!(v.abs() < 1e-6);
let v = <f32 as Acos>::acos(1.0);
assert!(v.abs() < 1e-6);
let v = <f32 as Atan>::atan(1.0);
assert!((v - core::f32::consts::FRAC_PI_4).abs() < 1e-6);
let v = <f32 as Atan2>::atan2(0.0, 1.0);
assert!(v.abs() < 1e-6);
}
#[test]
fn nan_markers_hold() {
fn assert_non_nan<T: NonNan>() {}
fn assert_has_nan<T: HasNan>() {}
assert_non_nan::<i32>();
assert_non_nan::<u64>();
assert_has_nan::<f32>();
assert_has_nan::<f64>();
assert!(<f32 as Nan>::nan().is_nan());
}
#[test]
fn infinity_markers_hold() {
fn assert_non_inf<T: NonAnySignInfinity>() {}
fn assert_non_pos_inf<T: NonPositiveInfinity>() {}
fn assert_non_neg_inf<T: NonNegativeInfinity>() {}
fn assert_pos_inf<T: HasPositiveInfinity>() {}
fn assert_neg_inf<T: HasNegativeInfinity>() {}
assert_non_inf::<i32>();
assert_non_inf::<u64>();
assert_non_inf::<f32>();
assert_non_inf::<f64>();
assert_non_pos_inf::<i32>();
assert_non_pos_inf::<u64>();
assert_non_neg_inf::<i32>();
assert_non_neg_inf::<u64>();
assert_pos_inf::<f32>();
assert_pos_inf::<f64>();
assert_neg_inf::<f32>();
assert_neg_inf::<f64>();
assert!(<f32 as PositiveInfinity>::positive_infinity().is_infinite());
assert!(<f32 as NegativeInfinity>::negative_infinity().is_infinite());
}
}