#![deny(rustdoc::broken_intra_doc_links)]

//! # Scalar Numerical Functions Module
//!
//! This module provides a collection of traits and error types for common mathematical
//! functions operating on scalar numerical values. These functions are designed to be
//! generic over different floating-point and complex number types, including support
//! for arbitrary-precision numbers via the [`rug`](https://crates.io/crates/rug) library (when the "rug" feature is enabled).
//!
//! ## Core Concepts
//!
//! - **Function Traits**: Each mathematical operation (e.g., [`Exp`], [`Ln`], [`Sin`], [`Pow`], etc.)
//!   is defined by a trait. These traits typically offer two methods:
//!     - `try_xxx()`: A fallible method that performs comprehensive validation of inputs
//!       and outputs, returning a [`Result`].
//!     - `xxx()`: An infallible method that aims for performance, especially in release
//!       builds. In debug builds, it usually calls `try_xxx().unwrap()`.
//!
//! - **Error Handling**: Errors are structured using the [`FunctionErrors`] enum, which
//!   distinguishes between input validation failures and output validation failures.
//!   Each function trait usually has an associated error type (e.g., [`ExpErrors`], [`LogarithmRealErrors`], etc.)
//!   that is a type alias for [`FunctionErrors`] specialized with function-specific
//!   input error enums (e.g., [`ExpInputErrors`], [`LogarithmRealInputErrors`], etc.).
//!
//! - **Validation**: Input and output values are typically validated using policies defined
//!   in the [`validation`](crate::validation) module (as implementation of the
//!   [`ValidationPolicy`](try_create::ValidationPolicy) trait from the [`try_create`](https://crates.io/crates/try_create) crate),
//!   with [`StrictFinitePolicy`](crate::validation::StrictFinitePolicy) being commonly used to ensure
//!   values are not NaN, Infinity, or subnormal.
//!
//! ## Provided Functions
//!
//! The module re-exports traits and error types for various categories of functions:
//!
//! - **Basic Operations**:
//!   - [`Abs`]: Absolute value.
//!   - [`NegAssign`]: In-place negation.
//!   - [`Reciprocal`]: Reciprocal (`1/x`).
//!   - [`Pow`]: Power function (`base^exponent`).
//!   - [`Sqrt`]: Square root.
//! - **Exponential and Logarithmic**:
//!   - [`Exp`]: Exponential function (`e^x`).
//!   - [`Ln`]: Natural logarithm.
//!   - [`Log2`]: Base-2 logarithm.
//!   - [`Log10`]: Base-10 logarithm.
//! - **Trigonometric**:
//!   - [`Sin`], [`Cos`], [`Tan`]: Basic trigonometric functions.
//!   - [`ASin`], [`ACos`], [`ATan`]: Inverse trigonometric functions.
//!   - [`ATan2`]: Four-quadrant inverse tangent.
//! - **Hyperbolic**:
//!   - [`SinH`], [`CosH`], [`TanH`]: Hyperbolic functions.
//!   - [`ASinH`], [`ACosH`], [`ATanH`]: Inverse hyperbolic functions.
//! - **Complex Number Operations**:
//!   - [`Arg`]: Argument (phase) of a complex number.
//!   - [`Conjugate`]: Complex conjugate.
//! - **Comparison**:
//!   - [`Max`], [`Min`]: Maximum and minimum of two numbers.
//! - **Real Number Specific**:
//!   - [`Rounding`]: Ceiling, floor, rounding operations.
//!   - [`Sign`]: Sign manipulation and checking.
//!   - [`Clamp`], [`Classify`], [`ExpM1`], [`Hypot`], [`Ln1p`], [`TotalCmp`]: Specialized real number operations.
//!
//! Each function is organized into its own submodule (e.g., `abs`, `exp`) and its
//! public interface is re-exported here.

