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 // The following variants are placeholders for potential future validation policies
76 // and are not currently used by StrictFinitePolicy.
77
78 #[error("Value is not strictly positive: {value}")]
79 NotPositive {
80 value: RawReal,
81 backtrace: Backtrace,
82 },
83
84 #[error("Value is negative: {value}")]
85 Negative {
86 value: RawReal,
87 backtrace: Backtrace,
88 },
89
90 #[error("Value is zero: {value}")]
91 IsZero {
92 value: RawReal,
93 backtrace: Backtrace,
94 },
95
96 #[error("Value {value} is outside the allowed range [{min}, {max}]")]
97 OutOfRange {
98 value: RawReal,
99 min: RawReal,
100 max: RawReal,
101 backtrace: Backtrace,
102 },
103 */
104}
105
106//--------------------------------------------
107// Errors for complex number validation
108//--------------------------------------------
109/// Errors that can occur during the validation of a complex number.
110///
111/// This enum is generic over `ErrorValidationReal`, which is the error type returned
112/// by validating the real and imaginary parts of the complex number (e.g.,
113/// [`ErrorsValidationRawReal<f64>`](ErrorsValidationRawReal)).
114///
115/// It indicates whether the real part, the imaginary part, or both parts failed validation.
116#[derive(Debug, Error)]
117pub enum ErrorsValidationRawComplex<ErrorValidationReal: std::error::Error> {
118 /// The real part of the complex number failed validation.
119 #[error("Real part validation error: {source}")]
120 InvalidRealPart {
121 /// The underlying validation error for the real part.
122 #[source]
123 #[backtrace]
124 source: ErrorValidationReal,
125 },
126
127 /// The imaginary part of the complex number failed validation.
128 #[error("Imaginary part validation error: {source}")]
129 InvalidImaginaryPart {
130 /// The underlying validation error for the imaginary part.
131 #[source]
132 #[backtrace]
133 source: ErrorValidationReal,
134 },
135
136 /// Both the real and imaginary parts of the complex number failed validation.
137 #[error("Both real and imaginary parts are invalid: real={real_error}, imag={imag_error}")]
138 InvalidBothParts {
139 /// The validation error for the real part.
140 real_error: ErrorValidationReal,
141
142 /// The validation error for the imaginary part.
143 imag_error: ErrorValidationReal,
144 },
145}
146
147//-------------------------------------------------------------
148/// Errors that can occur when trying to convert an `f64` to another real-type scalar of type `RawReal`.
149///
150/// This enum distinguishes between:
151/// 1. Failures due to the `f64` not being exactly representable at the target `PRECISION`
152/// of the `RawReal` type.
153/// 2. General validation failures of the output `RawReal` (e.g., NaN, Infinity, subnormal).
154#[derive(Debug, Error)]
155pub enum ErrorsTryFromf64<RawReal: RawRealTrait> {
156 /// The input `f64` value is not representable exactly at the target `precision` using the output `RawReal` type.
157 #[error(
158 "the input f64 value ({value_in:?}) cannot be exactly represented with the specific precision ({precision:?}). Try to increase the precision."
159 )]
160 NonRepresentableExactly {
161 /// The `f64` value that could not be exactly represented.
162 value_in: f64,
163
164 /// The input `value_in` after the conversion to the type `RawReal` with the requested `precision`.
165 value_converted_from_f64: RawReal,
166
167 /// The precision that was requested.
168 precision: u32,
169
170 /// A captured backtrace for debugging purposes.
171 backtrace: Backtrace,
172 },
173
174 /// The output value failed validation.
175 #[error("the output value is invalid!")]
176 Output {
177 /// The underlying validation error for the `output` value.
178 #[from]
179 source: ErrorsValidationRawReal<RawReal>,
180 },
181}
182//-------------------------------------------------------------
183
184//-------------------------------------------------------------
185/// Errors that can occur when converting a raw real number to an integer type.
186///
187/// This enum represents the possible failures when attempting to convert a
188/// floating-point number to an integer, including non-finite values, non-integer
189/// values (with fractional parts), and values outside the representable range
190/// of the target integer type.
191///
192/// # Type Parameters
193///
194/// - `RawReal`: The source floating-point type implementing [`RawRealTrait`].
195/// - `IntType`: The target integer type implementing [`Integer`].
196#[derive(Debug, Error)]
197pub enum ErrorsRawRealToInteger<RawReal: RawRealTrait, IntType: Integer> {
198 /// The `RawReal` value is not finite (i.e., it is NaN or Infinity).
199 #[error("Value is not finite: {value}")]
200 NotFinite {
201 /// The non-finite `RawReal` value that caused the error.
202 value: RawReal,
203
204 /// A captured backtrace for debugging purposes.
205 backtrace: Backtrace,
206 },
207
208 /// The `RawReal` value is not an integer (i.e., it has a fractional part).
209 #[error("Value is not an integer: {value}")]
210 NotAnInteger {
211 /// The `RawReal` value that is not an integer.
212 value: RawReal,
213
214 /// A captured backtrace for debugging purposes.
215 backtrace: Backtrace,
216 },
217
218 /// The `RawReal` value is outside the range representable by the target integer type `IntType`.
219 #[error("Value {value} is out of range [{min}, {max}] for target integer type")]
220 OutOfRange {
221 /// The `RawReal` value that is out of range.
222 value: RawReal,
223
224 /// The minimum representable value of the target integer type `IntType`.
225 min: IntType,
226
227 /// The maximum representable value of the target integer type `IntType`.
228 max: IntType,
229
230 /// A captured backtrace for debugging purposes.
231 backtrace: Backtrace,
232 },
233}
234//-------------------------------------------------------------
235
236//--------------------------------------------------------------------------------------------------
237// Conditional Backtrace Support
238//--------------------------------------------------------------------------------------------------
239
240/// Captures a backtrace if the `backtrace` feature is enabled.
241///
242/// When the `backtrace` feature is enabled, this function captures a full backtrace
243/// using [`capture_backtrace()`]. When disabled (default), it returns a
244/// disabled backtrace with zero overhead.
245///
246/// # Performance
247///
248/// Backtrace capture is expensive (~1-10μs per capture). For performance-critical
249/// code, leave the `backtrace` feature disabled. Enable it during development or
250/// debugging to get detailed error traces.
251///
252/// # Example
253///
254/// ```toml
255/// # In Cargo.toml, enable backtraces for debugging:
256/// [dependencies]
257/// num-valid = { version = "0.2", features = ["backtrace"] }
258/// ```
259#[inline(always)]
260pub fn capture_backtrace() -> Backtrace {
261 #[cfg(feature = "backtrace")]
262 {
263 Backtrace::force_capture()
264 }
265 #[cfg(not(feature = "backtrace"))]
266 {
267 Backtrace::disabled()
268 }
269}
270
271/// Returns `true` if the `backtrace` feature is enabled.
272///
273/// This can be used to conditionally check whether backtraces are being captured.
274///
275/// # Example
276///
277/// ```rust
278/// use num_valid::core::errors::is_backtrace_enabled;
279///
280/// if is_backtrace_enabled() {
281/// println!("Backtraces are enabled - errors will include stack traces");
282/// } else {
283/// println!("Backtraces are disabled for performance");
284/// }
285/// ```
286#[inline(always)]
287pub const fn is_backtrace_enabled() -> bool {
288 #[cfg(feature = "backtrace")]
289 {
290 true
291 }
292 #[cfg(not(feature = "backtrace"))]
293 {
294 false
295 }
296}
297
298//--------------------------------------------------------------------------------------------------