unit_interval/
lib.rs

1#![deny(missing_docs)]
2#![deny(rustdoc::broken_intra_doc_links)]
3#![deny(rustdoc::invalid_rust_codeblocks)]
4#![deny(rustdoc::missing_crate_level_docs)]
5#![warn(rustdoc::invalid_codeblock_attributes)]
6//! A small crate for working with numbers in the unit interval.
7//!
8//! This crate currently only provides the [`UnitInterval`] type, which represents a number
9//! constrained to the closed interval between 0 and 1, inclusive. It offers
10//! operations, bounds checking, and utilities for working with
11//! values in this range.
12//!
13//! ## Quick Start
14//!
15//! To get started, create a `UnitInterval` using one of the many constructor methods:
16//!
17//! ```rust
18//! use unit_interval::UnitInterval;
19//!
20//! // Create a UnitInterval, panics if out of bounds
21//! let a = UnitInterval::new(0.5);
22//!
23//! // Create a UnitInterval, returns a Result
24//! let b = UnitInterval::new_checked(0.75).unwrap();
25//!
26//! // Create a UnitInterval, clamping the value to [0, 1]
27//! let c = UnitInterval::new_clamped(1.5);
28//! assert_eq!(c.into_inner(), 1.0);
29//! ```
30//!
31//! Perform operations on `UnitInterval` values:
32//!
33//! ```rust
34//! use unit_interval::UnitInterval;
35//!
36//! let a = UnitInterval::new(0.3);
37//! let b = UnitInterval::new(0.5);
38//!
39//! // Multiplication always stays within [0, 1]
40//! let product = a * b;
41//! assert_eq!(product.into_inner(), 0.15);
42//!
43//! // Other operations may need checking or clamping
44//! let sum = a.checked_add(b).unwrap();
45//! let difference = a.clamped_sub(b);
46//! ```
47
48use core::borrow::Borrow;
49use core::error;
50use core::fmt::{self, Debug, Display};
51use core::ops::{Add, Div, Mul, Sub};
52
53use num_traits::{float::FloatCore, One, Zero};
54
55/// A number in the closed [unit interval](https://en.wikipedia.org/wiki/Unit_interval) \[0, 1\]
56///
57/// The precise invariant is that for an underlying value `v` of type `T` is
58/// `T::zero() <= v` and `v <= T::one()` where [`Zero`] and [`One`] are traits
59/// from from the [num-traits] crate.
60///
61/// Unlike [`NonZero`](core::num::NonZero) types, this type does not reserve any bit-patterns
62/// and simply guarantee that the value inside will not exceed the bounds via construction.
63/// Unsoundly constructing a value of this type that exceed its bounds will not result in immediate
64/// undefined behavior.
65///
66/// # Examples
67/// ```
68/// use unit_interval::UnitInterval;
69///
70/// let full = UnitInterval::one();
71/// let half = UnitInterval::new(0.5);
72///
73/// assert_eq!(full + half, 1.5);
74/// assert_eq!(half - full, -0.5);
75/// assert_eq!(half * full, UnitInterval::new(0.5));
76/// assert_eq!(full / half, 2.0);
77///
78/// assert_eq!(full.into_inner(), 1.0);
79/// assert_eq!(half.into_inner(), 0.5);
80/// ```
81///
82/// [`num-traits`]: https://crates.io/crates/num-traits
83#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
84#[repr(transparent)]
85pub struct UnitInterval<T>(T);
86
87/// An error type representing a value that falls outside the closed unit interval \[0, 1\]
88///
89/// This type is returned by operations that may produce values outside the unit interval,
90/// providing information about how the value exceeds the bounds.
91#[derive(Clone, Copy, PartialEq, Eq)]
92pub struct BoundError<T> {
93    kind: BoundErrorKind,
94    val: T,
95}
96impl<T> BoundError<T> {
97    #[inline]
98    const fn new(kind: BoundErrorKind, val: T) -> Self {
99        Self { kind, val }
100    }
101    #[inline]
102    const fn less_than_zero(val: T) -> Self {
103        Self::new(BoundErrorKind::LessThanZero, val)
104    }
105    #[inline]
106    const fn greater_than_one(val: T) -> Self {
107        Self::new(BoundErrorKind::GreaterThanOne, val)
108    }
109    #[inline]
110    const fn neither(val: T) -> Self {
111        Self::new(BoundErrorKind::Neither, val)
112    }
113
114    /// The way in which the value is out of bounds.
115    ///
116    /// For more detail, see [BoundErrorKind].
117    #[inline]
118    pub const fn kind(&self) -> BoundErrorKind {
119        self.kind
120    }
121    /// The value that caused the error.
122    ///
123    /// The same one used in the attempted creation of a [`UnitInterval`].
124    #[inline]
125    pub fn value(self) -> T {
126        self.val
127    }
128}
129impl<T: Debug> Debug for BoundError<T> {
130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131        match self.kind {
132            BoundErrorKind::LessThanZero => {
133                write!(f, "{:?} compares less than zero", self.val)
134            }
135            BoundErrorKind::GreaterThanOne => {
136                write!(f, "{:?} compares greater than one", self.val)
137            }
138            BoundErrorKind::Neither => write!(
139                f,
140                "{:?} compares neither greater than or equal to zero nor less than or equal to one",
141                self.val
142            ),
143        }
144    }
145}
146impl<T: Display> Display for BoundError<T> {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        match self.kind {
149            BoundErrorKind::LessThanZero => write!(f, "{} compares less than zero", self.val),
150            BoundErrorKind::GreaterThanOne => {
151                write!(f, "{} compares greater than one", self.val)
152            }
153            BoundErrorKind::Neither => write!(
154                f,
155                "{} compares neither greater than or equal to zero nor less than or equal to one",
156                self.val
157            ),
158        }
159    }
160}
161
162impl<T: Debug + Display> error::Error for BoundError<T> {}
163
164/// Describes how a value falls outside the closed unit interval [0, 1]
165///
166/// # Examples
167/// ```
168/// use unit_interval::{UnitInterval, BoundErrorKind};
169///
170/// let result = UnitInterval::new_checked(-0.5);
171/// assert_eq!(result.unwrap_err().kind(), BoundErrorKind::LessThanZero);
172///
173/// let result = UnitInterval::new_checked(1.5);
174/// assert_eq!(result.unwrap_err().kind(), BoundErrorKind::GreaterThanOne);
175///
176/// let result = UnitInterval::new_checked(f32::NAN);
177/// assert_eq!(result.unwrap_err().kind(), BoundErrorKind::Neither);
178/// ```
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq)]
181pub enum BoundErrorKind {
182    /// The value is less than both zero and one
183    ///
184    /// When `T::zero() <= val` is false but `val <= T::one()` is true.
185    LessThanZero,
186    /// The value is greater than both zero and one
187    ///
188    /// When `T::zero() <= val` is true but `val <= T::one()` is false.
189    GreaterThanOne,
190    /// The value is neither greater than or equal to zero nor less than or equal to one
191    ///
192    /// When both `T::zero() <= val` and `val <= T::one()` are false.
193    ///
194    /// This can mean 2 things:
195    /// 1. The value is [NaN]-like
196    /// 2. The comparison operations ([`PartialOrd`]) or [`Zero`] or [`One`]
197    ///     are incorrectly implemented for the type of the value
198    ///
199    /// [NaN]: https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN
200    Neither,
201}
202
203impl<T: Zero + One + PartialOrd> UnitInterval<T> {
204    /// Guarantee the number in the closed unit interval if
205    /// `T::zero() <= val` and `val <= T::one()`, else returns an error
206    /// detailing which bound was crossed.
207    #[inline]
208    pub fn new_checked(val: T) -> Result<Self, BoundError<T>> {
209        match (T::zero() <= val, val <= T::one()) {
210            (true, true) => Ok(Self(val)),
211            (true, false) => Err(BoundError::greater_than_one(val)),
212            (false, true) => Err(BoundError::less_than_zero(val)),
213            (false, false) => Err(BoundError::neither(val)),
214        }
215    }
216    /// Guarantee the number in the closed unit interval, clamping the value
217    /// if it exceed the bounds in either direction.
218    ///
219    /// # Panics
220    /// Panics if the value exceed the bounds in both direction
221    /// (see [`BoundErrorKind::Neither`]).
222    ///
223    /// # Examples
224    /// ```
225    /// use unit_interval::UnitInterval;
226    ///
227    /// assert_eq!(UnitInterval::new_clamped(2).into_inner(), 1);
228    /// assert_eq!(UnitInterval::new_clamped(-5).into_inner(), 0);
229    /// ```
230    ///
231    /// NaN is an example of when this function panics
232    /// ```should_panic
233    /// use unit_interval::UnitInterval;
234    ///
235    /// let _ = UnitInterval::new_clamped(f32::NAN);
236    /// ```
237    #[inline]
238    #[must_use]
239    pub fn new_clamped(val: T) -> Self {
240        let zero = T::zero();
241        let one = T::one();
242        match (zero <= val, val <= one) {
243            (true, true) => Self(val),
244            (true, false) => Self(one),
245            (false, true) => Self(zero),
246            (false, false) => {
247                panic!("Value must compare greater equal to zero OR less equal to one")
248            }
249        }
250    }
251    /// Guarantee the number in the closed unit interval, panicking if not.
252    ///
253    /// # Panics
254    /// Panics if the number is not within the unit interval.
255    #[inline]
256    #[must_use]
257    pub fn new(val: T) -> Self
258    where
259        T: Debug,
260    {
261        Self::new_checked(val).expect("Value must be in the interval [0, 1]")
262    }
263}
264impl<T: FloatCore> UnitInterval<T> {
265    /// Guarantee the number in the closed unit interval by taking only
266    /// its fractional part.
267    ///
268    /// This cannot fail as the fractional part of a number is off the range [0, 1),
269    /// which is a subset of \[0, 1\].
270    #[inline]
271    #[must_use]
272    pub fn new_fract(val: T) -> Self {
273        Self(val.fract())
274    }
275}
276impl<T> UnitInterval<T> {
277    /// Assumes that the number is in the closed unit interval.
278    ///
279    /// # Safety
280    /// Improper usage of this function should only lead to logic error and not undefined behavior
281    /// as long as no further unsafe code rely on the guarantee granted by this type.
282    #[inline]
283    #[must_use]
284    pub const unsafe fn new_unchecked(val: T) -> Self {
285        Self(val)
286    }
287
288    /// Returns a reference to the inner value.
289    #[inline]
290    pub const fn as_inner(&self) -> &T {
291        &self.0
292    }
293    /// Consumes the `UnitInterval` and returns the inner value.
294    #[inline]
295    pub fn into_inner(self) -> T {
296        self.0
297    }
298}
299impl<T: Zero> UnitInterval<T> {
300    /// Creates a new `UnitInterval` with a value of zero.
301    ///
302    /// # Examples
303    /// ```
304    /// use unit_interval::UnitInterval;
305    ///
306    /// let zero = UnitInterval::<f32>::zero();
307    /// assert_eq!(zero.into_inner(), 0.0);
308    /// ```
309    #[inline]
310    pub fn zero() -> Self {
311        Self(T::zero())
312    }
313}
314impl<T: One> UnitInterval<T> {
315    /// Creates a new `UnitInterval` with a value of one.
316    ///
317    /// # Examples
318    /// ```
319    /// use unit_interval::UnitInterval;
320    ///
321    /// let one = UnitInterval::<f32>::one();
322    /// assert_eq!(one.into_inner(), 1.0);
323    /// ```
324    #[inline]
325    pub fn one() -> Self {
326        Self(T::one())
327    }
328    /// Returns the complement of the currently held value.
329    ///
330    /// # Examples
331    /// ```
332    /// use unit_interval::UnitInterval;
333    ///
334    /// let a = UnitInterval::new(0.2);
335    /// assert_eq!(a.complement(), UnitInterval::new(0.8));
336    /// ```
337    #[inline]
338    pub fn complement(self) -> UnitInterval<<T as Sub>::Output>
339    where
340        T: Sub,
341    {
342        UnitInterval(T::one() - self.0)
343    }
344}
345
346impl<T: Add> UnitInterval<T>
347where
348    T::Output: Zero + One + PartialOrd,
349{
350    /// Adds a value inside the close unit interval to produce another.
351    ///
352    /// Equivalent to adding the inner values then using [`UnitInterval::new_checked`].
353    ///
354    /// # Examples
355    /// ```
356    /// use unit_interval::{UnitInterval, BoundErrorKind};
357    ///
358    /// let a = UnitInterval::new(0.5);
359    /// let b = UnitInterval::new(0.75);
360    /// let result = a.checked_add(b);
361    /// assert_eq!(result, UnitInterval::new_checked(0.5 + 0.75));
362    /// let err = result.unwrap_err();
363    /// assert_eq!(err.kind(), BoundErrorKind::GreaterThanOne);
364    /// assert_eq!(err.value(), 1.25);
365    /// ```
366    #[inline]
367    pub fn checked_add(self, rhs: Self) -> Result<UnitInterval<T::Output>, BoundError<T::Output>> {
368        UnitInterval::new_checked(self.0 + rhs.0)
369    }
370    /// Adds two `UnitInterval` values, clamping the result to the unit interval.
371    ///
372    /// # Examples
373    /// ```
374    /// use unit_interval::UnitInterval;
375    ///
376    /// let a = UnitInterval::new(0.7);
377    /// let b = UnitInterval::new(0.6);
378    /// let result = a.clamped_add(b);
379    /// assert_eq!(result.into_inner(), 1.0);
380    /// ```
381    #[inline]
382    pub fn clamped_add(self, rhs: Self) -> UnitInterval<T::Output> {
383        UnitInterval::new_clamped(self.0 + rhs.0)
384    }
385}
386impl<T: Sub> UnitInterval<T>
387where
388    T::Output: Zero + One + PartialOrd,
389{
390    /// Subtracts a value inside the close unit interval to produce another.
391    ///
392    /// Equivalent to subtracting the inner values then using [`UnitInterval::new_checked`].
393    ///
394    /// # Examples
395    /// ```
396    /// use unit_interval::{UnitInterval, BoundErrorKind};
397    ///
398    /// let a = UnitInterval::new(0.4);
399    /// let b = UnitInterval::new(0.8);
400    /// let result = a.checked_sub(b);
401    /// assert_eq!(result, UnitInterval::new_checked(0.4 - 0.8));
402    /// let err = result.unwrap_err();
403    /// assert_eq!(err.kind(), BoundErrorKind::LessThanZero);
404    /// assert_eq!(err.value(), -0.4);
405    /// ```
406    #[inline]
407    pub fn checked_sub(self, rhs: Self) -> Result<UnitInterval<T::Output>, BoundError<T::Output>> {
408        UnitInterval::new_checked(self.0 - rhs.0)
409    }
410    /// Subtracts one `UnitInterval` from another, clamping the result to the unit interval.
411    ///
412    /// # Examples
413    /// ```
414    /// use unit_interval::UnitInterval;
415    ///
416    /// let a = UnitInterval::new(0.3);
417    /// let b = UnitInterval::new(0.6);
418    /// let result = a.clamped_sub(b);
419    /// assert_eq!(result.into_inner(), 0.0);
420    /// ```
421    #[inline]
422    pub fn clamped_sub(self, rhs: Self) -> UnitInterval<T::Output> {
423        UnitInterval::new_clamped(self.0 - rhs.0)
424    }
425}
426impl<T: Mul> UnitInterval<T>
427where
428    T::Output: Zero + One + PartialOrd,
429{
430    /// Multiplies a value inside the close unit interval to produce another.
431    ///
432    /// Equivalent to multiplying the inner values then using [`UnitInterval::new_checked`].
433    ///
434    /// Note: Multiplication of two values in [0, 1] always results in a value in [0, 1],
435    /// so checking is not strictly necessary for this operation.
436    ///
437    /// # Examples
438    /// ```
439    /// use unit_interval::UnitInterval;
440    ///
441    /// let a = UnitInterval::new(0.5);
442    /// let b = UnitInterval::new(0.6);
443    /// let result = a.checked_mul(b);
444    /// assert_eq!(result, UnitInterval::new_checked(0.5 * 0.6));
445    /// let ok = result.unwrap();
446    /// assert_eq!(ok.into_inner(), 0.3);
447    /// ```
448    #[inline]
449    pub fn checked_mul(self, rhs: Self) -> Result<UnitInterval<T::Output>, BoundError<T::Output>> {
450        UnitInterval::new_checked(self.0 * rhs.0)
451    }
452    /// Multiplies two `UnitInterval` values, clamping the result to the unit interval.
453    ///
454    /// Note: Multiplication of two values in [0, 1] always results in a value in [0, 1],
455    /// so clamping is not strictly necessary for this operation.
456    ///
457    /// # Examples
458    /// ```
459    /// use unit_interval::UnitInterval;
460    ///
461    /// let a = UnitInterval::new(0.5);
462    /// let b = UnitInterval::new(0.6);
463    /// let result = a.clamped_mul(b);
464    /// assert_eq!(result.into_inner(), 0.3);
465    /// ```
466    #[inline]
467    pub fn clamped_mul(self, rhs: Self) -> UnitInterval<T::Output> {
468        UnitInterval::new_clamped(self.0 * rhs.0)
469    }
470}
471impl<T: Div> UnitInterval<T>
472where
473    T::Output: Zero + One + PartialOrd,
474{
475    /// Divides a value inside the close unit interval to produce another.
476    ///
477    /// Equivalent to dividing the inner values then using [`UnitInterval::new_checked`].
478    ///
479    /// # Examples
480    /// ```
481    /// use unit_interval::{UnitInterval, BoundErrorKind};
482    ///
483    /// let a = UnitInterval::new(0.8);
484    /// let b = UnitInterval::new(0.4);
485    /// let result = a.checked_div(b);
486    /// assert_eq!(result, UnitInterval::new_checked(0.8 / 0.4));
487    /// let err = result.unwrap_err();
488    /// assert_eq!(err.kind(), BoundErrorKind::GreaterThanOne);
489    /// assert_eq!(err.value(), 2.0);
490    /// ```
491    #[inline]
492    pub fn checked_div(self, rhs: Self) -> Result<UnitInterval<T::Output>, BoundError<T::Output>> {
493        UnitInterval::new_checked(self.0 / rhs.0)
494    }
495    /// Divides one `UnitInterval` by another, clamping the result to the unit interval.
496    ///
497    /// # Examples
498    /// ```
499    /// use unit_interval::UnitInterval;
500    ///
501    /// let a = UnitInterval::new(0.8);
502    /// let b = UnitInterval::new(0.4);
503    /// let result = a.clamped_div(b);
504    /// assert_eq!(result.into_inner(), 1.0);
505    /// ```
506    #[inline]
507    pub fn clamped_div(self, rhs: Self) -> UnitInterval<T::Output> {
508        UnitInterval::new_clamped(self.0 / rhs.0)
509    }
510}
511
512impl<T: One> One for UnitInterval<T> {
513    #[inline]
514    fn one() -> Self {
515        UnitInterval::one()
516    }
517}
518
519impl<T: Add> Add<T> for UnitInterval<T> {
520    type Output = T::Output;
521
522    #[inline]
523    fn add(self, rhs: T) -> Self::Output {
524        self.0 + rhs
525    }
526}
527impl<T: Sub> Sub<T> for UnitInterval<T> {
528    type Output = T::Output;
529
530    #[inline]
531    fn sub(self, rhs: T) -> Self::Output {
532        self.0 - rhs
533    }
534}
535impl<T: Mul> Mul<T> for UnitInterval<T> {
536    type Output = T::Output;
537
538    #[inline]
539    fn mul(self, rhs: T) -> Self::Output {
540        self.0 * rhs
541    }
542}
543impl<T: Div> Div<T> for UnitInterval<T> {
544    type Output = T::Output;
545
546    #[inline]
547    fn div(self, rhs: T) -> Self::Output {
548        self.0 / rhs
549    }
550}
551
552impl<T: Add> Add for UnitInterval<T> {
553    type Output = T::Output;
554
555    #[inline]
556    fn add(self, rhs: Self) -> Self::Output {
557        self.0 + rhs.0
558    }
559}
560impl<T: Sub> Sub for UnitInterval<T> {
561    type Output = T::Output;
562
563    #[inline]
564    fn sub(self, rhs: Self) -> Self::Output {
565        self.0 - rhs.0
566    }
567}
568impl<T: Mul> Mul for UnitInterval<T> {
569    type Output = UnitInterval<T::Output>;
570
571    #[inline]
572    fn mul(self, rhs: UnitInterval<T>) -> Self::Output {
573        UnitInterval(self.0 * rhs.0)
574    }
575}
576impl<T: Div> Div for UnitInterval<T> {
577    type Output = T::Output;
578
579    #[inline]
580    fn div(self, rhs: Self) -> Self::Output {
581        self.0 / rhs.0
582    }
583}
584
585impl<T> AsRef<T> for UnitInterval<T> {
586    #[inline]
587    fn as_ref(&self) -> &T {
588        self.as_inner()
589    }
590}
591impl<T> Borrow<T> for UnitInterval<T> {
592    #[inline]
593    fn borrow(&self) -> &T {
594        self.as_inner()
595    }
596}
597
598#[cfg(test)]
599mod tests {
600    use super::*;
601
602    use core::cmp::Ordering;
603    use core::f64;
604
605    const EPSILON: f64 = 1e-4;
606    macro_rules! assert_float_eq {
607        ($a:expr, $b:expr) => {
608            let left: f64 = $a;
609            let right: f64 = $b;
610            match (left - right).abs().partial_cmp(&EPSILON) {
611                None | Some(Ordering::Greater) => assert_eq!(left, right),
612                _ => {}
613            }
614        };
615    }
616
617    #[test]
618    fn new() {
619        assert_eq!(UnitInterval::new(0.5).into_inner(), 0.5);
620        assert_eq!(UnitInterval::new(0.0).into_inner(), 0.0);
621        assert_eq!(UnitInterval::new(1.0).into_inner(), 1.0);
622    }
623
624    #[test]
625    fn new_negative_zero() {
626        let _ = UnitInterval::new(-0.0);
627    }
628
629    #[test]
630    #[should_panic(expected = "Value must be in the interval [0, 1]: -0.1 compares less than zero")]
631    fn new_panic_less_than_zero() {
632        let _ = UnitInterval::new(-0.1);
633    }
634
635    #[test]
636    #[should_panic(
637        expected = "Value must be in the interval [0, 1]: 1.1 compares greater than one"
638    )]
639    fn new_panic_greater_than_one() {
640        let _ = UnitInterval::new(1.1);
641    }
642
643    #[test]
644    fn new_checked() {
645        assert!(UnitInterval::new_checked(0.5).is_ok());
646        assert!(UnitInterval::new_checked(0.0).is_ok());
647        assert!(UnitInterval::new_checked(1.0).is_ok());
648
649        let err = UnitInterval::new_checked(-0.1).unwrap_err();
650        assert_eq!(err.kind(), BoundErrorKind::LessThanZero);
651        assert_float_eq!(err.value(), -0.1);
652
653        let err = UnitInterval::new_checked(1.1).unwrap_err();
654        assert_eq!(err.kind(), BoundErrorKind::GreaterThanOne);
655        assert_float_eq!(err.value(), 1.1);
656
657        let err = UnitInterval::new_checked(f64::NAN).unwrap_err();
658        assert_eq!(err.kind(), BoundErrorKind::Neither);
659        assert!(err.value().is_nan());
660    }
661
662    #[test]
663    fn new_clamped() {
664        assert_float_eq!(UnitInterval::new_clamped(0.5).into_inner(), 0.5);
665        assert_float_eq!(UnitInterval::new_clamped(-0.1).into_inner(), 0.0);
666        assert_float_eq!(UnitInterval::new_clamped(1.1).into_inner(), 1.0);
667    }
668
669    #[test]
670    fn new_fract() {
671        assert_float_eq!(UnitInterval::new_fract(1.5).into_inner(), 0.5);
672        assert_float_eq!(UnitInterval::new_fract(2.75).into_inner(), 0.75);
673        assert_float_eq!(UnitInterval::new_fract(-1.25).into_inner(), -0.25);
674    }
675
676    #[test]
677    fn as_inner() {
678        let unit = UnitInterval::new(0.5);
679        assert_float_eq!(*unit.as_inner(), 0.5);
680    }
681
682    #[test]
683    fn into_inner() {
684        let unit = UnitInterval::new(0.5);
685        assert_float_eq!(unit.into_inner(), 0.5);
686    }
687
688    #[test]
689    fn zero() {
690        assert_float_eq!(UnitInterval::<f64>::zero().into_inner(), 0.0);
691    }
692
693    #[test]
694    fn one() {
695        assert_float_eq!(UnitInterval::<f64>::one().into_inner(), 1.0);
696    }
697
698    #[test]
699    fn complement() {
700        assert_float_eq!(UnitInterval::new(0.3).complement().into_inner(), 0.7);
701        assert_float_eq!(UnitInterval::new(1.0).complement().into_inner(), 0.0);
702        assert_float_eq!(UnitInterval::new(0.0).complement().into_inner(), 1.0);
703    }
704
705    #[test]
706    fn checked_add() {
707        let a = UnitInterval::new(0.3);
708        let b = UnitInterval::new(0.4);
709        assert_float_eq!(a.checked_add(b).unwrap().into_inner(), 0.7f64);
710
711        let a = UnitInterval::new(0.7);
712        let b = UnitInterval::new(0.4);
713        assert!(a.checked_add(b).is_err());
714    }
715
716    #[test]
717    fn checked_sub() {
718        let a = UnitInterval::new(0.7);
719        let b = UnitInterval::new(0.4);
720        assert_float_eq!(a.checked_sub(b).unwrap().into_inner(), 0.3);
721
722        let a = UnitInterval::new(0.3);
723        let b = UnitInterval::new(0.4);
724        assert!(a.checked_sub(b).is_err());
725    }
726
727    #[test]
728    fn checked_mul() {
729        let a = UnitInterval::new(0.5);
730        let b = UnitInterval::new(0.6);
731        assert_float_eq!(a.checked_mul(b).unwrap().into_inner(), 0.3);
732    }
733
734    #[test]
735    fn checked_div() {
736        let a = UnitInterval::new(0.5);
737        let b = UnitInterval::new(0.25);
738        assert!(a.checked_div(b).is_err());
739
740        let a = UnitInterval::new(0.25);
741        let b = UnitInterval::new(0.5);
742        assert_float_eq!(a.checked_div(b).unwrap().into_inner(), 0.5);
743    }
744
745    #[test]
746    fn clamped_add() {
747        let a = UnitInterval::new(0.7);
748        let b = UnitInterval::new(0.4);
749        assert_float_eq!(a.clamped_add(b).into_inner(), 1.0);
750    }
751
752    #[test]
753    fn clamped_sub() {
754        let a = UnitInterval::new(0.3);
755        let b = UnitInterval::new(0.4);
756        assert_float_eq!(a.clamped_sub(b).into_inner(), 0.0);
757    }
758
759    #[test]
760    fn clamped_mul() {
761        let a = UnitInterval::new(0.5);
762        let b = UnitInterval::new(0.6);
763        assert_float_eq!(a.clamped_mul(b).into_inner(), 0.3);
764    }
765
766    #[test]
767    fn clamped_div() {
768        let a = UnitInterval::new(0.5);
769        let b = UnitInterval::new(0.25);
770        assert_float_eq!(a.clamped_div(b).into_inner(), 1.0);
771    }
772
773    #[test]
774    fn add() {
775        let a = UnitInterval::new(0.3);
776        let b = UnitInterval::new(0.4);
777        assert_float_eq!(a + b, 0.7);
778    }
779
780    #[test]
781    fn sub() {
782        let a = UnitInterval::new(0.7);
783        let b = UnitInterval::new(0.4);
784        assert_float_eq!(a - b, 0.3);
785    }
786
787    #[test]
788    fn mul() {
789        let a = UnitInterval::new(0.5);
790        let b = UnitInterval::new(0.6);
791        assert_float_eq!((a * b).into_inner(), 0.3);
792    }
793
794    #[test]
795    fn div() {
796        let a = UnitInterval::new(0.5);
797        let b = UnitInterval::new(0.25);
798        assert_float_eq!(a / b, 2.0);
799    }
800}