use std::{
    fmt::LowerExp,
    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use thiserror::Error;

mod abs;
pub(crate) mod complex;
mod exponential;
mod hyperbolic;
mod logarithm;
mod max_min;
mod neg_assign;
pub(crate) mod pow;
mod real;
mod reciprocal;
pub(crate) mod sqrt;
mod trigonometric;

pub use abs::{Abs, AbsComplexErrors, AbsInputErrors, AbsRealErrors};
pub use complex::{
    Arg, ArgErrors, ArgInputErrors, ComplexScalarConstructors, ComplexScalarGetParts,
    ComplexScalarMutateParts, ComplexScalarSetParts, Conjugate,
};
pub use exponential::{Exp, ExpErrors, ExpInputErrors};
pub use hyperbolic::{
    ACosH, ACosHErrors, ACosHInputErrors, ASinH, ASinHErrors, ASinHInputErrors, ATanH, ATanHErrors,
    ATanHInputErrors, CosH, CosHErrors, CosHInputErrors, HyperbolicFunctions, SinH, SinHErrors,
    SinHInputErrors, TanH, TanHComplexErrors, TanHComplexInputErrors, TanHRealErrors,
    TanHRealInputErrors,
};
pub use logarithm::{
    Ln, Log2, Log10, LogarithmComplexErrors, LogarithmComplexInputErrors, LogarithmFunctions,
    LogarithmRealErrors, LogarithmRealInputErrors,
};
pub use max_min::{Max, Min};
pub use neg_assign::NegAssign;
pub use pow::{
    Pow, PowComplexBaseRealExponentErrors, PowComplexBaseRealExponentInputErrors, PowIntExponent,
    PowIntExponentErrors, PowIntExponentInputErrors, PowRealBaseRealExponentErrors,
    PowRealBaseRealExponentInputErrors,
};
pub use real::{Clamp, Classify, ExpM1, Hypot, Ln1p, TotalCmp};
pub use reciprocal::{Reciprocal, ReciprocalErrors, ReciprocalInputErrors};
pub use sqrt::{
    Sqrt, SqrtComplexErrors, SqrtComplexInputErrors, SqrtRealErrors, SqrtRealInputErrors,
};
pub use trigonometric::{
    ACos, ACosComplexErrors, ACosComplexInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
    ASinComplexErrors, ASinComplexInputErrors, ASinRealErrors, ASinRealInputErrors, ATan, ATan2,
    ATan2Errors, ATan2InputErrors, ATanComplexErrors, ATanComplexInputErrors, ATanRealErrors,
    ATanRealInputErrors, Cos, CosErrors, CosInputErrors, Sin, SinErrors, SinInputErrors, Tan,
    TanComplexErrors, TanComplexInputErrors, TanRealErrors, TanRealInputErrors,
    TrigonometricFunctions,
};

//-------------------------------------------------------------
/// A convenience trait that aggregates the standard arithmetic operations.
///
/// This trait bundles the common arithmetic operator traits from `std::ops`
/// (e.g., [`Add`], [`Sub`], [`Mul`], [`Div`], and their `*Assign` variants)
/// into a single super-trait. It is used as a bound on [`FpScalar`](crate::FpScalar) to ensure
/// all scalar types support basic arithmetic.
///
/// This trait does **not** require `Copy`. Instead, it explicitly requires that
/// arithmetic operations are implemented for both owned values (`Self`) and
/// references (`&Self`). This provides flexibility for both move and copy semantics,
/// allowing implementors to avoid unnecessary clones in performance-sensitive code.
pub trait Arithmetic:
    Sized
    + Add<Self, Output = Self>
    + for<'a> Add<&'a Self, Output = Self>
    + AddAssign
    + for<'a> AddAssign<&'a Self>
    + Sub<Output = Self>
    + for<'a> Sub<&'a Self, Output = Self>
    + SubAssign
    + for<'a> SubAssign<&'a Self>
    + Mul<Output = Self>
    + for<'a> Mul<&'a Self, Output = Self>
    + MulAssign
    + for<'a> MulAssign<&'a Self>
    + Div<Output = Self>
    + for<'a> Div<&'a Self, Output = Self>
    + DivAssign
    + for<'a> DivAssign<&'a Self>
    + Neg<Output = Self>
    + NegAssign
    + LowerExp
{
}
//------------------------------------------------------------------------------------------------------------

/// A generic error type for fallible numerical function computations.
///
/// This enum is used as a standard wrapper for function-specific errors,
/// distinguishing between failures that occur during input validation and those
/// that occur during output validation (or due to the computation itself resulting
/// in an invalid value according to the defined policy).
///
/// # Type Parameters
///
/// - `InputError`: The type of the error that occurs if input validation fails.
///   This is typically a function-specific enum detailing various input-related
///   problems (e.g., [`ExpInputErrors`],, [`LogarithmRealInputErrors`], etc.).
/// - `OutputError`: The type of the error that occurs if output validation fails.
///   This is usually an error type related to the properties of the scalar value itself,
///   often from the [`validation`](crate::validation) module (e.g.,
///   [`ErrorsValidationRawReal`](crate::validation::ErrorsValidationRawReal) or
///   [`ErrorsValidationRawComplex`](crate::validation::ErrorsValidationRawComplex)), indicating
///   that the computed result is not valid (e.g., NaN, Infinity).
#[derive(Debug, Error)]
pub enum FunctionErrors<InputError: std::error::Error, OutputError: std::error::Error> {
    /// Error due to invalid input values.
    ///
    /// This variant is returned when initial validation of the function's arguments
    /// fails according to the defined validation policy (e.g.,
    /// [`StrictFinitePolicy`](crate::validation::StrictFinitePolicy)) or due to
    /// domain-specific constraints (e.g., negative input to a real logarithm).
    #[error("the input value is not valid accordingly to the used validation policy!")]
    Input {
        /// The source error that occurred during input validation.
        /// This provides specific details about why the input was considered invalid.
        #[from] // Allows easy conversion from InputError to FunctionErrors::Input
        source: InputError,
    },

    /// Error due to the computed output failing validation.
    ///
    /// This variant is returned if the result of the computation, even from
    /// valid inputs, fails validation according to the defined policy. This
    /// typically means the result was non-finite (NaN or Infinity) or otherwise
    /// did not meet the criteria for a valid output.
    #[error("the output value is not valid accordingly to the used validation policy!")]
    Output {
        /// The source error that occurred during output validation.
        /// This provides specific details about why the computed output was
        /// considered invalid.
        #[source] // Indicates that `source` is the underlying cause of this error
        #[backtrace] // Captures a backtrace when this error variant is created
        source: OutputError,
    },
}

//------------------------------------------------------------------------------------------------
/// Trait for fused multiply-add operations.
///
/// This trait provides methods for computing `(self * b) + c` efficiently.
///
/// ## Why a custom `MulAddRef` trait?
///
/// This trait is distinct from [`num_traits::MulAdd`] primarily in its method signatures,
/// which take `b` and `c` by reference (`&Self`). This is a deliberate design choice to:
/// 1.  **Maintain API Consistency:** Aligns with the other operator traits in this library that
///     support by-reference operations.
/// 2.  **Reduce Cloning:** Allows implementors to avoid cloning values in performance-sensitive
///     contexts, which is especially important for non-`Copy` types like [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
///
/// Implementors should aim to use hardware FMA (Fused Multiply-Add) instructions
/// where available and appropriate for the underlying scalar type to improve
/// performance and accuracy.
pub trait MulAddRef {
    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
    ///
    /// `a.mul_add_ref(b, c)` produces a result like `a * &b + &c`.
    fn mul_add_ref(self, b: &Self, c: &Self) -> Self;
}
//------------------------------------------------------------------------------------------------

/// Provides methods for rounding floating-point numbers.
pub trait Rounding {
    /// Returns the smallest integer greater than or equal to `self`.
    fn kernel_ceil(self) -> Self;

    /// Returns the largest integer smaller than or equal to `self`.
    fn kernel_floor(self) -> Self;

    /// Returns the fractional part of `self`.
    fn kernel_fract(self) -> Self;

    /// Rounds `self` to the nearest integer, rounding half-way cases away from zero.
    fn kernel_round(self) -> Self;

    /// Returns the nearest integer to a number. Rounds half-way cases to the number with an even least significant digit.
    ///
    /// This function always returns the precise result.
    ///
    /// # Examples
    /// ```
    /// use num_valid::functions::Rounding;
    ///
    /// let f = 3.3_f64;
    /// let g = -3.3_f64;
    /// let h = 3.5_f64;
    /// let i = 4.5_f64;
    ///
    /// assert_eq!(f.kernel_round_ties_even(), 3.0);
    /// assert_eq!(g.kernel_round_ties_even(), -3.0);
    /// assert_eq!(h.kernel_round_ties_even(), 4.0);
    /// assert_eq!(i.kernel_round_ties_even(), 4.0);
    /// ```
    fn kernel_round_ties_even(self) -> Self;

    /// Returns the integer part of `self`. This means that non-integer numbers are always truncated towards zero.
    ///    
    /// # Examples
    /// ```
    /// use num_valid::{RealScalar, functions::Rounding};
    ///
    /// let f = 3.7_f64;
    /// let g = 3.0_f64;
    /// let h = -3.7_f64;
    ///
    /// assert_eq!(f.kernel_trunc(), 3.0);
    /// assert_eq!(g.kernel_trunc(), 3.0);
    /// assert_eq!(h.kernel_trunc(), -3.0);
    /// ```
    fn kernel_trunc(self) -> Self;
}

/// Provides methods for sign manipulation and checking.
pub trait Sign {
    /// Returns a number with the magnitude of `self` and the sign of `sign`.
    fn kernel_copysign(self, sign: &Self) -> Self;

    /// Computes the signum.
    ///
    /// The returned value is:
    /// - `1.0` if the value is positive, +0.0 or +∞
    /// - `−1.0` if the value is negative, −0.0 or −∞
    /// - `NaN` if the value is NaN
    fn kernel_signum(self) -> Self;

    /// Returns `true` if the value is negative, −0 or NaN with a negative sign.
    fn kernel_is_sign_negative(&self) -> bool;

    /// Returns `true` if the value is positive, +0 or NaN with a positive sign.
    fn kernel_is_sign_positive(&self) -> bool;
}
