Skip to main content

unit_intervals/
signed_unit_interval.rs

1use core::{
2    cmp::Ordering,
3    error::Error,
4    fmt,
5    ops::{Add, Deref, Div, Mul, Neg, Rem, Sub},
6};
7
8use crate::{UnitInterval, UnitIntervalError, UnitIntervalFloat};
9
10/// A floating-point value constrained to the closed signed unit interval `[-1, 1]`.
11///
12/// `SignedUnitInterval` is useful for normalized signed values such as direction,
13/// balance, centered offsets, joystick axes, and correlation-like coefficients.
14#[cfg_attr(
15    feature = "rkyv",
16    derive(::rkyv::Archive, ::rkyv::Serialize),
17    rkyv(crate = ::rkyv)
18)]
19#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
20#[repr(transparent)]
21pub struct SignedUnitInterval<T = f32>(T);
22
23/// Error returned when converting an out-of-range value into a [`SignedUnitInterval`].
24#[derive(Debug, Copy, Clone, Eq, PartialEq)]
25pub struct SignedUnitIntervalError;
26
27impl fmt::Display for SignedUnitIntervalError {
28    #[inline]
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        f.write_str("value is outside the signed unit interval")
31    }
32}
33
34impl Error for SignedUnitIntervalError {}
35
36#[cfg(feature = "rkyv")]
37#[cfg_attr(docsrs, doc(cfg(feature = "rkyv")))]
38mod rkyv {
39    use super::*;
40    use ::rkyv::{
41        Archive, Deserialize,
42        rancor::{Fallible, Source, fail},
43    };
44
45    impl<T, D> Deserialize<SignedUnitInterval<T>, D> for ArchivedSignedUnitInterval<T>
46    where
47        T: Archive + UnitIntervalFloat,
48        T::Archived: Deserialize<T, D>,
49        D: Fallible + ?Sized,
50        D::Error: Source,
51    {
52        #[inline]
53        fn deserialize(&self, deserializer: &mut D) -> Result<SignedUnitInterval<T>, D::Error> {
54            let value = self.0.deserialize(deserializer)?;
55
56            if let Some(value) = SignedUnitInterval::new(value) {
57                Ok(value)
58            } else {
59                fail!(SignedUnitIntervalError);
60            }
61        }
62    }
63}
64
65#[cfg(feature = "serde")]
66#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
67mod serde {
68    use super::*;
69    use ::serde::{Deserialize, Deserializer, Serialize, Serializer, de};
70
71    impl<T: Serialize> Serialize for SignedUnitInterval<T> {
72        #[inline]
73        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
74            self.0.serialize(serializer)
75        }
76    }
77
78    impl<'de, T> Deserialize<'de> for SignedUnitInterval<T>
79    where
80        T: UnitIntervalFloat + Deserialize<'de>,
81    {
82        #[inline]
83        fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
84            // Keep deserialization on the same invariant-preserving path as
85            // construction from a raw float. Serialization is intentionally
86            // transparent, so the data format only stores the inner value and
87            // cannot encode whether that value came from a previously checked
88            // `SignedUnitInterval`. Treating decoded input as trusted wrapper
89            // state would let out-of-range values and `NaN` bypass the type's
90            // public contract. Decoding the backing value first and then
91            // routing it through `new` gives every serde format the same
92            // behavior as `TryFrom<T>`: valid values reconstruct the wrapper,
93            // and invalid values become ordinary deserialization errors.
94            let value = T::deserialize(deserializer)?;
95
96            Self::new(value).ok_or_else(|| de::Error::custom(SignedUnitIntervalError))
97        }
98    }
99}
100
101#[cfg(feature = "bytemuck")]
102#[cfg_attr(docsrs, doc(cfg(feature = "bytemuck")))]
103mod bytemuck {
104    use super::*;
105
106    unsafe impl<T> ::bytemuck::Zeroable for SignedUnitInterval<T> where
107        T: UnitIntervalFloat + ::bytemuck::Zeroable
108    {
109    }
110
111    unsafe impl<T> ::bytemuck::NoUninit for SignedUnitInterval<T> where
112        T: UnitIntervalFloat + ::bytemuck::NoUninit
113    {
114    }
115
116    unsafe impl<T> ::bytemuck::CheckedBitPattern for SignedUnitInterval<T>
117    where
118        T: UnitIntervalFloat + ::bytemuck::AnyBitPattern,
119    {
120        type Bits = T;
121
122        #[inline]
123        fn is_valid_bit_pattern(bits: &Self::Bits) -> bool {
124            SignedUnitInterval::contains(*bits)
125        }
126    }
127}
128
129#[cfg(feature = "arbitrary")]
130#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
131mod arbitrary {
132    use super::*;
133    use ::arbitrary::{Arbitrary, Result, Unstructured};
134
135    macro_rules! impl_arbitrary_signed_unit_interval {
136        ($float:ty, $unsigned:ty) => {
137            impl<'a> Arbitrary<'a> for SignedUnitInterval<$float> {
138                #[inline]
139                fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
140                    let raw = <$unsigned as Arbitrary<'a>>::arbitrary(u)?;
141                    let unit = raw as $float / <$unsigned>::MAX as $float;
142                    let value = unit * 2.0 - 1.0;
143
144                    Ok(Self::from_inner(value))
145                }
146
147                #[inline]
148                fn size_hint(depth: usize) -> (usize, Option<usize>) {
149                    <$unsigned as Arbitrary<'a>>::size_hint(depth)
150                }
151            }
152        };
153    }
154
155    impl_arbitrary_signed_unit_interval!(f32, u32);
156    impl_arbitrary_signed_unit_interval!(f64, u64);
157}
158
159#[cfg(feature = "num-traits")]
160#[cfg_attr(docsrs, doc(cfg(feature = "num-traits")))]
161mod num_traits {
162    use super::*;
163    use ::num_traits::{
164        AsPrimitive, Bounded, ConstOne, FromPrimitive, NumCast, One, Pow, ToBytes, ToPrimitive,
165        ops::{
166            checked::{CheckedMul, CheckedNeg},
167            saturating::SaturatingMul,
168        },
169    };
170
171    macro_rules! impl_num_traits_signed_unit_interval {
172        ($float:ty) => {
173            impl ToPrimitive for SignedUnitInterval<$float> {
174                #[inline]
175                fn to_isize(&self) -> Option<isize> {
176                    self.0.to_isize()
177                }
178
179                #[inline]
180                fn to_i8(&self) -> Option<i8> {
181                    self.0.to_i8()
182                }
183
184                #[inline]
185                fn to_i16(&self) -> Option<i16> {
186                    self.0.to_i16()
187                }
188
189                #[inline]
190                fn to_i32(&self) -> Option<i32> {
191                    self.0.to_i32()
192                }
193
194                #[inline]
195                fn to_i64(&self) -> Option<i64> {
196                    self.0.to_i64()
197                }
198
199                #[inline]
200                fn to_i128(&self) -> Option<i128> {
201                    self.0.to_i128()
202                }
203
204                #[inline]
205                fn to_usize(&self) -> Option<usize> {
206                    self.0.to_usize()
207                }
208
209                #[inline]
210                fn to_u8(&self) -> Option<u8> {
211                    self.0.to_u8()
212                }
213
214                #[inline]
215                fn to_u16(&self) -> Option<u16> {
216                    self.0.to_u16()
217                }
218
219                #[inline]
220                fn to_u32(&self) -> Option<u32> {
221                    self.0.to_u32()
222                }
223
224                #[inline]
225                fn to_u64(&self) -> Option<u64> {
226                    self.0.to_u64()
227                }
228
229                #[inline]
230                fn to_u128(&self) -> Option<u128> {
231                    self.0.to_u128()
232                }
233
234                #[inline]
235                fn to_f32(&self) -> Option<f32> {
236                    self.0.to_f32()
237                }
238
239                #[inline]
240                fn to_f64(&self) -> Option<f64> {
241                    self.0.to_f64()
242                }
243            }
244
245            impl FromPrimitive for SignedUnitInterval<$float> {
246                #[inline]
247                fn from_i64(n: i64) -> Option<Self> {
248                    <$float as FromPrimitive>::from_i64(n).and_then(Self::new)
249                }
250
251                #[inline]
252                fn from_u64(n: u64) -> Option<Self> {
253                    <$float as FromPrimitive>::from_u64(n).and_then(Self::new)
254                }
255
256                #[inline]
257                fn from_f32(n: f32) -> Option<Self> {
258                    <$float as FromPrimitive>::from_f32(n).and_then(Self::new)
259                }
260
261                #[inline]
262                fn from_f64(n: f64) -> Option<Self> {
263                    <$float as FromPrimitive>::from_f64(n).and_then(Self::new)
264                }
265            }
266
267            impl NumCast for SignedUnitInterval<$float> {
268                #[inline]
269                fn from<T: ToPrimitive>(n: T) -> Option<Self> {
270                    <$float as NumCast>::from(n).and_then(Self::new)
271                }
272            }
273
274            impl One for SignedUnitInterval<$float> {
275                #[inline]
276                fn one() -> Self {
277                    Self::ONE
278                }
279
280                #[inline]
281                fn is_one(&self) -> bool {
282                    SignedUnitInterval::is_one(*self)
283                }
284            }
285
286            impl ConstOne for SignedUnitInterval<$float> {
287                const ONE: Self = Self::ONE;
288            }
289
290            impl Bounded for SignedUnitInterval<$float> {
291                #[inline]
292                fn min_value() -> Self {
293                    Self::NEG_ONE
294                }
295
296                #[inline]
297                fn max_value() -> Self {
298                    Self::ONE
299                }
300            }
301
302            impl ToBytes for SignedUnitInterval<$float> {
303                type Bytes = <$float as ToBytes>::Bytes;
304
305                #[inline]
306                fn to_be_bytes(&self) -> Self::Bytes {
307                    self.0.to_be_bytes()
308                }
309
310                #[inline]
311                fn to_le_bytes(&self) -> Self::Bytes {
312                    self.0.to_le_bytes()
313                }
314
315                #[inline]
316                fn to_ne_bytes(&self) -> Self::Bytes {
317                    self.0.to_ne_bytes()
318                }
319            }
320
321            impl CheckedMul for SignedUnitInterval<$float> {
322                #[inline]
323                fn checked_mul(&self, v: &Self) -> Option<Self> {
324                    Some(*self * *v)
325                }
326            }
327
328            impl CheckedNeg for SignedUnitInterval<$float> {
329                #[inline]
330                fn checked_neg(&self) -> Option<Self> {
331                    Some(-*self)
332                }
333            }
334
335            impl SaturatingMul for SignedUnitInterval<$float> {
336                #[inline]
337                fn saturating_mul(&self, v: &Self) -> Self {
338                    *self * *v
339                }
340            }
341        };
342    }
343
344    macro_rules! impl_pow_signed_unit_interval {
345        ($rhs:ty) => {
346            impl<T: UnitIntervalFloat> Pow<$rhs> for SignedUnitInterval<T> {
347                type Output = Self;
348
349                #[inline]
350                fn pow(self, rhs: $rhs) -> Self::Output {
351                    pow_signed_unit_interval(self, rhs as usize)
352                }
353            }
354
355            impl<T: UnitIntervalFloat> Pow<&$rhs> for SignedUnitInterval<T> {
356                type Output = Self;
357
358                #[inline]
359                fn pow(self, rhs: &$rhs) -> Self::Output {
360                    pow_signed_unit_interval(self, *rhs as usize)
361                }
362            }
363
364            impl<T: UnitIntervalFloat> Pow<$rhs> for &SignedUnitInterval<T> {
365                type Output = SignedUnitInterval<T>;
366
367                #[inline]
368                fn pow(self, rhs: $rhs) -> Self::Output {
369                    pow_signed_unit_interval(*self, rhs as usize)
370                }
371            }
372
373            impl<T: UnitIntervalFloat> Pow<&$rhs> for &SignedUnitInterval<T> {
374                type Output = SignedUnitInterval<T>;
375
376                #[inline]
377                fn pow(self, rhs: &$rhs) -> Self::Output {
378                    pow_signed_unit_interval(*self, *rhs as usize)
379                }
380            }
381        };
382    }
383
384    macro_rules! impl_as_primitive_signed_unit_interval {
385        ($float:ty => $($target:ty),+ $(,)?) => {
386            $(
387                impl AsPrimitive<$target> for SignedUnitInterval<$float> {
388                    #[inline]
389                    fn as_(self) -> $target {
390                        self.0 as $target
391                    }
392                }
393            )+
394        };
395    }
396
397    impl_num_traits_signed_unit_interval!(f32);
398    impl_num_traits_signed_unit_interval!(f64);
399    impl_pow_signed_unit_interval!(u8);
400    impl_pow_signed_unit_interval!(u16);
401    impl_pow_signed_unit_interval!(u32);
402    impl_pow_signed_unit_interval!(usize);
403
404    impl_as_primitive_signed_unit_interval!(f32 => f32, f64);
405    impl_as_primitive_signed_unit_interval!(f64 => f32, f64);
406
407    impl AsPrimitive<SignedUnitInterval<f32>> for SignedUnitInterval<f32> {
408        #[inline]
409        fn as_(self) -> SignedUnitInterval<f32> {
410            self
411        }
412    }
413
414    impl AsPrimitive<SignedUnitInterval<f64>> for SignedUnitInterval<f32> {
415        #[inline]
416        fn as_(self) -> SignedUnitInterval<f64> {
417            SignedUnitInterval::from_inner(self.0 as f64)
418        }
419    }
420
421    impl AsPrimitive<SignedUnitInterval<f32>> for SignedUnitInterval<f64> {
422        #[inline]
423        fn as_(self) -> SignedUnitInterval<f32> {
424            SignedUnitInterval::from_inner(self.0 as f32)
425        }
426    }
427
428    impl AsPrimitive<SignedUnitInterval<f64>> for SignedUnitInterval<f64> {
429        #[inline]
430        fn as_(self) -> SignedUnitInterval<f64> {
431            self
432        }
433    }
434
435    #[inline]
436    fn pow_signed_unit_interval<T: UnitIntervalFloat>(
437        base: SignedUnitInterval<T>,
438        exp: usize,
439    ) -> SignedUnitInterval<T> {
440        let mut result = SignedUnitInterval::ONE;
441        let mut factor = base;
442        let mut exp = exp;
443
444        while exp > 0 {
445            if exp & 1 == 1 {
446                result = result * factor;
447            }
448
449            exp >>= 1;
450
451            if exp > 0 {
452                factor = factor * factor;
453            }
454        }
455
456        result
457    }
458}
459
460impl<T: UnitIntervalFloat> SignedUnitInterval<T> {
461    /// The lower bound of the signed unit interval.
462    pub const NEG_ONE: Self = Self(T::NEG_ONE);
463
464    /// The midpoint of the signed unit interval.
465    pub const ZERO: Self = Self(T::ZERO);
466
467    /// The upper bound of the signed unit interval.
468    pub const ONE: Self = Self(T::ONE);
469
470    /// The positive midpoint of the signed unit interval.
471    pub const HALF: Self = Self(T::HALF);
472
473    /// Creates a value if `v` is inside `[-1, 1]`.
474    ///
475    /// Returns `None` for values outside the interval and for `NaN`.
476    #[inline]
477    pub fn new(v: T) -> Option<Self> {
478        if Self::contains(v) {
479            Some(Self::from_inner(v))
480        } else {
481            None
482        }
483    }
484
485    /// Creates a value without checking that `v` is inside `[-1, 1]`.
486    ///
487    /// # Safety
488    ///
489    /// The caller must guarantee that `v` is greater than or equal to negative
490    /// one, less than or equal to one, and not `NaN`.
491    #[cfg(feature = "unsafe")]
492    #[inline]
493    pub const unsafe fn new_unchecked(v: T) -> Self {
494        Self(v)
495    }
496
497    /// Returns whether `v` is inside `[-1, 1]`.
498    ///
499    /// `NaN` is not contained in the interval.
500    #[inline]
501    pub fn contains(v: T) -> bool {
502        v >= T::NEG_ONE && v <= T::ONE
503    }
504
505    /// Creates a value by clamping `v` into `[-1, 1]`.
506    ///
507    /// `NaN` is treated as zero.
508    #[inline]
509    pub fn saturating(v: T) -> Self {
510        Self::from_inner(v.clamp_signed_unit())
511    }
512
513    #[inline]
514    pub(crate) fn from_inner(v: T) -> Self {
515        Self::assert_contains(v);
516        Self(v)
517    }
518
519    #[cfg(any(test, feature = "assertions"))]
520    #[inline]
521    fn assert_contains(v: T) {
522        assert!(
523            Self::contains(v),
524            "SignedUnitInterval invariant violated: value is outside [-1, 1]"
525        );
526    }
527
528    #[cfg(not(any(test, feature = "assertions")))]
529    #[cfg_attr(docsrs, doc(cfg(feature = "assertions")))]
530    #[inline]
531    fn assert_contains(_v: T) {}
532
533    /// Returns the inner floating-point value.
534    #[inline]
535    pub const fn get(self) -> T {
536        self.0
537    }
538
539    /// Consumes the wrapper and returns the inner floating-point value.
540    #[inline]
541    pub const fn into_inner(self) -> T {
542        self.0
543    }
544
545    /// Returns whether this value is exactly zero.
546    #[inline]
547    pub fn is_zero(self) -> bool {
548        self.0 == T::ZERO
549    }
550
551    /// Returns whether this value is exactly one.
552    #[inline]
553    pub fn is_one(self) -> bool {
554        self.0 == T::ONE
555    }
556
557    /// Returns whether this value is exactly negative one.
558    #[inline]
559    pub fn is_neg_one(self) -> bool {
560        self.0 == T::NEG_ONE
561    }
562
563    /// Returns `1 - self`.
564    #[inline]
565    pub fn complement(self) -> T {
566        T::ONE - self.0
567    }
568
569    /// Returns the smaller of two signed unit interval values.
570    #[inline]
571    pub fn min<R: Into<Self>>(self, rhs: R) -> Self {
572        let rhs = rhs.into();
573
574        if self.0 <= rhs.0 { self } else { rhs }
575    }
576
577    /// Returns the larger of two signed unit interval values.
578    #[inline]
579    pub fn max<R: Into<Self>>(self, rhs: R) -> Self {
580        let rhs = rhs.into();
581
582        if self.0 >= rhs.0 { self } else { rhs }
583    }
584
585    /// Returns the midpoint between two signed unit interval values.
586    #[inline]
587    pub fn midpoint<R: Into<Self>>(self, rhs: R) -> Self {
588        let rhs = rhs.into();
589
590        Self::from_inner((self.0 + rhs.0) * T::HALF)
591    }
592
593    /// Returns the absolute distance between two signed unit interval values.
594    #[inline]
595    pub fn distance_to<R: Into<Self>>(self, rhs: R) -> T {
596        let rhs = rhs.into();
597
598        if self.0 >= rhs.0 {
599            self.0 - rhs.0
600        } else {
601            rhs.0 - self.0
602        }
603    }
604
605    /// Adds two values, returning `None` if the result is outside `[-1, 1]`.
606    #[inline]
607    pub fn checked_add<R: Into<Self>>(self, rhs: R) -> Option<Self> {
608        Self::new(self.0 + rhs.into().0)
609    }
610
611    /// Adds two values without checking that the result is inside `[-1, 1]`.
612    ///
613    /// # Safety
614    ///
615    /// The caller must guarantee that `self + rhs` is inside `[-1, 1]` and not
616    /// `NaN`.
617    #[cfg(feature = "unsafe")]
618    #[cfg_attr(docsrs, doc(cfg(feature = "unsafe")))]
619    #[inline]
620    pub unsafe fn add_unchecked<R: Into<Self>>(self, rhs: R) -> Self {
621        // SAFETY: Guaranteed by the caller.
622        unsafe { Self::new_unchecked(self.0 + rhs.into().0) }
623    }
624
625    /// Adds two values and clamps the result into `[-1, 1]`.
626    #[inline]
627    pub fn saturating_add<R: Into<Self>>(self, rhs: R) -> Self {
628        Self::saturating(self.0 + rhs.into().0)
629    }
630
631    /// Subtracts `rhs`, returning `None` if the result is outside `[-1, 1]`.
632    #[inline]
633    pub fn checked_sub<R: Into<Self>>(self, rhs: R) -> Option<Self> {
634        Self::new(self.0 - rhs.into().0)
635    }
636
637    /// Subtracts `rhs` without checking that the result is inside `[-1, 1]`.
638    ///
639    /// # Safety
640    ///
641    /// The caller must guarantee that `self - rhs` is inside `[-1, 1]` and not
642    /// `NaN`.
643    #[cfg(feature = "unsafe")]
644    #[cfg_attr(docsrs, doc(cfg(feature = "unsafe")))]
645    #[inline]
646    pub unsafe fn sub_unchecked<R: Into<Self>>(self, rhs: R) -> Self {
647        // SAFETY: Guaranteed by the caller.
648        unsafe { Self::new_unchecked(self.0 - rhs.into().0) }
649    }
650
651    /// Subtracts `rhs` and clamps the result into `[-1, 1]`.
652    #[inline]
653    pub fn saturating_sub<R: Into<Self>>(self, rhs: R) -> Self {
654        Self::saturating(self.0 - rhs.into().0)
655    }
656
657    /// Divides by `rhs`, returning `None` if the result is outside `[-1, 1]`.
658    #[inline]
659    pub fn checked_div<R: Into<Self>>(self, rhs: R) -> Option<Self> {
660        Self::new(self.0 / rhs.into().0)
661    }
662
663    /// Divides by `rhs` without checking that the result is inside `[-1, 1]`.
664    ///
665    /// # Safety
666    ///
667    /// The caller must guarantee that `self / rhs` is inside `[-1, 1]` and not
668    /// `NaN`.
669    #[cfg(feature = "unsafe")]
670    #[cfg_attr(docsrs, doc(cfg(feature = "unsafe")))]
671    #[inline]
672    pub unsafe fn div_unchecked<R: Into<Self>>(self, rhs: R) -> Self {
673        // SAFETY: Guaranteed by the caller.
674        unsafe { Self::new_unchecked(self.0 / rhs.into().0) }
675    }
676
677    /// Divides by `rhs` and clamps the result into `[-1, 1]`.
678    #[inline]
679    pub fn saturating_div<R: Into<Self>>(self, rhs: R) -> Self {
680        Self::saturating(self.0 / rhs.into().0)
681    }
682
683    /// Multiplies by an arbitrary float, returning `None` if the result is outside `[-1, 1]`.
684    #[inline]
685    pub fn checked_scale(self, factor: T) -> Option<Self> {
686        Self::new(self.0 * factor)
687    }
688
689    /// Multiplies by an arbitrary float without checking that the result is
690    /// inside `[-1, 1]`.
691    ///
692    /// # Safety
693    ///
694    /// The caller must guarantee that `self * factor` is inside `[-1, 1]` and
695    /// not `NaN`.
696    #[cfg(feature = "unsafe")]
697    #[cfg_attr(docsrs, doc(cfg(feature = "unsafe")))]
698    #[inline]
699    pub unsafe fn scale_unchecked(self, factor: T) -> Self {
700        // SAFETY: Guaranteed by the caller.
701        unsafe { Self::new_unchecked(self.0 * factor) }
702    }
703
704    /// Multiplies by an arbitrary float and clamps the result into `[-1, 1]`.
705    #[inline]
706    pub fn saturating_scale(self, factor: T) -> Self {
707        Self::saturating(self.0 * factor)
708    }
709
710    /// Linearly interpolates between `start` and `end`.
711    #[inline]
712    pub fn lerp(self, start: T, end: T) -> T {
713        start + (end - start) * self.0
714    }
715}
716
717/// Returns [`SignedUnitInterval::ZERO`].
718impl<T: UnitIntervalFloat> Default for SignedUnitInterval<T> {
719    #[inline]
720    fn default() -> Self {
721        Self::ZERO
722    }
723}
724
725/// Dereferences to the inner floating-point value.
726impl<T> Deref for SignedUnitInterval<T> {
727    type Target = T;
728
729    #[inline]
730    fn deref(&self) -> &Self::Target {
731        &self.0
732    }
733}
734
735/// Borrows the inner floating-point value.
736impl<T> AsRef<T> for SignedUnitInterval<T> {
737    #[inline]
738    fn as_ref(&self) -> &T {
739        &self.0
740    }
741}
742
743impl<T: UnitIntervalFloat> From<UnitInterval<T>> for SignedUnitInterval<T> {
744    #[inline]
745    fn from(u: UnitInterval<T>) -> Self {
746        Self::from_inner(u.get())
747    }
748}
749
750impl<T: UnitIntervalFloat> TryFrom<SignedUnitInterval<T>> for UnitInterval<T> {
751    type Error = UnitIntervalError;
752
753    #[inline]
754    fn try_from(value: SignedUnitInterval<T>) -> Result<Self, Self::Error> {
755        Self::new(value.0).ok_or(UnitIntervalError)
756    }
757}
758
759macro_rules! impl_signed_unit_interval_float {
760    ($float:ty) => {
761        impl From<SignedUnitInterval<$float>> for $float {
762            #[inline]
763            fn from(u: SignedUnitInterval<$float>) -> Self {
764                u.0
765            }
766        }
767
768        impl TryFrom<$float> for SignedUnitInterval<$float> {
769            type Error = SignedUnitIntervalError;
770
771            #[inline]
772            fn try_from(value: $float) -> Result<Self, Self::Error> {
773                Self::new(value).ok_or(SignedUnitIntervalError)
774            }
775        }
776
777        impl PartialEq<$float> for SignedUnitInterval<$float> {
778            #[inline]
779            fn eq(&self, other: &$float) -> bool {
780                self.0 == *other
781            }
782        }
783
784        impl PartialEq<SignedUnitInterval<$float>> for $float {
785            #[inline]
786            fn eq(&self, other: &SignedUnitInterval<$float>) -> bool {
787                *self == other.0
788            }
789        }
790
791        impl PartialOrd<$float> for SignedUnitInterval<$float> {
792            #[inline]
793            fn partial_cmp(&self, other: &$float) -> Option<Ordering> {
794                self.0.partial_cmp(other)
795            }
796        }
797
798        impl PartialOrd<SignedUnitInterval<$float>> for $float {
799            #[inline]
800            fn partial_cmp(&self, other: &SignedUnitInterval<$float>) -> Option<Ordering> {
801                self.partial_cmp(&other.0)
802            }
803        }
804
805        impl Add for SignedUnitInterval<$float> {
806            type Output = $float;
807
808            #[inline]
809            fn add(self, rhs: Self) -> Self::Output {
810                self.0 + rhs.0
811            }
812        }
813
814        impl Add<UnitInterval<$float>> for SignedUnitInterval<$float> {
815            type Output = $float;
816
817            #[inline]
818            fn add(self, rhs: UnitInterval<$float>) -> Self::Output {
819                self.0 + rhs.get()
820            }
821        }
822
823        impl Add<SignedUnitInterval<$float>> for UnitInterval<$float> {
824            type Output = $float;
825
826            #[inline]
827            fn add(self, rhs: SignedUnitInterval<$float>) -> Self::Output {
828                self.get() + rhs.0
829            }
830        }
831
832        impl Add<$float> for SignedUnitInterval<$float> {
833            type Output = $float;
834
835            #[inline]
836            fn add(self, rhs: $float) -> Self::Output {
837                self.0 + rhs
838            }
839        }
840
841        impl Add<SignedUnitInterval<$float>> for $float {
842            type Output = $float;
843
844            #[inline]
845            fn add(self, rhs: SignedUnitInterval<$float>) -> Self::Output {
846                self + rhs.0
847            }
848        }
849
850        impl Sub for SignedUnitInterval<$float> {
851            type Output = $float;
852
853            #[inline]
854            fn sub(self, rhs: Self) -> Self::Output {
855                self.0 - rhs.0
856            }
857        }
858
859        impl Sub<UnitInterval<$float>> for SignedUnitInterval<$float> {
860            type Output = $float;
861
862            #[inline]
863            fn sub(self, rhs: UnitInterval<$float>) -> Self::Output {
864                self.0 - rhs.get()
865            }
866        }
867
868        impl Sub<SignedUnitInterval<$float>> for UnitInterval<$float> {
869            type Output = $float;
870
871            #[inline]
872            fn sub(self, rhs: SignedUnitInterval<$float>) -> Self::Output {
873                self.get() - rhs.0
874            }
875        }
876
877        impl Sub<$float> for SignedUnitInterval<$float> {
878            type Output = $float;
879
880            #[inline]
881            fn sub(self, rhs: $float) -> Self::Output {
882                self.0 - rhs
883            }
884        }
885
886        impl Sub<SignedUnitInterval<$float>> for $float {
887            type Output = $float;
888
889            #[inline]
890            fn sub(self, rhs: SignedUnitInterval<$float>) -> Self::Output {
891                self - rhs.0
892            }
893        }
894
895        impl Mul<$float> for SignedUnitInterval<$float> {
896            type Output = $float;
897
898            #[inline]
899            fn mul(self, rhs: $float) -> Self::Output {
900                self.0 * rhs
901            }
902        }
903
904        impl Mul<SignedUnitInterval<$float>> for $float {
905            type Output = $float;
906
907            #[inline]
908            fn mul(self, rhs: SignedUnitInterval<$float>) -> Self::Output {
909                self * rhs.0
910            }
911        }
912
913        impl Div for SignedUnitInterval<$float> {
914            type Output = $float;
915
916            #[inline]
917            fn div(self, rhs: Self) -> Self::Output {
918                self.0 / rhs.0
919            }
920        }
921
922        impl Div<UnitInterval<$float>> for SignedUnitInterval<$float> {
923            type Output = $float;
924
925            #[inline]
926            fn div(self, rhs: UnitInterval<$float>) -> Self::Output {
927                self.0 / rhs.get()
928            }
929        }
930
931        impl Div<SignedUnitInterval<$float>> for UnitInterval<$float> {
932            type Output = $float;
933
934            #[inline]
935            fn div(self, rhs: SignedUnitInterval<$float>) -> Self::Output {
936                self.get() / rhs.0
937            }
938        }
939
940        impl Div<$float> for SignedUnitInterval<$float> {
941            type Output = $float;
942
943            #[inline]
944            fn div(self, rhs: $float) -> Self::Output {
945                self.0 / rhs
946            }
947        }
948
949        impl Div<SignedUnitInterval<$float>> for $float {
950            type Output = $float;
951
952            #[inline]
953            fn div(self, rhs: SignedUnitInterval<$float>) -> Self::Output {
954                self / rhs.0
955            }
956        }
957
958        impl Rem for SignedUnitInterval<$float> {
959            type Output = $float;
960
961            #[inline]
962            fn rem(self, rhs: Self) -> Self::Output {
963                self.0 % rhs.0
964            }
965        }
966
967        impl Rem<UnitInterval<$float>> for SignedUnitInterval<$float> {
968            type Output = $float;
969
970            #[inline]
971            fn rem(self, rhs: UnitInterval<$float>) -> Self::Output {
972                self.0 % rhs.get()
973            }
974        }
975
976        impl Rem<SignedUnitInterval<$float>> for UnitInterval<$float> {
977            type Output = $float;
978
979            #[inline]
980            fn rem(self, rhs: SignedUnitInterval<$float>) -> Self::Output {
981                self.get() % rhs.0
982            }
983        }
984
985        impl Rem<$float> for SignedUnitInterval<$float> {
986            type Output = $float;
987
988            #[inline]
989            fn rem(self, rhs: $float) -> Self::Output {
990                self.0 % rhs
991            }
992        }
993
994        impl Rem<SignedUnitInterval<$float>> for $float {
995            type Output = $float;
996
997            #[inline]
998            fn rem(self, rhs: SignedUnitInterval<$float>) -> Self::Output {
999                self % rhs.0
1000            }
1001        }
1002
1003        impl Neg for SignedUnitInterval<$float> {
1004            type Output = Self;
1005
1006            #[inline]
1007            fn neg(self) -> Self::Output {
1008                Self::from_inner(-self.0)
1009            }
1010        }
1011
1012        impl SignedUnitInterval<$float> {
1013            /// Returns the absolute value.
1014            #[inline]
1015            pub fn abs(self) -> UnitInterval<$float> {
1016                UnitInterval::new(self.0.abs()).expect("absolute signed unit value is in [0, 1]")
1017            }
1018
1019            /// Returns a number representing the sign of this value.
1020            #[inline]
1021            pub fn signum(self) -> Self {
1022                Self::from_inner(self.0.signum())
1023            }
1024
1025            /// Returns this value with the sign of `sign`.
1026            #[inline]
1027            pub fn copysign(self, sign: $float) -> Self {
1028                Self::from_inner(self.0.copysign(sign))
1029            }
1030
1031            /// Returns `true` if this value is positive zero or positive.
1032            #[inline]
1033            pub fn is_sign_positive(self) -> bool {
1034                self.0.is_sign_positive()
1035            }
1036
1037            /// Returns `true` if this value is negative zero or negative.
1038            #[inline]
1039            pub fn is_sign_negative(self) -> bool {
1040                self.0.is_sign_negative()
1041            }
1042
1043            /// Returns `true`; signed unit interval values are always finite.
1044            #[inline]
1045            pub fn is_finite(self) -> bool {
1046                self.0.is_finite()
1047            }
1048
1049            /// Returns `false`; signed unit interval values cannot be infinite.
1050            #[inline]
1051            pub fn is_infinite(self) -> bool {
1052                self.0.is_infinite()
1053            }
1054
1055            /// Returns `false`; signed unit interval values cannot be `NaN`.
1056            #[inline]
1057            pub fn is_nan(self) -> bool {
1058                self.0.is_nan()
1059            }
1060
1061            /// Takes the reciprocal, `1 / self`.
1062            #[inline]
1063            pub fn recip(self) -> $float {
1064                self.0.recip()
1065            }
1066        }
1067
1068        #[cfg(any(test, feature = "std"))]
1069        impl SignedUnitInterval<$float> {
1070            /// Returns the largest integer less than or equal to this value.
1071            #[inline]
1072            pub fn floor(self) -> Self {
1073                Self::from_inner(self.0.floor())
1074            }
1075
1076            /// Returns the smallest integer greater than or equal to this value.
1077            #[inline]
1078            pub fn ceil(self) -> Self {
1079                Self::from_inner(self.0.ceil())
1080            }
1081
1082            /// Returns the nearest integer to this value, rounding halfway cases away from zero.
1083            #[inline]
1084            pub fn round(self) -> Self {
1085                Self::from_inner(self.0.round())
1086            }
1087
1088            /// Returns the integer part of this value.
1089            #[inline]
1090            pub fn trunc(self) -> Self {
1091                Self::from_inner(self.0.trunc())
1092            }
1093
1094            /// Returns the fractional part of this value.
1095            #[inline]
1096            pub fn fract(self) -> Self {
1097                Self::from_inner(self.0.fract())
1098            }
1099
1100            /// Raises this value to an integer power.
1101            #[inline]
1102            pub fn powi(self, n: i32) -> $float {
1103                self.0.powi(n)
1104            }
1105
1106            /// Raises this value to a floating-point power.
1107            #[inline]
1108            pub fn powf(self, n: $float) -> $float {
1109                self.0.powf(n)
1110            }
1111
1112            /// Returns the square root.
1113            #[inline]
1114            pub fn sqrt(self) -> $float {
1115                self.0.sqrt()
1116            }
1117
1118            /// Returns the cube root.
1119            #[inline]
1120            pub fn cbrt(self) -> Self {
1121                Self::from_inner(self.0.cbrt())
1122            }
1123
1124            /// Computes `self * a + b` with one rounding error.
1125            #[inline]
1126            pub fn mul_add(self, a: $float, b: $float) -> $float {
1127                self.0.mul_add(a, b)
1128            }
1129
1130            /// Returns the Euclidean division of this value by `rhs`.
1131            #[inline]
1132            pub fn div_euclid(self, rhs: $float) -> $float {
1133                self.0.div_euclid(rhs)
1134            }
1135
1136            /// Returns the least non-negative remainder of this value divided by `rhs`.
1137            #[inline]
1138            pub fn rem_euclid(self, rhs: $float) -> $float {
1139                self.0.rem_euclid(rhs)
1140            }
1141
1142            /// Returns `e^(self)`.
1143            #[inline]
1144            pub fn exp(self) -> $float {
1145                self.0.exp()
1146            }
1147
1148            /// Returns `2^(self)`.
1149            #[inline]
1150            pub fn exp2(self) -> $float {
1151                self.0.exp2()
1152            }
1153
1154            /// Returns the natural logarithm.
1155            #[inline]
1156            pub fn ln(self) -> $float {
1157                self.0.ln()
1158            }
1159
1160            /// Returns the logarithm with respect to an arbitrary base.
1161            #[inline]
1162            pub fn log(self, base: $float) -> $float {
1163                self.0.log(base)
1164            }
1165
1166            /// Returns the base 2 logarithm.
1167            #[inline]
1168            pub fn log2(self) -> $float {
1169                self.0.log2()
1170            }
1171
1172            /// Returns the base 10 logarithm.
1173            #[inline]
1174            pub fn log10(self) -> $float {
1175                self.0.log10()
1176            }
1177
1178            /// Returns the sine, in radians.
1179            #[inline]
1180            pub fn sin(self) -> Self {
1181                Self::from_inner(self.0.sin())
1182            }
1183
1184            /// Returns the cosine, in radians.
1185            #[inline]
1186            pub fn cos(self) -> UnitInterval<$float> {
1187                UnitInterval::new(self.0.cos()).expect("cosine on [-1, 1] is in [0, 1]")
1188            }
1189
1190            /// Returns the tangent, in radians.
1191            #[inline]
1192            pub fn tan(self) -> $float {
1193                self.0.tan()
1194            }
1195
1196            /// Returns both sine and cosine, in radians.
1197            #[inline]
1198            pub fn sin_cos(self) -> (Self, UnitInterval<$float>) {
1199                let (sin, cos) = self.0.sin_cos();
1200                (
1201                    Self::from_inner(sin),
1202                    UnitInterval::new(cos).expect("cosine on [-1, 1] is in [0, 1]"),
1203                )
1204            }
1205
1206            /// Returns the arcsine, in radians.
1207            #[inline]
1208            pub fn asin(self) -> $float {
1209                self.0.asin()
1210            }
1211
1212            /// Returns the arccosine, in radians.
1213            #[inline]
1214            pub fn acos(self) -> $float {
1215                self.0.acos()
1216            }
1217
1218            /// Returns the arctangent, in radians.
1219            #[inline]
1220            pub fn atan(self) -> Self {
1221                Self::from_inner(self.0.atan())
1222            }
1223
1224            /// Returns the four-quadrant arctangent of `self` and `other`, in radians.
1225            #[inline]
1226            pub fn atan2(self, other: $float) -> $float {
1227                self.0.atan2(other)
1228            }
1229
1230            /// Returns the hyperbolic sine.
1231            #[inline]
1232            pub fn sinh(self) -> $float {
1233                self.0.sinh()
1234            }
1235
1236            /// Returns the hyperbolic cosine.
1237            #[inline]
1238            pub fn cosh(self) -> $float {
1239                self.0.cosh()
1240            }
1241
1242            /// Returns the hyperbolic tangent.
1243            #[inline]
1244            pub fn tanh(self) -> Self {
1245                Self::from_inner(self.0.tanh())
1246            }
1247
1248            /// Returns the inverse hyperbolic sine.
1249            #[inline]
1250            pub fn asinh(self) -> Self {
1251                Self::from_inner(self.0.asinh())
1252            }
1253
1254            /// Returns the inverse hyperbolic cosine.
1255            #[inline]
1256            pub fn acosh(self) -> $float {
1257                self.0.acosh()
1258            }
1259
1260            /// Returns the inverse hyperbolic tangent.
1261            #[inline]
1262            pub fn atanh(self) -> $float {
1263                self.0.atanh()
1264            }
1265
1266            /// Calculates the length of the hypotenuse of a right-angle triangle.
1267            #[inline]
1268            pub fn hypot(self, other: $float) -> $float {
1269                self.0.hypot(other)
1270            }
1271        }
1272    };
1273}
1274
1275impl_signed_unit_interval_float!(f32);
1276impl_signed_unit_interval_float!(f64);
1277
1278/// Converts a `SignedUnitInterval<f32>` into its inner value widened to `f64`.
1279impl From<SignedUnitInterval<f32>> for f64 {
1280    #[inline]
1281    fn from(u: SignedUnitInterval) -> Self {
1282        u.0 as f64
1283    }
1284}
1285
1286/// Converts a `SignedUnitInterval<f32>` into `SignedUnitInterval<f64>`.
1287impl From<SignedUnitInterval<f32>> for SignedUnitInterval<f64> {
1288    #[inline]
1289    fn from(u: SignedUnitInterval<f32>) -> Self {
1290        Self::from_inner(u.0 as f64)
1291    }
1292}
1293
1294/// Converts a `SignedUnitInterval<f64>` into `SignedUnitInterval<f32>`.
1295impl From<SignedUnitInterval<f64>> for SignedUnitInterval<f32> {
1296    #[inline]
1297    fn from(u: SignedUnitInterval<f64>) -> Self {
1298        Self::from_inner(u.0 as f32)
1299    }
1300}
1301
1302/// Multiplies two signed unit interval values.
1303impl<T: UnitIntervalFloat> Mul for SignedUnitInterval<T> {
1304    type Output = Self;
1305
1306    #[inline]
1307    fn mul(self, rhs: Self) -> Self::Output {
1308        Self::from_inner(self.0 * rhs.0)
1309    }
1310}
1311
1312/// Multiplies a signed unit interval by a unit interval.
1313impl<T: UnitIntervalFloat> Mul<UnitInterval<T>> for SignedUnitInterval<T> {
1314    type Output = Self;
1315
1316    #[inline]
1317    fn mul(self, rhs: UnitInterval<T>) -> Self::Output {
1318        Self::from_inner(self.0 * rhs.get())
1319    }
1320}
1321
1322/// Multiplies a unit interval by a signed unit interval.
1323impl<T: UnitIntervalFloat> Mul<SignedUnitInterval<T>> for UnitInterval<T> {
1324    type Output = SignedUnitInterval<T>;
1325
1326    #[inline]
1327    fn mul(self, rhs: SignedUnitInterval<T>) -> Self::Output {
1328        SignedUnitInterval::from_inner(self.get() * rhs.0)
1329    }
1330}
1331
1332#[cfg(test)]
1333mod tests {
1334    use super::SignedUnitInterval;
1335
1336    #[test]
1337    #[should_panic(expected = "SignedUnitInterval invariant violated")]
1338    fn test_configuration_enables_internal_assertions() {
1339        SignedUnitInterval::<f32>::from_inner(1.1);
1340    }
1341
1342    #[cfg(feature = "rkyv")]
1343    #[test]
1344    fn rkyv_deserialization_rejects_invalid_archived_inner_value() {
1345        let invalid = super::ArchivedSignedUnitInterval(rkyv::Archived::<f32>::from_native(1.25));
1346
1347        assert!(
1348            rkyv::deserialize::<SignedUnitInterval<f32>, rkyv::rancor::Error>(&invalid).is_err()
1349        );
1350    }
1351}