num_valid/core/traits/
validation.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! Validation traits and marker traits for scalar types.
4//!
5//! This module provides traits for floating-point classification checks and
6//! marker traits that guarantee certain properties of validated types.
7
8use crate::kernels::{RawComplexTrait, RawRealTrait, RawScalarTrait};
9use duplicate::duplicate_item;
10use num::Complex;
11use try_create::ValidationPolicy;
12
13/// Provides a set of fundamental floating-point classification checks.
14///
15/// This trait defines common methods to determine the characteristics of a numerical value,
16/// such as whether it is finite, infinite, NaN (Not a Number), or normal.
17/// It is implemented for standard floating-point types (`f64`), complex numbers
18/// (`num::Complex<f64>`), and their arbitrary-precision counterparts from the `rug`
19/// library (via `RealRugStrictFinite<P>` and `ComplexRugStrictFinite<P>` which internally use [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html)
20/// and [`rug::Complex`](https://docs.rs/rug/latest/rug/struct.Complex.html)) when the "rug" feature is enabled.
21///
22/// `FpChecks` is often used as a supertrait for more general numerical traits like
23/// [`FpScalar`](crate::FpScalar), ensuring that types representing floating-point
24/// scalars can be queried for these basic properties. This is essential for
25/// validation policies and writing robust numerical algorithms.
26///
27/// Note that this trait focuses on these specific classifications. For more detailed
28/// categorization (like distinguishing subnormals or zero explicitly through this trait),
29/// types may provide other methods (e.g., `classify()` for `f64` and [`rug::Float`](https://docs.rs/rug/latest/rug/struct.Float.html),
30/// or `is_zero()` from [`FpScalar`](crate::FpScalar)).
31pub trait FpChecks {
32    /// Returns [`true`] if `self` is finite (i.e., not infinite and not NaN).
33    ///
34    /// For complex numbers, this typically means both the real and imaginary parts are finite.
35    fn is_finite(&self) -> bool;
36
37    /// Returns [`true`] if `self` is positive infinity or negative infinity.
38    ///
39    /// For complex numbers, this typically means at least one part is infinite,
40    /// and no part is NaN.
41    fn is_infinite(&self) -> bool;
42
43    /// Returns [`true`] if `self` is NaN (Not a Number).
44    ///
45    /// For complex numbers, this typically means at least one part is NaN.
46    fn is_nan(&self) -> bool;
47
48    /// Returns [`true`] if `self` is a *normal* number.
49    ///
50    /// A normal number is a finite, non-zero number that is not subnormal.
51    /// For complex numbers, this typically means both real and imaginary parts are normal
52    /// numbers (and thus individually finite, non-zero, and not subnormal).
53    fn is_normal(&self) -> bool;
54}
55
56#[duplicate_item(
57    T;
58    [f64];
59    [Complex::<f64>];
60)]
61impl FpChecks for T {
62    #[inline(always)]
63    fn is_finite(&self) -> bool {
64        T::is_finite(*self)
65    }
66
67    #[inline(always)]
68    fn is_infinite(&self) -> bool {
69        T::is_infinite(*self)
70    }
71
72    #[inline(always)]
73    fn is_nan(&self) -> bool {
74        T::is_nan(*self)
75    }
76
77    #[inline(always)]
78    fn is_normal(&self) -> bool {
79        T::is_normal(*self)
80    }
81}
82//------------------------------------------------------------------------------------------------
83
84//------------------------------------------------------------------------------------------------
85/// A marker for policies that apply to real types.
86///
87/// This trait refines the generic [`ValidationPolicy`] for types that implement
88/// [`RawRealTrait`]. It adds two key constraints:
89///
90/// 1.  It associates a `const PRECISION` with the policy, essential for backends
91///     like `rug`.
92/// 2.  It enforces that the policy's `Error` type must be the same as the canonical
93///     `ValidationErrors` type defined on the raw scalar itself. This architectural
94///     choice ensures consistent error handling throughout the library.
95pub trait ValidationPolicyReal:
96    ValidationPolicy<
97        Value: RawRealTrait,
98        Error = <<Self as ValidationPolicy>::Value as RawScalarTrait>::ValidationErrors,
99    >
100{
101    /// The precision (in bits) of the validated real type.
102    ///
103    /// For IEEE 754 double-precision (`f64`), this is 53 bits.
104    /// For arbitrary-precision types like `rug::Float`, this can be any positive integer.
105    const PRECISION: u32;
106}
107
108/// A marker for policies that apply to complex types.
109///
110/// This trait refines the generic [`ValidationPolicy`] for types that implement
111/// [`RawComplexTrait`]. It adds two key constraints:
112///
113/// 1.  It associates a `const PRECISION` with the policy, essential for backends
114///     like `rug`.
115/// 2.  It enforces that the policy's `Error` type must be the same as the canonical
116///     `ValidationErrors` type defined on the raw scalar itself. This architectural
117///     choice ensures consistent error handling throughout the library.
118pub trait ValidationPolicyComplex:
119    ValidationPolicy<
120        Value: RawComplexTrait,
121        Error = <<Self as ValidationPolicy>::Value as RawScalarTrait>::ValidationErrors,
122    >
123{
124    /// The precision (in bits) of the validated complex type's components.
125    ///
126    /// For IEEE 754 double-precision (`Complex<f64>`), this is 53 bits.
127    /// For arbitrary-precision types like `rug::Complex`, this can be any positive integer.
128    const PRECISION: u32;
129}
130
131/// A marker trait for validation policies that guarantee finite real values.
132///
133/// This trait serves as a compile-time marker to identify policies that ensure
134/// all validated real values are always finite (never NaN or infinite). It enables
135/// the implementation of full equality ([`Eq`]) and hashing ([`Hash`]) for
136/// validated types, allowing them to be used as keys in hash-based collections
137/// like [`HashMap`](std::collections::HashMap) and [`HashSet`](std::collections::HashSet).
138///
139/// ## Enabled Features
140///
141/// When a validation policy implements this trait, the corresponding validated types
142/// (like [`RealValidated<K>`](crate::RealValidated)) automatically gain:
143///
144/// - **Full Equality ([`Eq`])**: Equality becomes reflexive, symmetric, and transitive
145///   since NaN values (which violate these properties) are excluded.
146/// - **Total Ordering ([`Ord`])**: Enables total ordering for validated types, allowing
147///   use in sorted collections like [`BTreeMap`](std::collections::BTreeMap) and [`BTreeSet`](std::collections::BTreeSet),
148///   and enabling standard library sorting operations.
149/// - **Hashing ([`Hash`])**: Combined with [`Eq`], this allows validated types to be
150///   used as keys in hash-based collections like [`HashMap`](std::collections::HashMap) and [`HashSet`](std::collections::HashSet).
151///
152/// ## Hashing Implementation Details
153///
154/// The [`Hash`] implementation for validated types:
155/// - Delegates to the underlying raw type's [`RawScalarTrait::compute_hash`] method
156/// - Handles IEEE 754 floating-point edge cases correctly (e.g., signed zeros)
157/// - Maintains the contract that `a == b` implies `hash(a) == hash(b)`
158/// - Works with both native `f64`/`Complex<f64>` and arbitrary-precision `rug` types
159///
160/// ## Comparison and Ordering
161///
162/// Validated types with finite value guarantees support multiple comparison mechanisms:
163/// 1. **Partial Ordering ([`PartialOrd`])**: Always available, efficient for comparisons
164/// 2. **Total Ordering ([`Ord`])**: Available when this trait is implemented, enables sorted collections
165/// 3. **Reference-based comparison**: The library's [`Max`](crate::functions::Max)/[`Min`](crate::functions::Min)
166///    traits provide `max_by_ref()`/`min_by_ref()` methods that avoid unnecessary cloning
167///
168/// ## Use Cases
169///
170/// This marker trait enables validated numerical types to be used in contexts that
171/// require [`Eq`], [`Hash`], and [`Ord`]:
172///
173/// ```rust
174/// use num_valid::{RealNative64StrictFinite, functions::Max};
175/// use std::collections::{HashMap, HashSet, BTreeMap, BTreeSet};
176/// use try_create::TryNew;
177///
178/// // Use as HashMap keys (requires Eq + Hash)
179/// let mut scores = HashMap::new();
180/// let player1 = RealNative64StrictFinite::try_new(1.5).unwrap();
181/// scores.insert(player1, 100);
182///
183/// // Use in HashSet (requires Eq + Hash)
184/// let mut unique_values = HashSet::new();
185/// unique_values.insert(RealNative64StrictFinite::try_new(3.14).unwrap());
186///
187/// // Use in BTreeMap (requires Ord)
188/// let mut sorted_scores = BTreeMap::new();
189/// sorted_scores.insert(RealNative64StrictFinite::try_new(1.5).unwrap(), 100);
190///
191/// // Comparison works with both PartialOrd and Ord
192/// let a = RealNative64StrictFinite::try_new(1.0).unwrap();
193/// let b = RealNative64StrictFinite::try_new(2.0).unwrap();
194/// assert!(a < b);  // Uses PartialOrd
195/// assert_eq!(a.clone().max(b.clone()), b);  // Uses Ord::max from std (consumes values)
196/// assert_eq!(a.max_by_ref(&b), &b);  // Uses library's Max trait (avoids cloning)
197/// ```
198///
199/// ## Hash Collision Considerations
200///
201/// The hashing implementation ensures:
202/// - Consistent hashes for mathematically equal values
203/// - Proper handling of floating-point edge cases
204/// - Compatibility with both native and arbitrary-precision backends
205/// - No hash collisions due to NaN values (which are excluded by design)
206///
207/// ## Currently Implemented By
208///
209/// - [`StrictFinitePolicy<T, P>`](crate::core::policies::StrictFinitePolicy): The primary policy that
210///   rejects NaN, infinity, and subnormal values.
211/// - [`DebugValidationPolicy<StrictFinitePolicy<T, P>>`](crate::core::policies::DebugValidationPolicy):
212///   A wrapper that applies strict validation only in debug builds.
213///
214/// ## Safety and Correctness
215///
216/// This trait should only be implemented by validation policies that genuinely
217/// guarantee finite values. Incorrect implementation could lead to hash collisions
218/// or violated equality contracts in the methods that rely on this guarantee.
219///
220/// The trait is designed as a marker trait (no methods) to emphasize that it's
221/// purely a compile-time contract rather than runtime functionality.
222pub trait GuaranteesFiniteRealValues: ValidationPolicyReal {}
223
224/// Marker trait indicating that a validation policy guarantees finite complex values.
225///
226/// This trait serves as a compile-time indicator that a validation policy for
227/// complex numbers ensures all validated values have finite real and imaginary components
228/// (i.e., neither component is NaN or infinity). This guarantee enables the
229/// implementation of [`Eq`] and [`Hash`] for [`ComplexValidated`](crate::core::types::ComplexValidated) types, allowing
230/// them to be used as keys in hash-based collections like [`HashMap`](std::collections::HashMap)
231/// and [`HashSet`](std::collections::HashSet).
232///
233/// ## Purpose
234///
235/// Complex numbers can have NaN or infinite components, making equality comparison
236/// problematic (NaN != NaN). By guaranteeing finiteness at the policy level,
237/// this trait allows:
238/// - Full equality ([`Eq`]) implementation for complex validated types
239/// - Consistent hashing ([`Hash`]) for use in hash-based collections
240/// - Compile-time verification of these properties
241///
242/// ## Design Rationale
243///
244/// This trait works in tandem with [`GuaranteesFiniteRealValues`] for real numbers:
245/// - [`GuaranteesFiniteRealValues`]: For real number policies
246/// - [`GuaranteesFiniteComplexValues`]: For complex number policies
247///
248/// This separation allows different validation strategies for real and complex
249/// components while maintaining type safety.
250///
251/// ## Currently Implemented By
252///
253/// - [`StrictFinitePolicy<T, P>`](crate::core::policies::StrictFinitePolicy): Validates both real and imaginary
254///   components for finiteness and non-subnormal values.
255/// - [`DebugValidationPolicy<StrictFinitePolicy<T, P>>`](crate::core::policies::DebugValidationPolicy):
256///   Applies strict validation only in debug builds.
257///
258/// ## Safety and Correctness
259///
260/// This trait should only be implemented by validation policies that genuinely
261/// guarantee finite values in both components. Incorrect implementation could lead
262/// to hash collisions or violated equality contracts.
263pub trait GuaranteesFiniteComplexValues: ValidationPolicyComplex {}