MathUtils 1.0.1

A high-fidelity Rust mirror of the JavaScript (ECMAScript) Math built-in object.
Documentation
//! Declarative macros providing JavaScript-like variadic function invocation.
//!
//! In JavaScript, functions such as `Math.max()`, `Math.min()`, and `Math.hypot()` accept an
//! arbitrary number of arguments (e.g., `Math.max(1, 5, 2, 9, -3)`). In Rust, functions have a fixed
//! arity. These macros bridge that gap by accepting 0, 1, 2, or $N$ arguments of any numeric type,
//! automatically casting them to `f64` and applying the exact ECMAScript rules.

/// Computes the maximum value among zero or more numeric arguments.
///
/// Mirrors JavaScript's variadic `Math.max(...values)`.
///
/// # Behavior
///
/// - **Zero arguments (`math_max!()`)**: Returns $-\infty$ (`f64::NEG_INFINITY`), exactly matching JavaScript.
/// - **One argument (`math_max!(x)`)**: Returns `x as f64`.
/// - **Two arguments (`math_max!(x, y)`)**: Evaluates `Math::max2(x, y)`.
/// - **Multiple arguments (`math_max!(a, b, c, ...)`)**: Evaluates `Math::max(&[a, b, c, ...])`.
/// - **Special Values**:
///   - If any argument is `NaN`, returns `NaN`.
///   - If comparing `+0.0` and `-0.0`, `+0.0` is strictly chosen as the maximum (`math_max!(-0.0, 0.0) == 0.0`).
///
/// # Examples
///
/// ```
/// use MathUtils::math_max;
///
/// // Zero arguments yields negative infinity:
/// assert_eq!(math_max!(), f64::NEG_INFINITY);
///
/// // Single value:
/// assert_eq!(math_max!(42.0), 42.0);
///
/// // Multiple integer and float expressions:
/// assert_eq!(math_max!(1.5, 9.8, -3.2, 14.0, 7.1), 14.0);
/// assert_eq!(math_max!(10, 20, 5), 20.0);
///
/// // Handling NaN:
/// assert!(math_max!(1.0, f64::NAN, 5.0).is_nan());
///
/// // Positive zero is greater than negative zero:
/// let res = math_max!(-0.0, 0.0);
/// assert_eq!(res, 0.0);
/// assert!(res.is_sign_positive());
/// ```
#[macro_export]
macro_rules! math_max {
    () => {
        f64::NEG_INFINITY
    };
    ($x:expr) => {
        $x as f64
    };
    ($x:expr, $y:expr) => {
        $crate::Math::max2($x as f64, $y as f64)
    };
    ($($x:expr),+ $(,)?) => {
        $crate::Math::max(&[$($x as f64),+])
    };
}

/// Computes the minimum value among zero or more numeric arguments.
///
/// Mirrors JavaScript's variadic `Math.min(...values)`.
///
/// # Behavior
///
/// - **Zero arguments (`math_min!()`)**: Returns $+\infty$ (`f64::INFINITY`), exactly matching JavaScript.
/// - **One argument (`math_min!(x)`)**: Returns `x as f64`.
/// - **Two arguments (`math_min!(x, y)`)**: Evaluates `Math::min2(x, y)`.
/// - **Multiple arguments (`math_min!(a, b, c, ...)`)**: Evaluates `Math::min(&[a, b, c, ...])`.
/// - **Special Values**:
///   - If any argument is `NaN`, returns `NaN`.
///   - If comparing `+0.0` and `-0.0`, `-0.0` is strictly chosen as the minimum (`math_min!(0.0, -0.0) == -0.0`).
///
/// # Examples
///
/// ```
/// use MathUtils::math_min;
///
/// // Zero arguments yields positive infinity:
/// assert_eq!(math_min!(), f64::INFINITY);
///
/// // Single value:
/// assert_eq!(math_min!(42.0), 42.0);
///
/// // Multiple values:
/// assert_eq!(math_min!(1.5, 9.8, -3.2, 14.0, 7.1), -3.2);
/// assert_eq!(math_min!(10, 20, 5), 5.0);
///
/// // Handling NaN:
/// assert!(math_min!(1.0, f64::NAN, 5.0).is_nan());
///
/// // Negative zero is less than positive zero:
/// let res = math_min!(0.0, -0.0);
/// assert_eq!(res, 0.0);
/// assert!(res.is_sign_negative());
/// ```
#[macro_export]
macro_rules! math_min {
    () => {
        f64::INFINITY
    };
    ($x:expr) => {
        $x as f64
    };
    ($x:expr, $y:expr) => {
        $crate::Math::min2($x as f64, $y as f64)
    };
    ($($x:expr),+ $(,)?) => {
        $crate::Math::min(&[$($x as f64),+])
    };
}

/// Computes the square root of the sum of squares of zero or more numbers ($\sqrt{x_1^2 + x_2^2 + \dots + x_n^2}$).
///
/// Mirrors JavaScript's variadic `Math.hypot(...values)`.
///
/// # Behavior
///
/// - **Zero arguments (`math_hypot!()`)**: Returns `0.0`.
/// - **One argument (`math_hypot!(x)`)**: Returns the absolute value $|x|$.
/// - **Two or more arguments**: Computes $\sqrt{\sum x_i^2}$ using intermediate scaling to avoid overflow or underflow.
/// - **Special Values**:
///   - If any argument is $+-\infty$, returns $+\infty$ (even if another argument is `NaN`).
///   - If any argument is `NaN` and no argument is infinite, returns `NaN`.
///
/// # Examples
///
/// ```
/// use MathUtils::math_hypot;
///
/// // 2D Euclidean distance (Pythagorean 3-4-5 triangle):
/// assert_eq!(math_hypot!(3.0, 4.0), 5.0);
///
/// // 3D Euclidean distance:
/// assert_eq!(math_hypot!(1.0, 2.0, 2.0), 3.0);
///
/// // Empty arguments:
/// assert_eq!(math_hypot!(), 0.0);
///
/// // Infinity overrides NaN:
/// assert_eq!(math_hypot!(f64::INFINITY, f64::NAN), f64::INFINITY);
/// ```
#[macro_export]
macro_rules! math_hypot {
    () => {
        0.0f64
    };
    ($x:expr) => {
        $crate::Math::abs($x as f64)
    };
    ($x:expr, $y:expr) => {
        $crate::Math::hypot2($x as f64, $y as f64)
    };
    ($($x:expr),+ $(,)?) => {
        $crate::Math::hypot(&[$($x as f64),+])
    };
}