num-valid 0.3.3

A robust numerical library providing validated types for real and complex numbers to prevent common floating-point errors like NaN propagation. Features a generic, layered architecture with support for native f64 and optional arbitrary-precision arithmetic.
Documentation
#![deny(rustdoc::broken_intra_doc_links)]

//! Error types for validation and conversion failures.
//!
//! This module provides the error types used throughout the library for reporting
//! validation failures, conversion errors, and function domain violations.

use crate::kernels::RawRealTrait;
use num::Integer;
use std::{backtrace::Backtrace, fmt::Display};
use thiserror::Error;

//--------------------------------------------
// Errors for raw real number validation
//--------------------------------------------
/// Errors that can occur during the validation of a raw real number.
///
/// This enum is generic over `RawReal`, which is typically `f64` or [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
/// It covers common validation failures like non-finite values, subnormality, infinity, and precision mismatch.
#[derive(Debug, Error)]
pub enum ErrorsValidationRawReal<RawReal: std::fmt::Debug + Display + Clone> {
    /// The value is subnormal.
    #[error("Value is subnormal: {value}")]
    IsSubnormal {
        /// The subnormal value that failed validation.
        value: RawReal,

        /// A captured backtrace for debugging purposes.
        backtrace: Backtrace,
    },

    /// The value is NaN (Not a Number).
    #[error("Value is NaN: {value}")]
    IsNaN {
        /// The NaN value that failed validation.
        value: RawReal,

        /// A captured backtrace for debugging purposes.
        backtrace: Backtrace,
    },

    /// The value is positive infinity.
    #[error("Value is positive infinity")]
    IsPosInfinity {
        /// The positive infinity value that failed validation.
        backtrace: Backtrace,
    },

    /// The value is negative infinity.
    #[error("Value is negative infinity")]
    IsNegInfinity {
        /// The negative infinity value that failed validation.
        backtrace: Backtrace,
    },

    /// The precision of the input does not match the requested precision.
    #[error(
        "precision mismatch: input real has precision {actual_precision}, \
        but the requested precision is {requested_precision}"
    )]
    PrecisionMismatch {
        /// The input value.
        input_value: RawReal,

        /// The precision of the input value.
        actual_precision: u32,

        /// The requested precision.
        requested_precision: u32,

        /// A captured backtrace for debugging purposes.
        backtrace: Backtrace,
    },
    /*
    // The following variants are placeholders for potential future validation policies
    // and are not currently used by StrictFinitePolicy.

    #[error("Value is not strictly positive: {value}")]
    NotPositive {
        value: RawReal,
        backtrace: Backtrace,
    },

    #[error("Value is negative: {value}")]
    Negative {
        value: RawReal,
        backtrace: Backtrace,
    },

    #[error("Value is zero: {value}")]
    IsZero {
        value: RawReal,
        backtrace: Backtrace,
    },

    #[error("Value {value} is outside the allowed range [{min}, {max}]")]
    OutOfRange {
        value: RawReal,
        min: RawReal,
        max: RawReal,
        backtrace: Backtrace,
    },
    */
}

//--------------------------------------------
// Errors for complex number validation
//--------------------------------------------
/// Errors that can occur during the validation of a complex number.
///
/// This enum is generic over `ErrorValidationReal`, which is the error type returned
/// by validating the real and imaginary parts of the complex number (e.g.,
/// [`ErrorsValidationRawReal<f64>`](ErrorsValidationRawReal)).
///
/// It indicates whether the real part, the imaginary part, or both parts failed validation.
#[derive(Debug, Error)]
pub enum ErrorsValidationRawComplex<ErrorValidationReal: std::error::Error> {
    /// The real part of the complex number failed validation.
    #[error("Real part validation error: {source}")]
    InvalidRealPart {
        /// The underlying validation error for the real part.
        #[source]
        #[backtrace]
        source: Box<ErrorValidationReal>,
    },

    /// The imaginary part of the complex number failed validation.
    #[error("Imaginary part validation error: {source}")]
    InvalidImaginaryPart {
        /// The underlying validation error for the imaginary part.
        #[source]
        #[backtrace]
        source: Box<ErrorValidationReal>,
    },

    /// Both the real and imaginary parts of the complex number failed validation.
    #[error("Both real and imaginary parts are invalid: real={real_error}, imag={imag_error}")]
    InvalidBothParts {
        /// The validation error for the real part.
        real_error: Box<ErrorValidationReal>,

        /// The validation error for the imaginary part.
        imag_error: Box<ErrorValidationReal>,
    },
}

