Skip to main content

range_set_blaze/float/
finite.rs

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