Skip to main content

num_valid/core/
errors.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! Error types for validation and conversion failures.
4//!
5//! This module provides the error types used throughout the library for reporting
6//! validation failures, conversion errors, and function domain violations.
7
8use crate::kernels::RawRealTrait;
9use num::Integer;
10use std::{backtrace::Backtrace, fmt::Display};
11use thiserror::Error;
12
13//--------------------------------------------
14// Errors for raw real number validation
15//--------------------------------------------
16/// Errors that can occur during the validation of a raw real number.
17///
18/// This enum is generic over `RawReal`, which is typically `f64` or [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html).
19/// It covers common validation failures like non-finite values, subnormality, infinity, and precision mismatch.
20#[derive(Debug, Error)]
21pub enum ErrorsValidationRawReal<RawReal: std::fmt::Debug + Display + Clone> {
22    /// The value is subnormal.
23    #[error("Value is subnormal: {value}")]
24    IsSubnormal {
25        /// The subnormal value that failed validation.
26        value: RawReal,
27
28        /// A captured backtrace for debugging purposes.
29        backtrace: Backtrace,
30    },
31
32    /// The value is NaN (Not a Number).
33    #[error("Value is NaN: {value}")]
34    IsNaN {
35        /// The NaN value that failed validation.
36        value: RawReal,
37
38        /// A captured backtrace for debugging purposes.
39        backtrace: Backtrace,
40    },
41
42    /// The value is positive infinity.
43    #[error("Value is positive infinity")]
44    IsPosInfinity {
45        /// The positive infinity value that failed validation.
46        backtrace: Backtrace,
47    },
48
49    /// The value is negative infinity.
50    #[error("Value is negative infinity")]
51    IsNegInfinity {
52        /// The negative infinity value that failed validation.
53        backtrace: Backtrace,
54    },
55
56    /// The precision of the input does not match the requested precision.
57    #[error(
58        "precision mismatch: input real has precision {actual_precision}, \
59        but the requested precision is {requested_precision}"
60    )]
61    PrecisionMismatch {
62        /// The input value.
63        input_value: RawReal,
64
65        /// The precision of the input value.
66        actual_precision: u32,
67
68        /// The requested precision.
69        requested_precision: u32,
70
71        /// A captured backtrace for debugging purposes.
72        backtrace: Backtrace,
73    },
74}
75
76//--------------------------------------------
77// Errors for complex number validation
78//--------------------------------------------
79/// Errors that can occur during the validation of a complex number.
80///
81/// This enum is generic over `ErrorValidationReal`, which is the error type returned
82/// by validating the real and imaginary parts of the complex number (e.g.,
83/// [`ErrorsValidationRawReal<f64>`](ErrorsValidationRawReal)).
84///
85/// It indicates whether the real part, the imaginary part, or both parts failed validation.
86#[derive(Debug, Error)]
87pub enum ErrorsValidationRawComplex<ErrorValidationReal: std::error::Error> {
88    /// The real part of the complex number failed validation.
89    #[error("Real part validation error: {source}")]
90    InvalidRealPart {
91        /// The underlying validation error for the real part.
92        #[source]
93        #[backtrace]
94        source: Box<ErrorValidationReal>,
95    },
96
97    /// The imaginary part of the complex number failed validation.
98    #[error("Imaginary part validation error: {source}")]
99    InvalidImaginaryPart {
100        /// The underlying validation error for the imaginary part.
101        #[source]
102        #[backtrace]
103        source: Box<ErrorValidationReal>,
104    },
105
106    /// Both the real and imaginary parts of the complex number failed validation.
107    #[error("Both real and imaginary parts are invalid: real={real_error}, imag={imag_error}")]
108    InvalidBothParts {
109        /// The validation error for the real part.
110        real_error: Box<ErrorValidationReal>,
111
112        /// The validation error for the imaginary part.
113        imag_error: Box<ErrorValidationReal>,
114    },
115}
116
117//-------------------------------------------------------------
118#[derive(Debug, Error)]
119pub enum RawRealConversionError<RawRealIn: RawRealTrait, RawRealOut: RawRealTrait> {
120    #[error(
121        "the input value ({value_in:?}) cannot be exactly represented with the requested precision (precision_out: {precision_out:?}, value_out: {value_out:?}). "
122    )]
123    NonRepresentableExactly {
124        /// The `RawRealIn` value that could not be exactly represented.
125        value_in: RawRealIn,
126
127        /// The input `value_in` after the conversion to the type `RawRealOut` with the requested `precision`.
128        value_out: RawRealOut,
129
130        /// The precision of `value_out`.
131        precision_out: u32,
132
133        /// A captured backtrace for debugging purposes.
134        backtrace: Backtrace,
135    },
136
137    /// The input value failed validation.
138    #[error("the input value is invalid!")]
139    InputValidation {
140        /// The underlying validation error for the `input` value.
141        #[source]
142        source: ErrorsValidationRawReal<RawRealIn>,
143    },
144
145    /// The output value failed validation.
146    #[error("the output value is invalid!")]
147    OutputValidation {
148        /// The underlying validation error for the `output` value.
149        #[source]
150        source: ErrorsValidationRawReal<RawRealOut>,
151    },
152
153    #[error(
154        "the output value has a precision ({precision_out:?}) that is not valid for the target type. The valid precision is {valid_precision_out:?}."
155    )]
156    InvalidOutputPrecision {
157        /// The `RawRealIn` value.
158        value_in: RawRealIn,
159
160        valid_precision_out: u32,
161
162        /// The precision of `value_out`.
163        precision_out: u32,
164
165        /// A captured backtrace for debugging purposes.
166        backtrace: Backtrace,
167    },
168}
169//-------------------------------------------------------------
170
171//-------------------------------------------------------------
172/// Errors that can occur when converting a raw real number to an integer type.
173///
174/// This enum represents the possible failures when attempting to convert a
175/// floating-point number to an integer, including non-finite values, non-integer
176/// values (with fractional parts), and values outside the representable range
177/// of the target integer type.
178///
179/// # Type Parameters
180///
181/// - `RawReal`: The source floating-point type implementing [`RawRealTrait`].
182/// - `IntType`: The target integer type implementing [`Integer`].
183#[derive(Debug, Error)]
184pub enum ErrorsRawRealToInteger<RawReal: RawRealTrait, IntType: Integer> {
185    /// The `RawReal` value is not finite (i.e., it is NaN or Infinity).
186    #[error("Value is not finite: {value}")]
187    NotFinite {
188        /// The non-finite `RawReal` value that caused the error.
189        value: RawReal,
190
191        /// A captured backtrace for debugging purposes.
192        backtrace: Backtrace,
193    },
194
195    /// The `RawReal` value is not an integer (i.e., it has a fractional part).
196    #[error("Value is not an integer: {value}")]
197    NotAnInteger {
198        /// The `RawReal` value that is not an integer.
199        value: RawReal,
200
201        /// A captured backtrace for debugging purposes.
202        backtrace: Backtrace,
203    },
204
205    /// The `RawReal` value is outside the range representable by the target integer type `IntType`.
206    #[error("Value {value} is out of range [{min}, {max}] for target integer type")]
207    OutOfRange {
208        /// The `RawReal` value that is out of range.
209        value: RawReal,
210
211        /// The minimum representable value of the target integer type `IntType`.
212        min: IntType,
213
214        /// The maximum representable value of the target integer type `IntType`.
215        max: IntType,
216
217        /// A captured backtrace for debugging purposes.
218        backtrace: Backtrace,
219    },
220}
221//-------------------------------------------------------------
222
223//--------------------------------------------------------------------------------------------------
224// Conditional Backtrace Support
225//--------------------------------------------------------------------------------------------------
226
227/// Captures a backtrace if the `backtrace` feature is enabled.
228///
229/// When the `backtrace` feature is enabled, this function captures a full backtrace
230/// using [`capture_backtrace()`]. When disabled (default), it returns a
231/// disabled backtrace with zero overhead.
232///
233/// # Performance
234///
235/// Backtrace capture is expensive (~1-10μs per capture). For performance-critical
236/// code, leave the `backtrace` feature disabled. Enable it during development or
237/// debugging to get detailed error traces.
238///
239/// # Example
240///
241/// ```toml
242/// # In Cargo.toml, enable backtraces for debugging:
243/// [dependencies]
244/// num-valid = { version = "0.2", features = ["backtrace"] }
245/// ```
246#[inline(always)]
247pub fn capture_backtrace() -> Backtrace {
248    #[cfg(feature = "backtrace")]
249    {
250        Backtrace::force_capture()
251    }
252    #[cfg(not(feature = "backtrace"))]
253    {
254        Backtrace::disabled()
255    }
256}
257
258/// Returns `true` if the `backtrace` feature is enabled.
259///
260/// This can be used to conditionally check whether backtraces are being captured.
261///
262/// # Example
263///
264/// ```rust
265/// use num_valid::core::errors::is_backtrace_enabled;
266///
267/// if is_backtrace_enabled() {
268///     println!("Backtraces are enabled - errors will include stack traces");
269/// } else {
270///     println!("Backtraces are disabled for performance");
271/// }
272/// ```
273#[inline(always)]
274pub const fn is_backtrace_enabled() -> bool {
275    #[cfg(feature = "backtrace")]
276    {
277        true
278    }
279    #[cfg(not(feature = "backtrace"))]
280    {
281        false
282    }
283}
284
285//--------------------------------------------------------------------------------------------------