//-------------------------------------------------------------
/// Errors that can occur when trying to convert an `f64` to another real-type scalar of type `RawReal`.
///
/// This enum distinguishes between:
/// 1.  Failures due to the `f64` not being exactly representable at the target `PRECISION`
///     of the `RawReal` type.
/// 2.  General validation failures of the output `RawReal` (e.g., NaN, Infinity, subnormal).
#[derive(Debug, Error)]
pub enum ErrorsTryFromf64<RawReal: RawRealTrait> {
    /// The input `f64` value is not representable exactly at the target `precision` using the output `RawReal` type.
    #[error(
        "the input f64 value ({value_in:?}) cannot be exactly represented with the specific precision ({precision:?}). Try to increase the precision."
    )]
    NonRepresentableExactly {
        /// The `f64` value that could not be exactly represented.
        value_in: f64,

        /// The input `value_in` after the conversion to the type `RawReal` with the requested `precision`.
        value_converted_from_f64: RawReal,

        /// The precision that was requested.
        precision: u32,

        /// A captured backtrace for debugging purposes.
        backtrace: Backtrace,
    },

    /// The output value failed validation.
    #[error("the output value is invalid!")]
    Output {
        /// The underlying validation error for the `output` value.
        #[from]
        source: ErrorsValidationRawReal<RawReal>,
    },
}
//-------------------------------------------------------------

//-------------------------------------------------------------
/// Errors that can occur when converting a raw real number to an integer type.
///
/// This enum represents the possible failures when attempting to convert a
/// floating-point number to an integer, including non-finite values, non-integer
/// values (with fractional parts), and values outside the representable range
/// of the target integer type.
///
/// # Type Parameters
///
/// - `RawReal`: The source floating-point type implementing [`RawRealTrait`].
/// - `IntType`: The target integer type implementing [`Integer`].
#[derive(Debug, Error)]
pub enum ErrorsRawRealToInteger<RawReal: RawRealTrait, IntType: Integer> {
    /// The `RawReal` value is not finite (i.e., it is NaN or Infinity).
    #[error("Value is not finite: {value}")]
    NotFinite {
        /// The non-finite `RawReal` value that caused the error.
        value: RawReal,

        /// A captured backtrace for debugging purposes.
        backtrace: Backtrace,
    },

    /// The `RawReal` value is not an integer (i.e., it has a fractional part).
    #[error("Value is not an integer: {value}")]
    NotAnInteger {
        /// The `RawReal` value that is not an integer.
        value: RawReal,

        /// A captured backtrace for debugging purposes.
        backtrace: Backtrace,
    },

    /// The `RawReal` value is outside the range representable by the target integer type `IntType`.
    #[error("Value {value} is out of range [{min}, {max}] for target integer type")]
    OutOfRange {
        /// The `RawReal` value that is out of range.
        value: RawReal,

        /// The minimum representable value of the target integer type `IntType`.
        min: IntType,

        /// The maximum representable value of the target integer type `IntType`.
        max: IntType,

        /// A captured backtrace for debugging purposes.
        backtrace: Backtrace,
    },
}
//-------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
// Conditional Backtrace Support
//--------------------------------------------------------------------------------------------------

/// Captures a backtrace if the `backtrace` feature is enabled.
///
/// When the `backtrace` feature is enabled, this function captures a full backtrace
/// using [`capture_backtrace()`]. When disabled (default), it returns a
/// disabled backtrace with zero overhead.
///
/// # Performance
///
/// Backtrace capture is expensive (~1-10μs per capture). For performance-critical
/// code, leave the `backtrace` feature disabled. Enable it during development or
/// debugging to get detailed error traces.
///
/// # Example
///
/// ```toml
/// # In Cargo.toml, enable backtraces for debugging:
/// [dependencies]
/// num-valid = { version = "0.2", features = ["backtrace"] }
/// ```
#[inline(always)]
pub fn capture_backtrace() -> Backtrace {
    #[cfg(feature = "backtrace")]
    {
        Backtrace::force_capture()
    }
    #[cfg(not(feature = "backtrace"))]
    {
        Backtrace::disabled()
    }
}

/// Returns `true` if the `backtrace` feature is enabled.
///
/// This can be used to conditionally check whether backtraces are being captured.
///
/// # Example
///
/// ```rust
/// use num_valid::core::errors::is_backtrace_enabled;
///
/// if is_backtrace_enabled() {
///     println!("Backtraces are enabled - errors will include stack traces");
/// } else {
///     println!("Backtraces are disabled for performance");
/// }
/// ```
#[inline(always)]
pub const fn is_backtrace_enabled() -> bool {
    #[cfg(feature = "backtrace")]
    {
        true
    }
    #[cfg(not(feature = "backtrace"))]
    {
        false
    }
}

//--------------------------------------------------------------------------------------------------