Skip to main content

range_set_blaze/float/
not_nan.rs

1//! `NotNan` is a floating point type, suitable for use in ranges. Every value except NaN is
2//! valid, including `+infinity` and `-infinity`.
3//!
4//! Ordering and other semantics are as per normal floating point comparisons.
5//!
6//! The `NotNanF32`/`NotNanF64` wrappers are available by default. Enable
7//! `float_nightly_experimental` on nightly to add `NotNanF16`/`NotNanF128`.
8
9use core::{
10    cmp::Ordering,
11    fmt::Debug,
12    hash::{Hash, Hasher},
13    mem,
14    ops::RangeInclusive,
15    slice::from_raw_parts,
16};
17
18use super::not_nan_float::NotNanFloat;
19
20use crate::Integer;
21#[cfg(feature = "from_slice")]
22use crate::RangeSetBlaze;
23use num_traits::Zero;
24
25/// Total ordered f64, with `-0.0` normalized to `+0.0`, and excluding NaN.
26pub type NotNanF64 = NotNan<f64>;
27/// Total ordered f32, with `-0.0` normalized to `+0.0`, and excluding NaN.
28pub type NotNanF32 = NotNan<f32>;
29/// Total ordered f16, with `-0.0` normalized to `+0.0`, and excluding NaN.
30#[cfg(feature = "float_nightly_experimental")]
31pub type NotNanF16 = NotNan<f16>;
32/// Total ordered f128, with `-0.0` normalized to `+0.0`, and excluding NaN.
33#[cfg(feature = "float_nightly_experimental")]
34pub type NotNanF128 = NotNan<f128>;
35
36/// Construct a [`NotNanF64`] from an `f64`. Shorthand for [`NotNanF64::new`]
37#[must_use]
38pub const fn nnf64(x: f64) -> NotNanF64 {
39    not_nan_f64(x)
40}
41
42/// Construct a [`NotNanF32`] from an `f32`. Shorthand for [`NotNanF32::new`]
43#[must_use]
44pub const fn nnf32(x: f32) -> NotNanF32 {
45    not_nan_f32(x)
46}
47
48/// Construct a [`NotNanF16`] from an `f16`. Shorthand for [`NotNanF16::new`]
49#[cfg(feature = "float_nightly_experimental")]
50#[must_use]
51pub const fn nnf16(x: f16) -> NotNanF16 {
52    not_nan_f16(x)
53}
54
55/// Construct a [`NotNanF128`] from an `f128`. Shorthand for [`NotNanF128::new`]
56#[cfg(feature = "float_nightly_experimental")]
57#[must_use]
58pub const fn nnf128(x: f128) -> NotNanF128 {
59    not_nan_f128(x)
60}
61
62// TODO When const trait methods are stable, make the generic NotNan constructors and other
63// eligible methods const, then have these shorthands call NotNan::new directly. That will also
64// let their negative-zero normalization share `NotNanFloat::normalize` with runtime paths.
65macro_rules! not_nan_const_constructor {
66    ($name:ident, $primitive:ty, $not_nan:ty) => {
67        const fn $name(x: $primitive) -> $not_nan {
68            assert!(!x.is_nan(), "NotNan type requires a non-NaN value");
69            let normalized = if x == 0.0 && x.is_sign_negative() {
70                0.0
71            } else {
72                x
73            };
74            NotNan(normalized)
75        }
76    };
77}
78
79not_nan_const_constructor!(not_nan_f64, f64, NotNanF64);
80not_nan_const_constructor!(not_nan_f32, f32, NotNanF32);
81#[cfg(feature = "float_nightly_experimental")]
82not_nan_const_constructor!(not_nan_f16, f16, NotNanF16);
83#[cfg(feature = "float_nightly_experimental")]
84not_nan_const_constructor!(not_nan_f128, f128, NotNanF128);
85
86/// A transparent wrapper around [`f64`] and friends with total ordering.
87///
88/// Comparison, equality, and hashing all agree with `total_cmp` after zero normalization.
89/// Every value except NaN is legal, including `+infinity` and `-infinity`.
90///
91/// # Basic Usage
92/// ```
93/// use range_set_blaze::{RangeSetBlaze, NotNanF64, NotNanF32};
94/// let set = RangeSetBlaze::from_iter([NotNanF64::new(3.0)..=NotNanF64::new(5.0)]);
95/// assert!(set.contains(NotNanF64::new(3.1)));
96/// assert!(!set.contains(NotNanF64::new(2.9)));
97///
98/// let set = RangeSetBlaze::from(NotNanF64::from_primitive_range(3.0..=5.0));
99/// assert!(set.contains(NotNanF64::new(4.9)));
100/// assert!(!set.contains(NotNanF64::new(5.1)));
101///
102/// let set = RangeSetBlaze::from_iter(NotNanF32::from_primitive_ranges([3.0..=5.0, 7.0..=9.0]));
103/// assert!(set.contains(NotNanF32::new(4.0)));
104/// assert!(!set.contains(NotNanF32::new(6.0)));
105/// ```
106///
107/// # The Full Non-NaN Domain
108///
109/// The primitive `-∞..=+∞` range converts to `NotNanF64::MIN..=NotNanF64::MAX`,
110/// the complete ordered domain of legal values: every non-NaN `f64`, including
111/// both infinities, is in the range.
112///
113/// ```
114/// use range_set_blaze::{NotNanF64, RangeSetBlaze};
115///
116/// assert_eq!(NotNanF64::MIN, NotNanF64::new(f64::NEG_INFINITY));
117/// assert_eq!(NotNanF64::MAX, NotNanF64::new(f64::INFINITY));
118///
119/// let primitive_domain =
120///     NotNanF64::from_primitive_range(f64::NEG_INFINITY..=f64::INFINITY);
121/// let full_domain = NotNanF64::MIN..=NotNanF64::MAX;
122/// assert_eq!(primitive_domain, full_domain);
123///
124/// let full_domain = RangeSetBlaze::from(full_domain);
125/// assert!(full_domain.contains(NotNanF64::new(f64::NEG_INFINITY)));
126/// assert!(full_domain.contains(NotNanF64::new(-42.0)));
127/// assert!(full_domain.contains(NotNanF64::new(0.0)));
128/// assert!(full_domain.contains(NotNanF64::new(42.0)));
129/// assert!(full_domain.contains(NotNanF64::new(f64::INFINITY)));
130/// ```
131///
132/// The stable `NotNanF32` and `NotNanF64` types are available by default.
133/// On nightly, enable `float_nightly_experimental` to also use the
134/// `NotNanF16` and `NotNanF128` types.
135#[repr(transparent)]
136#[derive(Copy, Clone, Default, Debug)]
137pub struct NotNan<T: NotNanFloat>(T);
138
139impl<T: NotNanFloat> NotNan<T> {
140    /// The minimum value that can be represented by the type: negative infinity.\
141    /// Maps directly to `crate::Integer::min_value()`
142    ///
143    /// # Examples
144    /// ```
145    /// use range_set_blaze::NotNanF64;
146    ///
147    /// assert_eq!(NotNanF64::MIN, NotNanF64::new(f64::NEG_INFINITY));
148    /// ```
149    pub const MIN: Self = Self(T::MIN);
150
151    /// The maximum value that can be represented by the type: positive infinity.\
152    /// Maps directly to [`crate::Integer::max_value()`]
153    ///
154    /// # Examples
155    /// ```
156    /// use range_set_blaze::NotNanF64;
157    ///
158    /// assert_eq!(NotNanF64::MAX, NotNanF64::new(f64::INFINITY));
159    /// ```
160    pub const MAX: Self = Self(T::MAX);
161
162    /// The maximum possible size of a range, i.e. the size if `[MIN..=MAX]`
163    /// For `NotNan` types, this is unusual because NaN values are excluded, and
164    /// `-0.0` and `+0.0` share one slot after normalization.
165    ///
166    /// # Examples
167    /// ```
168    /// use range_set_blaze::NotNanF32;
169    ///
170    /// assert_eq!(NotNanF32::MAX_SIZE, 0xFF00_0000_u32 + 1);
171    /// ```
172    pub const MAX_SIZE: T::SafeLen = T::MAX_SIZE;
173
174    /// Creates a new [`NotNan`] from a primitive float.
175    /// Any value except NaN is legal, including the infinities.
176    ///
177    /// # Examples
178    /// ```
179    /// use range_set_blaze::NotNanF64;
180    ///
181    /// let _ = NotNanF64::new(1.0);
182    /// let _ = NotNanF64::new(f64::INFINITY);
183    /// ```
184    /// # Panics
185    ///
186    /// Panics if `x` is NaN.
187    #[must_use]
188    pub fn new(x: T) -> Self {
189        Self::try_new(x).expect("NotNan type requires a non-NaN value")
190    }
191
192    /// Creates a new [`NotNan`] from a primitive float.
193    ///
194    /// Returns `None` if the float is NaN.
195    ///
196    /// # Examples
197    /// ```
198    /// use range_set_blaze::NotNanF64;
199    ///
200    /// assert_eq!(NotNanF64::try_new(1.0), Some(NotNanF64::new(1.0)));
201    /// assert_eq!(NotNanF64::try_new(f64::INFINITY), Some(NotNanF64::new(f64::INFINITY)));
202    /// assert_eq!(NotNanF64::try_new(f64::NAN), None);
203    /// ```
204    #[must_use]
205    pub fn try_new(x: T) -> Option<Self> {
206        // SAFETY: `!T::is_nan` rules out NaN, and `T::normalize` canonicalizes -0.0.
207        (!T::is_nan(x)).then(|| unsafe { Self::new_unchecked(T::normalize(x)) })
208    }
209
210    /// Creates a new [`NotNan`] from a primitive float without validating it.
211    ///
212    /// This is the unchecked building block every validating constructor in this module
213    /// (`new`, `try_new`, `from_primitive_range`, `values`,
214    /// `from_primitive_slice`, ...) is defined in terms
215    /// of. Prefer those; only reach for this when you have already independently established
216    /// the safety precondition below and need to skip the redundant check.
217    ///
218    /// # Safety
219    ///
220    /// The caller must guarantee that:
221    /// - `x` is not NaN.
222    /// - `x` is not `-0.0`: zero must already be canonicalized to `+0.0`.
223    ///
224    /// [`NotNan`] has a public type invariant ("only non-NaN values, with zero canonicalized to
225    /// `+0.0`, are legal"). Even though today's implementation would only produce incorrect
226    /// results (wrong `MAX_SIZE`, a duplicated zero slot, `after`/`before` landing somewhere
227    /// unexpected) rather than immediate undefined behavior if this precondition is violated,
228    /// safe code must never be able to construct a value that breaks it. This preserves the
229    /// option for this crate, and downstream code, to rely on the invariant in future
230    /// (potentially unsafe) abstractions without an audit of every safe caller.
231    #[must_use]
232    pub const unsafe fn new_unchecked(x: T) -> Self {
233        Self(x)
234    }
235
236    /// Computes `self + (b - 1)` where `b` is of type `SafeLen`.
237    ///
238    /// # Panics
239    /// Panics if `b` is not small enough that the result stays within range for `T`
240    /// (checked unconditionally, in both debug and release builds, so safe code can
241    /// never construct a `NotNan` value that breaks its invariant this way).
242    #[must_use]
243    pub fn inclusive_end_from_start(self, b: T::SafeLen) -> Self {
244        let max_len = T::prim_safe_len(self.0, T::MAX);
245        assert!(
246            !b.is_zero() && b <= max_len,
247            "b must be in range 1..=max_len"
248        );
249        Self(T::inclusive_end_from_start(self.0, b))
250    }
251
252    /// Computes `self - (b - 1)` where `b` is of type `SafeLen`.
253    ///
254    /// # Panics
255    /// Panics if `b` is not small enough that the result stays within range for `T`
256    /// (checked unconditionally, in both debug and release builds, so safe code can
257    /// never construct a `NotNan` value that breaks its invariant this way).
258    #[must_use]
259    pub fn start_from_inclusive_end(self, b: T::SafeLen) -> Self {
260        let max_len = T::prim_safe_len(T::MIN, self.0);
261        assert!(
262            !b.is_zero() && b <= max_len,
263            "b must be in range 1..=max_len"
264        );
265        Self(T::start_from_inclusive_end(self.0, b))
266    }
267
268    /// Returns the wrapped value.
269    ///
270    /// # Examples
271    /// ```
272    /// use range_set_blaze::NotNanF64;
273    ///
274    /// assert_eq!(NotNanF64::new(42.0).into_inner(), 42.0);
275    /// ```
276    #[must_use]
277    pub const fn into_inner(self) -> T {
278        self.0
279    }
280
281    /// Returns the next float, in total order.
282    ///
283    /// # Examples
284    /// ```
285    /// use range_set_blaze::NotNanF64;
286    ///
287    /// assert_eq!(NotNanF64::new(42.0).after().before().into_inner(), 42.0);
288    /// ```
289    ///
290    /// # Panics
291    ///
292    /// Panics if `self` is the maximum value (checked unconditionally, in both debug
293    /// and release builds, so safe code can never construct a `NotNan` value that
294    /// breaks its invariant this way).
295    #[must_use]
296    pub fn after(self) -> Self {
297        assert!(self != Self::MAX, "after() called on maximum value");
298        Self(T::normalize(T::after(self.0)))
299    }
300
301    /// Returns the previous float, in total order.
302    ///
303    /// # Examples
304    /// ```
305    /// use range_set_blaze::NotNanF64;
306    ///
307    /// assert_eq!(NotNanF64::new(42.0).before().after().into_inner(), 42.0);
308    /// ```
309    ///
310    /// # Panics
311    ///
312    /// Panics if `self` is the minimum value (checked unconditionally, in both debug
313    /// and release builds, so safe code can never construct a `NotNan` value that
314    /// breaks its invariant this way).
315    #[must_use]
316    pub fn before(self) -> Self {
317        assert!(self != Self::MIN, "before() called on minimum value");
318        Self(T::normalize(T::before(self.0)))
319    }
320
321    /// Returns the next float, in total order.
322    ///
323    /// Returns [`None`] if `self` is the maximum value.
324    ///
325    /// # Examples
326    /// ```
327    /// use range_set_blaze::NotNanF64;
328    ///
329    /// let value = NotNanF64::new(42.0);
330    /// assert_eq!(value.checked_after(), Some(value.after()));
331    /// let value = NotNanF64::MAX;
332    /// assert_eq!(value.checked_after(), None);
333    /// ```
334    #[must_use]
335    pub fn checked_after(self) -> Option<Self> {
336        if self == Self::MAX {
337            None
338        } else {
339            Some(self.after())
340        }
341    }
342
343    /// Returns the previous float, in total order.
344    ///
345    /// Returns [`None`] if `self` is the minimum value.
346    ///
347    /// # Examples
348    /// ```
349    /// use range_set_blaze::NotNanF64;
350    ///
351    /// let value = NotNanF64::new(42.0);
352    /// assert_eq!(value.checked_before(), Some(value.before()));
353    /// let value = NotNanF64::MIN;
354    /// assert_eq!(value.checked_before(), None);
355    /// ```
356    #[must_use]
357    pub fn checked_before(self) -> Option<Self> {
358        if self == Self::MIN {
359            None
360        } else {
361            Some(self.before())
362        }
363    }
364
365    /// Converts an inclusive primitive range into an inclusive [`NotNan`] range.
366    ///
367    /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
368    ///
369    ///
370    /// # Examples
371    /// ```
372    /// use range_set_blaze::{RangeSetBlaze, NotNanF64};
373    ///
374    /// let short = RangeSetBlaze::from(NotNanF64::from_primitive_range(3.0..=5.0));
375    /// let long = RangeSetBlaze::from(NotNanF64::new(3.0)..=NotNanF64::new(5.0));
376    /// assert_eq!(short, long);
377    /// ```
378    /// # Panics
379    ///
380    /// Panics if `start` or `end` is NaN.
381    #[must_use]
382    pub fn from_primitive_range(range: RangeInclusive<T>) -> RangeInclusive<Self> {
383        let (start, end) = range.into_inner();
384        Self::new(start)..=Self::new(end)
385    }
386
387    /// Converts inclusive primitive ranges into inclusive [`NotNan`] ranges.
388    ///
389    /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
390    ///
391    ///
392    /// # Examples
393    /// ```
394    /// use range_set_blaze::{RangeSetBlaze, NotNanF64};
395    ///
396    /// let short = RangeSetBlaze::from_iter(NotNanF64::from_primitive_ranges([1.0..=2.0, 3.0..=4.0]));
397    /// let long = RangeSetBlaze::from_iter([NotNanF64::new(1.0)..=NotNanF64::new(2.0), NotNanF64::new(3.0)..=NotNanF64::new(4.0)]);
398    /// assert_eq!(short, long);
399    /// ```
400    /// # Panics
401    ///
402    /// Panics when the returned iterator is consumed if any range endpoint is NaN.
403    pub fn from_primitive_ranges<I>(ranges: I) -> impl Iterator<Item = RangeInclusive<Self>>
404    where
405        I: IntoIterator<Item = RangeInclusive<T>>,
406    {
407        ranges.into_iter().map(Self::from_primitive_range)
408    }
409
410    /// Convenience method to convert primitive values into ordered [`NotNan`] values.
411    /// # Examples
412    /// ```
413    /// use range_set_blaze::{RangeSetBlaze, NotNanF64};
414    ///
415    /// let short = RangeSetBlaze::from_iter(NotNanF64::values([1.0, 2.0, 3.0, 4.0]));
416    /// let long = RangeSetBlaze::from_iter([NotNanF64::new(1.0), NotNanF64::new(2.0), NotNanF64::new(3.0), NotNanF64::new(4.0)]);
417    /// assert_eq!(short, long);
418    /// ```
419    ///
420    /// # Panics
421    ///
422    /// Panics (when iterated) if any value is NaN.
423    pub fn values<I>(values: I) -> impl Iterator<Item = Self>
424    where
425        I: IntoIterator<Item = T>,
426    {
427        values.into_iter().map(Self::new)
428    }
429
430    /// Views primitive values as ordered [`NotNan`] values, validating as it goes.
431    ///
432    /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
433    ///
434    ///
435    /// This runs in `O(n)` (to validate every element) and does not allocate.
436    /// # Examples
437    /// ```
438    /// use range_set_blaze::{RangeSetBlaze, NotNanF64};
439    ///
440    /// let short = RangeSetBlaze::from_iter(NotNanF64::from_primitive_slice(&[1.0, 2.0, 3.0, 4.0]));
441    /// let long = RangeSetBlaze::from_iter([NotNanF64::new(1.0), NotNanF64::new(2.0), NotNanF64::new(3.0), NotNanF64::new(4.0)]);
442    /// assert_eq!(short, long);
443    /// ```
444    ///
445    /// # Panics
446    ///
447    /// Panics if any element is NaN, or is `-0.0` (which can't be normalized to `+0.0`
448    /// without copying — see [`NotNan::from_primitive_slice_unchecked`] if you need a true
449    /// zero-copy view and can guarantee your data already satisfies [`NotNan`]'s invariant).
450    #[must_use]
451    pub fn from_primitive_slice(values: &[T]) -> &[Self] {
452        assert!(
453            values.iter().all(|&v| !T::is_nan(v) && !T::is_neg_zero(v)),
454            "NotNan type requires non-NaN, non-negative-zero values"
455        );
456        // SAFETY: just validated every element is not NaN and not -0.0.
457        unsafe { Self::from_primitive_slice_unchecked(values) }
458    }
459
460    /// Views primitive values as ordered [`NotNan`] values, without validating them.
461    ///
462    /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
463    ///
464    ///
465    /// This runs in `O(1)` and does not allocate.
466    ///
467    /// # Safety
468    ///
469    /// The caller must guarantee that every element of `values` is not NaN and not `-0.0`
470    /// (zero must already be canonicalized to `+0.0`). Because the returned slice is a live
471    /// view over the same memory (not a copy), there is no opportunity to normalize `-0.0`
472    /// even if the caller wanted to; the data must already be clean.
473    ///
474    /// [`NotNan`] has a public type invariant that safe code must never be able to break, even
475    /// though violating it today would only produce incorrect results (see
476    /// [`NotNan::new_unchecked`] for the full rationale).
477    #[must_use]
478    pub const unsafe fn from_primitive_slice_unchecked(values: &[T]) -> &[Self] {
479        // SAFETY: NotNan is #[repr(transparent)] over T, making `&[T]`
480        // and `&[NotNan]` entirely interchangeable in layout and lifetimes; the caller is
481        // responsible for the value-level invariant per the safety doc above.
482        unsafe { mem::transmute::<&[T], &[Self]>(values) }
483    }
484}
485
486/// Extension trait for viewing a slice of [`NotNan`] values as primitive values.
487pub trait NotNanSliceExt<T: NotNanFloat> {
488    /// Views [`NotNan`] values as primitive values.
489    ///
490    /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
491    ///
492    ///
493    /// This runs in `O(1)` and does not allocate.
494    /// # Examples
495    /// ```
496    /// use range_set_blaze::NotNanF64;
497    /// use range_set_blaze::not_nan::NotNanSliceExt;
498    ///
499    /// let not_nans = [NotNanF64::new(1.0), NotNanF64::new(2.0), NotNanF64::new(3.0)];
500    /// assert_eq!(&[1.0, 2.0, 3.0], not_nans.as_primitive_slice());
501    /// ```
502    fn as_primitive_slice(&self) -> &[T];
503}
504
505impl<T: NotNanFloat> NotNanSliceExt<T> for [NotNan<T>] {
506    fn as_primitive_slice(&self) -> &[T] {
507        // SAFETY: NotNan<T> is #[repr(transparent)] over T, making `&[T]`
508        // and `&[NotNan<T>]` entirely interchangeable in layout and lifetimes.
509        unsafe { from_raw_parts(self.as_ptr().cast::<T>(), self.len()) }
510    }
511}
512
513/// Extension trait for converting an inclusive [`NotNan`] range into an inclusive primitive
514/// range (or a `(start, end)` primitive tuple).
515pub trait NotNanRangeExt<T: NotNanFloat> {
516    /// Converts an inclusive [`NotNan`] range into an inclusive primitive range.
517    ///
518    /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
519    ///
520    ///
521    /// This is the reverse of [`NotNan::from_primitive_range`].
522    ///
523    /// # Examples
524    /// ```
525    /// use range_set_blaze::NotNanF64;
526    /// use range_set_blaze::not_nan::NotNanRangeExt;
527    ///
528    /// let range = NotNanF64::new(3.0)..=NotNanF64::new(5.0);
529    /// assert_eq!(range.into_primitive_range(), 3.0..=5.0);
530    /// ```
531    #[must_use]
532    fn into_primitive_range(self) -> RangeInclusive<T>;
533
534    /// Converts an inclusive [`NotNan`] range into a `(start, end)` tuple of primitive values.
535    ///
536    /// "Primitive" here means Rust's built-in float type (e.g. `f64`).
537    ///
538    ///
539    /// Mirrors [`RangeInclusive::into_inner`] from the standard library, which unwraps a
540    /// range into its `(start, end)` tuple; this additionally converts each endpoint to its
541    /// primitive type.
542    ///
543    /// # Examples
544    /// ```
545    /// use range_set_blaze::NotNanF64;
546    /// use range_set_blaze::not_nan::NotNanRangeExt;
547    ///
548    /// let range = NotNanF64::new(3.0)..=NotNanF64::new(5.0);
549    /// assert_eq!(range.into_primitive_inner(), (3.0, 5.0));
550    /// ```
551    #[must_use]
552    fn into_primitive_inner(self) -> (T, T);
553}
554
555impl<T: NotNanFloat> NotNanRangeExt<T> for RangeInclusive<NotNan<T>> {
556    fn into_primitive_range(self) -> RangeInclusive<T> {
557        let (start, end) = self.into_primitive_inner();
558        start..=end
559    }
560
561    fn into_primitive_inner(self) -> (T, T) {
562        let (start, end) = self.into_inner();
563        (start.into_inner(), end.into_inner())
564    }
565}
566
567impl<T: NotNanFloat> PartialEq for NotNan<T> {
568    fn eq(&self, other: &Self) -> bool {
569        T::total_cmp(self.0, other.0) == Ordering::Equal
570    }
571}
572
573impl<T: NotNanFloat> Eq for NotNan<T> {}
574
575impl<T: NotNanFloat> PartialOrd for NotNan<T> {
576    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
577        Some(self.cmp(other))
578    }
579}
580
581impl<T: NotNanFloat> Ord for NotNan<T> {
582    fn cmp(&self, other: &Self) -> Ordering {
583        T::total_cmp(self.0, other.0)
584    }
585}
586
587impl<T: NotNanFloat> Hash for NotNan<T> {
588    fn hash<H: Hasher>(&self, state: &mut H) {
589        T::hash(self.0, state);
590    }
591}
592
593impl<T: NotNanFloat> Integer for NotNan<T> {
594    type SafeLen = T::SafeLen;
595
596    #[inline]
597    fn checked_add_one(self) -> Option<Self> {
598        self.checked_after()
599    }
600
601    // This moves to the next representable float in total_cmp order, not a numeric + 1.0.
602    #[inline]
603    fn add_one(self) -> Self {
604        self.after()
605    }
606
607    #[inline]
608    // This moves to the previous representable float in total_cmp order, not a numeric - 1.0.
609    fn sub_one(self) -> Self {
610        self.before()
611    }
612
613    #[inline]
614    fn assign_sub_one(&mut self) {
615        *self = self.before();
616    }
617
618    // Ideally, we would `impl std::iter::Step for NotNanF64` and just call Range::next(), but that's still experimental.
619    #[inline]
620    fn range_next(range: &mut RangeInclusive<Self>) -> Option<Self> {
621        if range.is_empty() {
622            None
623        } else if range.start() == range.end() && *range.start() == Self::MAX {
624            // Preserve the exhausted range sentinel without calling `after()` on MAX.
625            let next = *range.start();
626            *range = next..=range.end().before();
627            Some(next)
628        } else {
629            let next = *range.start();
630            *range = (next.after())..=*range.end();
631            Some(next)
632        }
633    }
634
635    #[inline]
636    fn range_next_back(range: &mut RangeInclusive<Self>) -> Option<Self> {
637        if range.is_empty() {
638            None
639        } else if range.start() == range.end() && *range.start() == Self::MIN {
640            // Preserve the exhausted range sentinel without calling `before()` on MIN.
641            let last = *range.end();
642            *range = last.after()..=last;
643            Some(last)
644        } else {
645            let last = *range.end();
646            *range = *range.start()..=last.before();
647            Some(last)
648        }
649    }
650
651    #[inline]
652    fn min_value() -> Self {
653        Self::MIN
654    }
655
656    #[inline]
657    fn max_value() -> Self {
658        Self::MAX
659    }
660
661    #[cfg(feature = "from_slice")]
662    #[inline]
663    fn from_slice(slice: impl AsRef<[Self]>) -> RangeSetBlaze<Self> {
664        // TODO Investigate applying the ordered float transform in SIMD chunks here.
665        // no way to do the fancy thing
666        RangeSetBlaze::from_iter(slice.as_ref())
667    }
668
669    fn safe_len(r: &RangeInclusive<Self>) -> Self::SafeLen {
670        let (start, end) = r.clone().into_primitive_inner();
671        T::prim_safe_len(start, end)
672    }
673
674    fn safe_len_to_f64_lossy(len: Self::SafeLen) -> f64 {
675        T::safe_len_to_f64_lossy(len)
676    }
677
678    fn f64_to_safe_len_lossy(f: f64) -> Self::SafeLen {
679        T::f64_to_safe_len_lossy(f)
680    }
681
682    fn inclusive_end_from_start(self, b: Self::SafeLen) -> Self {
683        self.inclusive_end_from_start(b)
684    }
685
686    fn start_from_inclusive_end(self, b: Self::SafeLen) -> Self {
687        self.start_from_inclusive_end(b)
688    }
689}
690
691#[cfg(test)]
692mod tests {
693    use super::*;
694    use crate::Integer;
695    #[cfg(not(target_arch = "wasm32"))]
696    use std::hint::black_box;
697    #[cfg(not(target_arch = "wasm32"))]
698    use std::panic::{AssertUnwindSafe, catch_unwind};
699    use std::vec;
700    use std::vec::Vec;
701
702    #[cfg(not(target_arch = "wasm32"))]
703    fn panics(f: impl FnOnce()) -> bool {
704        catch_unwind(AssertUnwindSafe(f)).is_err()
705    }
706
707    // WASM targets currently abort instead of unwinding, so `catch_unwind`
708    // cannot observe the expected constructor panics there.
709    #[cfg(not(target_arch = "wasm32"))]
710    #[test]
711    #[allow(clippy::float_cmp)]
712    fn safe_constructors_preserve_not_nan_invariant() {
713        assert_eq!(nnf32(-0.0).into_inner().to_bits(), 0);
714        assert_eq!(nnf64(-0.0).into_inner().to_bits(), 0);
715        assert_eq!(NotNanF64::new(-0.0), nnf64(0.0));
716        assert_eq!(NotNanF64::try_new(-0.0), Some(nnf64(0.0)));
717
718        // Infinities are legal values, not rejected.
719        for value in [f64::INFINITY, f64::NEG_INFINITY] {
720            assert_eq!(NotNanF64::new(value).into_inner(), value);
721            assert_eq!(NotNanF64::try_new(value), Some(NotNanF64::new(value)));
722        }
723
724        for invalid in [f64::NAN, -f64::NAN] {
725            assert!(panics(|| {
726                black_box(NotNanF64::new(invalid));
727            }));
728            assert_eq!(NotNanF64::try_new(invalid), None);
729            assert!(panics(|| drop(NotNanF64::from_primitive_range(
730                invalid..=1.0
731            ))));
732            assert!(panics(|| {
733                NotNanF64::values([invalid]).count();
734            }));
735            assert!(panics(|| {
736                black_box(NotNanF64::from_primitive_slice(&[invalid]));
737            }));
738        }
739
740        assert!(panics(|| {
741            black_box(NotNanF64::from_primitive_slice(&[-0.0]));
742        }));
743        assert!(panics(|| {
744            black_box(NotNanF64::from_primitive_slice(&[f64::NAN]));
745        }));
746
747        let values = [1.0, 2.0, 3.0];
748        let not_nans = NotNanF64::from_primitive_slice(&values);
749        assert_eq!(not_nans.as_primitive_slice(), &values);
750        assert_eq!(
751            NotNanF64::values(values).collect::<Vec<_>>(),
752            vec![nnf64(1.0), nnf64(2.0), nnf64(3.0)]
753        );
754        assert_eq!(
755            NotNanF64::from_primitive_ranges([1.0..=2.0]).collect::<Vec<_>>(),
756            vec![nnf64(1.0)..=nnf64(2.0)]
757        );
758    }
759
760    #[test]
761    fn ordering_agrees_with_total_cmp() {
762        let values = [
763            f64::NEG_INFINITY,
764            -f64::MAX,
765            -1.0,
766            0.0,
767            1.0,
768            f64::MAX,
769            f64::INFINITY,
770        ];
771
772        for left in values {
773            for right in values {
774                assert_eq!(nnf64(left).cmp(&nnf64(right)), left.total_cmp(&right));
775            }
776        }
777        assert_ne!(nnf64(0.0).cmp(&nnf64(-0.0)), 0.0_f64.total_cmp(&-0.0));
778    }
779
780    #[test]
781    fn converts_ranges() {
782        assert_eq!(
783            NotNanF64::from_primitive_range(10.0..=20.0),
784            nnf64(10.0)..=nnf64(20.0)
785        );
786        assert_eq!(
787            NotNanF64::from_primitive_ranges([10.0..=20.0, 30.0..=40.0]).collect::<Vec<_>>(),
788            vec![nnf64(10.0)..=nnf64(20.0), nnf64(30.0)..=nnf64(40.0)]
789        );
790    }
791
792    #[test]
793    fn after_and_before_step_through_zero_in_total_order() {
794        assert_eq!(nnf64(-0.0), nnf64(0.0));
795        assert_ne!(nnf64(0.0).before(), nnf64(-0.0));
796        assert_eq!(nnf64(0.0).after(), nnf64(f64::from_bits(1)));
797        assert_eq!(
798            nnf64(0.0).before(),
799            nnf64(f64::from_bits(0x8000_0000_0000_0001))
800        );
801    }
802
803    #[test]
804    fn after_and_before_panic_at_boundaries_in_all_build_modes() {
805        assert_eq!(NotNanF64::MAX.checked_after(), None);
806        assert_eq!(NotNanF64::MIN.checked_before(), None);
807    }
808
809    #[test]
810    #[should_panic(expected = "b must be in range 1..=max_len")]
811    fn not_nan_endpoint_offset_cannot_leave_domain() {
812        let _ = NotNanF32::MAX.inclusive_end_from_start(2);
813    }
814
815    #[test]
816    #[should_panic(expected = "after() called on maximum value")]
817    fn after_panics_at_max() {
818        let _ = NotNanF64::MAX.after();
819    }
820
821    #[test]
822    #[should_panic(expected = "before() called on minimum value")]
823    fn before_panics_at_min() {
824        let _ = NotNanF64::MIN.before();
825    }
826
827    #[test]
828    fn checked_after_and_before_stop_at_total_order_boundaries() {
829        assert_eq!(NotNanF64::MIN.checked_before(), None);
830        assert_eq!(NotNanF64::MAX.checked_after(), None);
831        assert_eq!(NotNanF64::MIN.checked_after(), Some(NotNanF64::MIN.after()));
832        assert_eq!(
833            NotNanF64::MAX.checked_before(),
834            Some(NotNanF64::MAX.before())
835        );
836    }
837
838    #[test]
839    fn min_and_max_are_total_order_boundaries() {
840        let values = [
841            nnf64(-f64::MAX),
842            nnf64(-1.0),
843            nnf64(-0.0),
844            nnf64(0.0),
845            nnf64(1.0),
846            nnf64(f64::MAX),
847        ];
848
849        for value in values {
850            assert!(NotNanF64::MIN <= value);
851            assert!(value <= NotNanF64::MAX);
852        }
853    }
854
855    /// `MIN`/`MAX` are the infinities, and they sit directly adjacent (in total order) to the
856    /// largest-magnitude finite values -- exactly the values reached by stepping `.before()`/
857    /// `.after()` once, and nowhere else.
858    #[test]
859    fn infinities_are_adjacent_to_finite_extremes() {
860        assert_eq!(NotNanF64::MIN, nnf64(f64::NEG_INFINITY));
861        assert_eq!(NotNanF64::MAX, nnf64(f64::INFINITY));
862        assert_eq!(NotNanF64::MIN.after(), nnf64(f64::MIN));
863        assert_eq!(NotNanF64::MAX.before(), nnf64(f64::MAX));
864        assert_eq!(nnf64(f64::MIN).before(), NotNanF64::MIN);
865        assert_eq!(nnf64(f64::MAX).after(), NotNanF64::MAX);
866
867        assert_eq!(NotNanF32::MIN, nnf32(f32::NEG_INFINITY));
868        assert_eq!(NotNanF32::MAX, nnf32(f32::INFINITY));
869        assert_eq!(NotNanF32::MIN.after(), nnf32(f32::MIN));
870        assert_eq!(NotNanF32::MAX.before(), nnf32(f32::MAX));
871        assert_eq!(nnf32(f32::MIN).before(), NotNanF32::MIN);
872        assert_eq!(nnf32(f32::MAX).after(), NotNanF32::MAX);
873    }
874
875    #[test]
876    fn infinities_are_valid_range_endpoints() {
877        use crate::RangeSetBlaze;
878
879        let set = RangeSetBlaze::from_iter([nnf64(f64::NEG_INFINITY)..=nnf64(0.0)]);
880        assert!(set.contains(NotNanF64::MIN));
881        assert!(set.contains(nnf64(f64::MIN)));
882        assert!(set.contains(nnf64(0.0)));
883        assert!(!set.contains(nnf64(0.0).after()));
884        assert!(!set.contains(NotNanF64::MAX));
885
886        let full = !RangeSetBlaze::<NotNanF64>::new();
887        assert!(full.contains(NotNanF64::MIN));
888        assert!(full.contains(NotNanF64::MAX));
889        assert_eq!(full.len(), NotNanF64::MAX_SIZE);
890    }
891
892    #[test]
893    fn after_and_before_are_neighbors_in_total_order() {
894        let values = [
895            NotNanF64::MIN,
896            nnf64(f64::MIN),
897            nnf64(-f64::MAX),
898            nnf64(-1.0),
899            nnf64(-0.0),
900            nnf64(0.0),
901            nnf64(1.0),
902            nnf64(f64::MAX),
903            NotNanF64::MAX,
904        ];
905
906        for value in values {
907            if value != NotNanF64::MAX {
908                assert_eq!(value.after().before(), value);
909            }
910            if value != NotNanF64::MIN {
911                assert_eq!(value.before().after(), value);
912            }
913        }
914    }
915
916    #[test]
917    fn adjacency_laws_cover_f32_and_f64_edges() {
918        macro_rules! check {
919            ($name:ident, $zero:expr, $negative_subnormal:expr, $positive_subnormal:expr, $min:expr, $max:expr) => {{
920                let values = [
921                    nnf32($zero),
922                    nnf32($negative_subnormal),
923                    nnf32($positive_subnormal),
924                    nnf32(-1.0),
925                    nnf32(1.0),
926                    nnf32($min),
927                    nnf32($max),
928                ];
929                for value in values {
930                    if value != NotNanF32::MAX {
931                        assert_eq!(value.after().before(), value);
932                    }
933                    if value != NotNanF32::MIN {
934                        assert_eq!(value.before().after(), value);
935                    }
936                }
937                assert_eq!(NotNanF32::MIN.checked_before(), None);
938                assert_eq!(NotNanF32::MAX.checked_after(), None);
939                assert_eq!(nnf32($negative_subnormal).after(), nnf32($zero));
940                assert_eq!(nnf32($zero).after(), nnf32($positive_subnormal));
941                let _ = stringify!($name);
942            }};
943        }
944
945        check!(
946            f32_edges,
947            0.0_f32,
948            -f32::from_bits(1),
949            f32::from_bits(1),
950            f32::MIN,
951            f32::MAX
952        );
953
954        let values = [
955            nnf64(-f64::from_bits(1)),
956            nnf64(0.0),
957            nnf64(f64::from_bits(1)),
958            nnf64(-1.0),
959            nnf64(1.0),
960            NotNanF64::MIN,
961            NotNanF64::MAX,
962        ];
963        for value in values {
964            if value != NotNanF64::MAX {
965                assert_eq!(value.after().before(), value);
966            }
967            if value != NotNanF64::MIN {
968                assert_eq!(value.before().after(), value);
969            }
970        }
971        assert_eq!(NotNanF64::MIN.checked_before(), None);
972        assert_eq!(NotNanF64::MAX.checked_after(), None);
973        assert_eq!(nnf64(-f64::from_bits(1)).after(), nnf64(0.0));
974        assert_eq!(nnf64(0.0).after(), nnf64(f64::from_bits(1)));
975    }
976
977    #[test]
978    fn range_length_laws_cover_f32_and_f64() {
979        let start = nnf32(-f32::from_bits(1));
980        let end = nnf32(f32::from_bits(1));
981        assert_eq!(NotNanF32::safe_len(&(start..=start)), 1);
982        assert_eq!(NotNanF32::safe_len(&(start..=start.after())), 2);
983        assert_eq!(NotNanF32::safe_len(&(start..=end)), 3);
984        assert_eq!(
985            NotNanF32::MAX_SIZE,
986            NotNanF32::safe_len(&(NotNanF32::MIN..=NotNanF32::MAX))
987        );
988        let length = 17;
989        let endpoint = start.inclusive_end_from_start(length);
990        assert_eq!(endpoint.start_from_inclusive_end(length), start);
991        assert_eq!(start.inclusive_end_from_start(length), endpoint);
992
993        let start = nnf64(-f64::from_bits(1));
994        let end = nnf64(f64::from_bits(1));
995        assert_eq!(NotNanF64::safe_len(&(start..=start)), 1);
996        assert_eq!(NotNanF64::safe_len(&(start..=start.after())), 2);
997        assert_eq!(NotNanF64::safe_len(&(start..=end)), 3);
998        assert_eq!(
999            NotNanF64::MAX_SIZE,
1000            NotNanF64::safe_len(&(NotNanF64::MIN..=NotNanF64::MAX))
1001        );
1002        let length = 17;
1003        let endpoint = start.inclusive_end_from_start(length);
1004        assert_eq!(endpoint.start_from_inclusive_end(length), start);
1005        assert_eq!(start.inclusive_end_from_start(length), endpoint);
1006    }
1007
1008    #[cfg(feature = "float_nightly_experimental")]
1009    #[test]
1010    fn f16_not_nan_adjacency_and_lengths_are_exhaustive() {
1011        for bits in 0..=u16::MAX {
1012            let value = f16::from_bits(bits);
1013            let Some(value) = NotNanF16::try_new(value) else {
1014                continue;
1015            };
1016            if value != NotNanF16::MIN {
1017                assert_eq!(value.before().after(), value);
1018            }
1019            if value != NotNanF16::MAX {
1020                assert_eq!(value.after().before(), value);
1021            }
1022            assert_eq!(NotNanF16::safe_len(&(value..=value)), 1);
1023        }
1024        assert_eq!(
1025            NotNanF16::MAX_SIZE,
1026            NotNanF16::safe_len(&(NotNanF16::MIN..=NotNanF16::MAX))
1027        );
1028    }
1029}