decorum/proxy/
constrained.rs

1#[cfg(feature = "approx")]
2use approx::{AbsDiffEq, RelativeEq, UlpsEq};
3use core::cmp::Ordering;
4use core::fmt::{self, Debug, Display, Formatter, LowerExp, UpperExp};
5use core::hash::{Hash, Hasher};
6use core::iter::{Product, Sum};
7use core::marker::PhantomData;
8use core::mem;
9use core::num::FpCategory;
10use core::ops::{
11    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
12};
13use core::str::FromStr;
14#[cfg(not(feature = "std"))]
15use num_traits::float::FloatCore as Float;
16#[cfg(feature = "std")]
17use num_traits::Float;
18use num_traits::{
19    Bounded, FloatConst, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Zero,
20};
21#[cfg(feature = "serde")]
22use serde_derive::{Deserialize, Serialize};
23
24use crate::cmp::{CanonicalEq, CanonicalOrd, EmptyInhabitant, EmptyOrd};
25use crate::constraint::{
26    Constraint, ExpectConstrained, InfinitySet, IsExtendedReal, IsFloat, IsReal, Member, NanSet,
27    SubsetOf, SupersetOf,
28};
29use crate::divergence::{self, Divergence, NonResidual};
30use crate::expression::Expression;
31use crate::hash::CanonicalHash;
32use crate::proxy::Proxy;
33#[cfg(feature = "serde")]
34use crate::proxy::Serde;
35use crate::real::{BinaryRealFunction, Function, Sign, UnaryRealFunction};
36use crate::sealed::StaticDebug;
37use crate::{
38    with_binary_operations, with_primitives, BaseEncoding, ExtendedReal, InfinityEncoding,
39    NanEncoding, Primitive, Real, ToCanonical, Total,
40};
41
42pub type OutputFor<P> = divergence::OutputFor<DivergenceFor<P>, P, ErrorFor<P>>;
43pub type ConstraintFor<P> = <P as ConstrainedProxy>::Constraint;
44pub type DivergenceFor<P> = <ConstraintFor<P> as Constraint>::Divergence;
45pub type ErrorFor<P> = <ConstraintFor<P> as Constraint>::Error;
46pub type ExpressionFor<P> = Expression<P, ErrorFor<P>>;
47
48/// A constrained IEEE 754 floating-point proxy type.
49pub trait ConstrainedProxy: Proxy {
50    type Constraint: Constraint;
51}
52
53/// IEEE 754 floating-point proxy that provides total ordering, equivalence, hashing, constraints,
54/// and error handling.
55///
56/// `Constrained` types wrap primitive floating-point type and extend their behavior. For example,
57/// all proxy types implement the standard [`Eq`], [`Hash`], and [`Ord`] traits, sometimes via the
58/// non-standard relations described in the [`cmp`] module when `NaN`s must be considered.
59/// Constraints and divergence can be composed to determine the subset of floating-point values
60/// that a proxy supports and how the proxy behaves when those constraints are violated.
61///
62/// Various type definitions are provided for various useful proxy constructions, such as the
63/// [`Total`] type, which extends floating-point types with a non-standard total ordering.
64///
65/// [`cmp`]: crate::cmp
66#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
67#[cfg_attr(
68    feature = "serde",
69    serde(
70        bound(
71            deserialize = "T: serde::Deserialize<'de> + Primitive, \
72                           C: Constraint, \
73                           C::Error: Display",
74            serialize = "T: Primitive + serde::Serialize, \
75                         C: Constraint"
76        ),
77        try_from = "Serde<T>",
78        into = "Serde<T>"
79    )
80)]
81#[repr(transparent)]
82pub struct Constrained<T, C> {
83    inner: T,
84    #[cfg_attr(feature = "serde", serde(skip))]
85    phantom: PhantomData<fn() -> C>,
86}
87
88impl<T, C> Constrained<T, C> {
89    pub(crate) const fn unchecked(inner: T) -> Self {
90        Constrained {
91            inner,
92            phantom: PhantomData,
93        }
94    }
95
96    pub(crate) fn with_inner<U, F>(self, f: F) -> U
97    where
98        F: FnOnce(T) -> U,
99    {
100        f(self.inner)
101    }
102}
103
104impl<T, C> Constrained<T, C>
105where
106    T: Copy,
107{
108    /// Converts a proxy into its underlying primitive floating-point type.
109    ///
110    /// # Examples
111    ///
112    /// ```rust
113    /// use decorum::R64;
114    ///
115    /// fn f() -> R64 {
116    /// #    use decorum::real::UnaryRealFunction;
117    /// #    R64::ZERO
118    ///     // ...
119    /// }
120    ///
121    /// let x: f64 = f().into_inner();
122    /// // The standard `From` and `Into` traits can also be used.
123    /// let y: f64 = f().into();
124    /// ```
125    pub const fn into_inner(self) -> T {
126        self.inner
127    }
128
129    pub(crate) fn map_unchecked<F>(self, f: F) -> Self
130    where
131        F: FnOnce(T) -> T,
132    {
133        Constrained::unchecked(f(self.into_inner()))
134    }
135}
136
137impl<T, C> Constrained<T, C>
138where
139    T: Debug,
140    C: StaticDebug,
141{
142    /// Writes a thorough [debugging][`Debug`] description of the proxy to the given [`Formatter`].
143    ///
144    /// This function is similar to [`debug`], but writes a verbose description of the proxy into a
145    /// [`Formatter`] rather than returning a [`Debug`] implementation.
146    ///
147    /// [`debug`]: crate::proxy::Constrained::debug
148    pub fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
149        write!(formatter, "Constrained<")?;
150        C::fmt(formatter)?;
151        write!(formatter, ">({:?})", self.inner)
152    }
153
154    /// Gets a [`Debug`] implementation that thoroughly describes the proxy.
155    ///
156    /// `Constrained` types implement [`Display`] and [`Debug`], but these implementations omit
157    /// more specific information about [constraints][`constraint`] and [divergence]. This function
158    /// provides an instance of a verbose [`Debug`] type that more thoroughly describes the
159    /// behavior of the proxy.
160    ///
161    /// [`constraint`]: crate::constraint
162    pub const fn debug(&self) -> impl '_ + Copy + Debug {
163        struct Formatted<'a, T, C>(&'a Constrained<T, C>);
164
165        impl<T, C> Clone for Formatted<'_, T, C> {
166            fn clone(&self) -> Self {
167                *self
168            }
169        }
170
171        impl<T, C> Copy for Formatted<'_, T, C> {}
172
173        impl<T, C> Debug for Formatted<'_, T, C>
174        where
175            T: Debug,
176            C: StaticDebug,
177        {
178            fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
179                Constrained::fmt(self.0, formatter)
180            }
181        }
182
183        Formatted(self)
184    }
185}
186
187impl<T, C> Constrained<T, C>
188where
189    T: Primitive,
190    C: Constraint,
191{
192    /// Constructs a proxy from a primitive IEEE 754 floating-point value.
193    ///
194    /// This function returns the output type of the [divergence] of the proxy and invokes its
195    /// error behavior if the floating-point value does not satisfy constraints. Note that this
196    /// function never fails for [`Total`], which has no constraints.
197    ///
198    /// The distinctions in output and behavior are static and are determined by the type
199    /// parameters of the `Constrained` type constructor.
200    ///
201    /// # Panics
202    ///
203    /// This function panics if the primitive floating-point value does not satisfy the constraints
204    /// of the proxy **and** the [divergence] of the proxy panics. For example, the [`OrPanic`]
205    /// divergence asserts constraints and panics.
206    ///
207    /// # Errors
208    ///
209    /// Returns an error if the primitive floating-point value does not satisfy the constraints of
210    /// the proxy **and** the [divergence] of the proxy encodes errors in its output type. For
211    /// example, the output type of the `OrError<AsExpression>` divergence is [`Expression`] and
212    /// this function returns the [`Undefined`] variant if the constraint is violated.
213    ///
214    /// # Examples
215    ///
216    /// Fallibly constructing proxies from primitive floating-point values:
217    ///
218    /// ```rust
219    /// use decorum::constraint::IsReal;
220    /// use decorum::divergence::{AsResult, OrError};
221    /// use decorum::proxy::Constrained;
222    ///
223    /// // The output type of `Real` is `Result`.
224    /// type Real = Constrained<f64, IsReal<OrError<AsResult>>>;
225    ///
226    /// let x = Real::new(2.0).unwrap(); // The output type of `new` is `Result` per `TryResult`.
227    /// ```
228    ///
229    /// Asserting proxy construction from primitive floating-point values:
230    ///
231    /// ```rust,should_panic
232    /// use decorum::constraint::IsReal;
233    /// use decorum::divergence::OrPanic;
234    /// use decorum::proxy::Constrained;
235    ///
236    /// // The output type of `OrPanic` is `Real`.
237    /// type Real = Constrained<f64, IsReal<OrPanic>>;
238    ///
239    /// let x = Real::new(2.0); // The output type of `new` is `Real` per `OrPanic`.
240    /// let y = Real::new(0.0 / 0.0); // Panics.
241    /// ```
242    ///
243    /// [`OrPanic`]: crate::divergence::OrPanic
244    /// [`Undefined`]: crate::expression::Expression::Undefined
245    pub fn new(inner: T) -> OutputFor<Self> {
246        C::map(inner, |inner| Constrained {
247            inner,
248            phantom: PhantomData,
249        })
250    }
251
252    /// Fallibly constructs a proxy from a primitive IEEE 754 floating-point value.
253    ///
254    /// This construction mirrors the [`TryFrom`] implementation and is independent of the
255    /// [divergence] of the proxy; it always outputs a [`Result`] and never panics.
256    ///
257    /// # Errors
258    ///
259    /// Returns an error if the primitive floating-point value does not satisfy the constraints of
260    /// the proxy. Note that the error type of the [`IsFloat`] constraint is [`Infallible`] and the
261    /// construction of [`Total`]s cannot fail here.
262    ///
263    /// # Examples
264    ///
265    /// Constructing proxies from primitive floating-point values:
266    ///
267    /// ```rust
268    /// use decorum::constraint::IsReal;
269    /// use decorum::divergence::OrPanic;
270    /// use decorum::proxy::Constrained;
271    ///
272    /// type Real = Constrained<f64, IsReal<OrPanic>>;
273    ///
274    /// fn f(x: Real) -> Real {
275    ///     x * 2.0
276    /// }
277    ///
278    /// let y = f(Real::try_new(2.0).unwrap());
279    /// // The `TryFrom` and `TryInto` traits can also be used.
280    /// let z = f(2.0.try_into().unwrap());
281    /// ```
282    ///
283    /// A proxy construction that fails:
284    ///
285    /// ```rust,should_panic
286    /// use decorum::constraint::IsReal;
287    /// use decorum::divergence::OrPanic;
288    /// use decorum::proxy::Constrained;
289    ///
290    /// type Real = Constrained<f64, IsReal<OrPanic>>;
291    ///
292    /// // `IsReal` does not allow `NaN`s, but `0.0 / 0.0` produces a `NaN`.
293    /// let x = Real::try_new(0.0 / 0.0).unwrap(); // Panics when unwrapping.
294    /// ```
295    ///
296    /// [`Infallible`]: core::convert::Infallible
297    pub fn try_new(inner: T) -> Result<Self, C::Error> {
298        C::check(inner).map(|_| Constrained {
299            inner,
300            phantom: PhantomData,
301        })
302    }
303
304    /// Constructs a proxy from a primitive IEEE 754 floating-point value and asserts that its
305    /// constraints are satisfied.
306    ///
307    /// This construction is independent of the [divergence] of the proxy and always asserts
308    /// constraints (even when the divergence is fallible). Note that this function never fails
309    /// (panics) for [`Total`], which has no constraints.
310    ///
311    /// # Panics
312    ///
313    /// **This construction panics if the primitive floating-point value does not satisfy the
314    /// constraints of the proxy.**
315    ///
316    /// # Examples
317    ///
318    /// Constructing proxies from primitive floating-point values:
319    ///
320    /// ```rust
321    /// use decorum::constraint::IsReal;
322    /// use decorum::divergence::OrPanic;
323    /// use decorum::proxy::Constrained;
324    ///
325    /// type Real = Constrained<f64, IsReal<OrPanic>>;
326    ///
327    /// fn f(x: Real) -> Real {
328    ///     x * 2.0
329    /// }
330    ///
331    /// let y = f(Real::assert(2.0));
332    /// ```
333    ///
334    /// A proxy construction that fails:
335    ///
336    /// ```rust,should_panic
337    /// use decorum::constraint::IsReal;
338    /// use decorum::divergence::OrPanic;
339    /// use decorum::proxy::Constrained;
340    ///
341    /// type Real = Constrained<f64, IsReal<OrPanic>>;
342    ///
343    /// // `IsReal` does not allow `NaN`s, but `0.0 / 0.0` produces a `NaN`.
344    /// let x = Real::assert(0.0 / 0.0); // Panics.
345    /// ```
346    pub fn assert(inner: T) -> Self {
347        Self::try_new(inner).expect_constrained()
348    }
349
350    /// Converts a slice of primitive IEEE 754 floating-point values into a slice of proxies.
351    ///
352    /// This conversion must check the constraints of the proxy against each floating-point value
353    /// and so has `O(N)` time complexity. **When using the [`IsFloat`] constraint, prefer the
354    /// infallible and `O(1)` [`from_slice`] function.**
355    ///
356    /// # Errors
357    ///
358    /// Returns an error if any of the primitive floating-point values in the slice do not satisfy
359    /// the constraints of the proxy.
360    ///
361    /// [`from_slice`]: crate::Total::from_slice
362    pub fn try_from_slice<'a>(slice: &'a [T]) -> Result<&'a [Self], C::Error> {
363        slice.iter().try_for_each(|inner| C::check(*inner))?;
364        // SAFETY: `Constrained<T>` is `repr(transparent)` and has the same binary representation
365        //         as its input type `T`. This means that it is safe to transmute `T` to
366        //         `Constrained<T>`.
367        Ok(unsafe { mem::transmute::<&'a [T], &'a [Self]>(slice) })
368    }
369
370    /// Converts a mutable slice of primitive IEEE 754 floating-point values into a mutable slice
371    /// of proxies.
372    ///
373    /// This conversion must check the constraints of the proxy against each floating-point value
374    /// and so has `O(N)` time complexity. **When using the [`IsFloat`] constraint, prefer the
375    /// infallible and `O(1)` [`from_mut_slice`] function.**
376    ///
377    /// # Errors
378    ///
379    /// Returns an error if any of the primitive floating-point values in the
380    /// slice do not satisfy the constraints of the proxy.
381    ///
382    /// [`from_mut_slice`]: crate::Total::from_mut_slice
383    pub fn try_from_mut_slice<'a>(slice: &'a mut [T]) -> Result<&'a mut [Self], C::Error> {
384        slice.iter().try_for_each(|inner| C::check(*inner))?;
385        // SAFETY: `Constrained<T>` is `repr(transparent)` and has the same binary representation
386        //         as its input type `T`. This means that it is safe to transmute `T` to
387        //         `Constrained<T>`.
388        Ok(unsafe { mem::transmute::<&'a mut [T], &'a mut [Self]>(slice) })
389    }
390
391    /// Converts a proxy into another proxy that is capable of representing a superset of its
392    /// values per its constraint.
393    ///
394    /// # Examples
395    ///
396    /// ```rust
397    /// use decorum::divergence::OrPanic;
398    /// use decorum::real::UnaryRealFunction;
399    /// use decorum::{E64, R64};
400    ///
401    /// let x = R64::<OrPanic>::ZERO;
402    /// let y = E64::from_subset(x); // `E64` allows a superset of the values of `R64`.
403    /// ```
404    pub fn from_subset<C2>(other: Constrained<T, C2>) -> Self
405    where
406        C2: Constraint + SubsetOf<C>,
407    {
408        Self::unchecked(other.into_inner())
409    }
410
411    /// Converts a proxy into another proxy that is capable of representing a superset of its
412    /// values per its constraint.
413    ///
414    /// # Examples
415    ///
416    /// ```rust
417    /// use decorum::real::UnaryRealFunction;
418    /// use decorum::{E64, R64};
419    ///
420    /// let x = R64::ZERO;
421    /// let y: E64 = x.into_superset(); // `E64` allows a superset of the values of `R64`.
422    /// ```
423    pub fn into_superset<C2>(self) -> Constrained<T, C2>
424    where
425        C2: Constraint + SupersetOf<C>,
426    {
427        Constrained::unchecked(self.into_inner())
428    }
429
430    /// Converts a proxy into its corresponding [`Expression`].
431    ///
432    /// The output of this function is always the [`Defined`] variant.
433    ///
434    /// [`Defined`]: crate::expression::Expression::Defined
435    pub fn into_expression(self) -> ExpressionFor<Self> {
436        Expression::from(self)
437    }
438
439    pub(crate) fn map<F>(self, f: F) -> OutputFor<Self>
440    where
441        F: FnOnce(T) -> T,
442    {
443        Self::new(f(self.into_inner()))
444    }
445
446    pub(crate) fn zip_map<C2, F>(self, other: Constrained<T, C2>, f: F) -> OutputFor<Self>
447    where
448        C2: Constraint,
449        F: FnOnce(T, T) -> T,
450    {
451        Self::new(f(self.into_inner(), other.into_inner()))
452    }
453}
454
455impl<T> Total<T>
456where
457    T: Primitive,
458{
459    /// Converts a slice of primitive IEEE 754 floating-point values into a slice of `Total`s.
460    ///
461    /// Unlike [`try_from_slice`], this conversion is infallible and trivial and so has `O(1)` time
462    /// complexity.
463    ///
464    /// [`try_from_slice`]: crate::proxy::Constrained::try_from_slice
465    pub fn from_slice<'a>(slice: &'a [T]) -> &'a [Self] {
466        // SAFETY: `Constrained<T>` is `repr(transparent)` and has the same binary representation
467        //         as its input type `T`. This means that it is safe to transmute `T` to
468        //         `Constrained<T>`.
469        unsafe { mem::transmute::<&'a [T], &'a [Self]>(slice) }
470    }
471
472    /// Converts a mutable slice of primitive floating-point values into a mutable slice of
473    /// `Total`s.
474    ///
475    /// Unlike [`try_from_mut_slice`], this conversion is infallible and trivial and so has `O(1)`
476    /// time complexity.
477    ///
478    /// [`try_from_mut_slice`]: crate::proxy::Constrained::try_from_mut_slice
479    pub fn from_mut_slice<'a>(slice: &'a mut [T]) -> &'a mut [Self] {
480        // SAFETY: `Constrained<T>` is `repr(transparent)` and has the same binary representation
481        //         as its input type `T`. This means that it is safe to transmute `T` to
482        //         `Constrained<T>`.
483        unsafe { mem::transmute::<&'a mut [T], &'a mut [Self]>(slice) }
484    }
485}
486
487#[cfg(feature = "approx")]
488impl<T, C> AbsDiffEq for Constrained<T, C>
489where
490    T: AbsDiffEq<Epsilon = T> + Primitive,
491    C: Constraint,
492{
493    type Epsilon = Self;
494
495    fn default_epsilon() -> Self::Epsilon {
496        Self::assert(T::default_epsilon())
497    }
498
499    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
500        self.into_inner()
501            .abs_diff_eq(&other.into_inner(), epsilon.into_inner())
502    }
503}
504
505impl<T, C> Add for Constrained<T, C>
506where
507    T: Primitive,
508    C: Constraint,
509{
510    type Output = OutputFor<Self>;
511
512    fn add(self, other: Self) -> Self::Output {
513        self.zip_map(other, Add::add)
514    }
515}
516
517impl<T, C> Add<T> for Constrained<T, C>
518where
519    T: Primitive,
520    C: Constraint,
521{
522    type Output = OutputFor<Self>;
523
524    fn add(self, other: T) -> Self::Output {
525        self.map(|inner| inner + other)
526    }
527}
528
529impl<T, C, E> AddAssign for Constrained<T, C>
530where
531    T: Primitive,
532    C: Constraint<Error = E>,
533    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
534{
535    fn add_assign(&mut self, other: Self) {
536        *self = *self + other;
537    }
538}
539
540impl<T, C, E> AddAssign<T> for Constrained<T, C>
541where
542    T: Primitive,
543    C: Constraint<Error = E>,
544    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
545{
546    fn add_assign(&mut self, other: T) {
547        *self = self.map(|inner| inner + other);
548    }
549}
550
551impl<T, C> AsRef<T> for Constrained<T, C> {
552    fn as_ref(&self) -> &T {
553        &self.inner
554    }
555}
556
557impl<T, C> BinaryRealFunction for Constrained<T, C>
558where
559    T: Primitive,
560    C: Constraint,
561{
562    #[cfg(feature = "std")]
563    fn div_euclid(self, n: Self) -> Self::Codomain {
564        self.zip_map(n, BinaryRealFunction::div_euclid)
565    }
566
567    #[cfg(feature = "std")]
568    fn rem_euclid(self, n: Self) -> Self::Codomain {
569        self.zip_map(n, BinaryRealFunction::rem_euclid)
570    }
571
572    #[cfg(feature = "std")]
573    fn pow(self, n: Self) -> Self::Codomain {
574        self.zip_map(n, BinaryRealFunction::pow)
575    }
576
577    #[cfg(feature = "std")]
578    fn log(self, base: Self) -> Self::Codomain {
579        self.zip_map(base, BinaryRealFunction::log)
580    }
581
582    #[cfg(feature = "std")]
583    fn hypot(self, other: Self) -> Self::Codomain {
584        self.zip_map(other, BinaryRealFunction::hypot)
585    }
586
587    #[cfg(feature = "std")]
588    fn atan2(self, other: Self) -> Self::Codomain {
589        self.zip_map(other, BinaryRealFunction::atan2)
590    }
591}
592
593impl<T, C> BinaryRealFunction<T> for Constrained<T, C>
594where
595    T: Primitive,
596    C: Constraint,
597{
598    #[cfg(feature = "std")]
599    fn div_euclid(self, n: T) -> Self::Codomain {
600        self.map(|inner| BinaryRealFunction::div_euclid(inner, n))
601    }
602
603    #[cfg(feature = "std")]
604    fn rem_euclid(self, n: T) -> Self::Codomain {
605        self.map(|inner| BinaryRealFunction::rem_euclid(inner, n))
606    }
607
608    #[cfg(feature = "std")]
609    fn pow(self, n: T) -> Self::Codomain {
610        self.map(|inner| BinaryRealFunction::pow(inner, n))
611    }
612
613    #[cfg(feature = "std")]
614    fn log(self, base: T) -> Self::Codomain {
615        self.map(|inner| BinaryRealFunction::log(inner, base))
616    }
617
618    #[cfg(feature = "std")]
619    fn hypot(self, other: T) -> Self::Codomain {
620        self.map(|inner| BinaryRealFunction::hypot(inner, other))
621    }
622
623    #[cfg(feature = "std")]
624    fn atan2(self, other: T) -> Self::Codomain {
625        self.map(|inner| BinaryRealFunction::atan2(inner, other))
626    }
627}
628
629impl<T, C> Bounded for Constrained<T, C>
630where
631    T: Primitive,
632{
633    fn min_value() -> Self {
634        BaseEncoding::MIN_FINITE
635    }
636
637    fn max_value() -> Self {
638        BaseEncoding::MAX_FINITE
639    }
640}
641
642impl<T, C> Clone for Constrained<T, C>
643where
644    T: Clone,
645{
646    fn clone(&self) -> Self {
647        Constrained {
648            inner: self.inner.clone(),
649            phantom: PhantomData,
650        }
651    }
652}
653
654impl<T, C> ConstrainedProxy for Constrained<T, C>
655where
656    T: Primitive,
657    C: Constraint,
658{
659    type Constraint = C;
660}
661
662impl<T, C> Function for Constrained<T, C>
663where
664    T: Primitive,
665    C: Constraint,
666{
667    type Codomain = OutputFor<Self>;
668}
669
670impl<T, C> Copy for Constrained<T, C> where T: Copy {}
671
672impl<T, D> Debug for Constrained<T, IsExtendedReal<D>>
673where
674    T: Debug,
675    D: Divergence,
676{
677    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
678        formatter
679            .debug_tuple("ExtendedReal")
680            .field(self.as_ref())
681            .finish()
682    }
683}
684
685impl<T> Debug for Constrained<T, IsFloat>
686where
687    T: Debug,
688{
689    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
690        formatter.debug_tuple("Total").field(self.as_ref()).finish()
691    }
692}
693
694impl<T, D> Debug for Constrained<T, IsReal<D>>
695where
696    T: Debug,
697    D: Divergence,
698{
699    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
700        formatter.debug_tuple("Real").field(self.as_ref()).finish()
701    }
702}
703
704impl<T, C> Default for Constrained<T, C>
705where
706    T: Primitive,
707    C: Constraint,
708{
709    fn default() -> Self {
710        // There is no constraint that disallows real numbers such as zero.
711        Self::unchecked(T::ZERO)
712    }
713}
714
715impl<T, C> Display for Constrained<T, C>
716where
717    T: Display,
718{
719    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
720        self.as_ref().fmt(f)
721    }
722}
723
724impl<T, C> Div for Constrained<T, C>
725where
726    T: Primitive,
727    C: Constraint,
728{
729    type Output = OutputFor<Self>;
730
731    fn div(self, other: Self) -> Self::Output {
732        self.zip_map(other, Div::div)
733    }
734}
735
736impl<T, C> Div<T> for Constrained<T, C>
737where
738    T: Primitive,
739    C: Constraint,
740{
741    type Output = OutputFor<Self>;
742
743    fn div(self, other: T) -> Self::Output {
744        self.map(|inner| inner / other)
745    }
746}
747
748impl<T, C, E> DivAssign for Constrained<T, C>
749where
750    T: Primitive,
751    C: Constraint<Error = E>,
752    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
753{
754    fn div_assign(&mut self, other: Self) {
755        *self = *self / other
756    }
757}
758
759impl<T, C, E> DivAssign<T> for Constrained<T, C>
760where
761    T: Primitive,
762    C: Constraint<Error = E>,
763    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
764{
765    fn div_assign(&mut self, other: T) {
766        *self = self.map(|inner| inner / other);
767    }
768}
769
770impl<T, C> BaseEncoding for Constrained<T, C>
771where
772    T: Primitive,
773{
774    const MAX_FINITE: Self = Constrained::unchecked(T::MAX_FINITE);
775    const MIN_FINITE: Self = Constrained::unchecked(T::MIN_FINITE);
776    const MIN_POSITIVE_NORMAL: Self = Constrained::unchecked(T::MIN_POSITIVE_NORMAL);
777    const EPSILON: Self = Constrained::unchecked(T::EPSILON);
778
779    fn classify(self) -> FpCategory {
780        T::classify(self.into_inner())
781    }
782
783    fn is_normal(self) -> bool {
784        T::is_normal(self.into_inner())
785    }
786
787    fn is_sign_positive(self) -> bool {
788        self.into_inner().is_sign_positive()
789    }
790
791    fn is_sign_negative(self) -> bool {
792        self.into_inner().is_sign_negative()
793    }
794
795    #[cfg(feature = "std")]
796    fn signum(self) -> Self {
797        self.map_unchecked(|inner| inner.signum())
798    }
799
800    fn integer_decode(self) -> (u64, i16, i8) {
801        T::integer_decode(self.into_inner())
802    }
803}
804
805impl<T, C> Eq for Constrained<T, C> where T: Primitive {}
806
807impl<T, C, E> Float for Constrained<T, C>
808where
809    T: Float + Primitive,
810    C: Constraint<Error = E> + Member<InfinitySet> + Member<NanSet>,
811    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
812{
813    fn infinity() -> Self {
814        InfinityEncoding::INFINITY
815    }
816
817    fn neg_infinity() -> Self {
818        InfinityEncoding::NEG_INFINITY
819    }
820
821    fn is_infinite(self) -> bool {
822        self.with_inner(Float::is_infinite)
823    }
824
825    fn is_finite(self) -> bool {
826        self.with_inner(Float::is_finite)
827    }
828
829    fn nan() -> Self {
830        <Self as NanEncoding>::NAN
831    }
832
833    fn is_nan(self) -> bool {
834        self.with_inner(Float::is_nan)
835    }
836
837    fn max_value() -> Self {
838        BaseEncoding::MAX_FINITE
839    }
840
841    fn min_value() -> Self {
842        BaseEncoding::MIN_FINITE
843    }
844
845    fn min_positive_value() -> Self {
846        BaseEncoding::MIN_POSITIVE_NORMAL
847    }
848
849    fn epsilon() -> Self {
850        BaseEncoding::EPSILON
851    }
852
853    fn min(self, other: Self) -> Self {
854        self.zip_map(other, Float::min)
855    }
856
857    fn max(self, other: Self) -> Self {
858        self.zip_map(other, Float::max)
859    }
860
861    fn neg_zero() -> Self {
862        -Self::ZERO
863    }
864
865    fn is_sign_positive(self) -> bool {
866        self.with_inner(Float::is_sign_positive)
867    }
868
869    fn is_sign_negative(self) -> bool {
870        self.with_inner(Float::is_sign_negative)
871    }
872
873    fn signum(self) -> Self {
874        self.map(Float::signum)
875    }
876
877    fn abs(self) -> Self {
878        self.map(Float::abs)
879    }
880
881    fn classify(self) -> FpCategory {
882        self.with_inner(Float::classify)
883    }
884
885    fn is_normal(self) -> bool {
886        self.with_inner(Float::is_normal)
887    }
888
889    fn integer_decode(self) -> (u64, i16, i8) {
890        self.with_inner(Float::integer_decode)
891    }
892
893    fn floor(self) -> Self {
894        self.map(Float::floor)
895    }
896
897    fn ceil(self) -> Self {
898        self.map(Float::ceil)
899    }
900
901    fn round(self) -> Self {
902        self.map(Float::round)
903    }
904
905    fn trunc(self) -> Self {
906        self.map(Float::trunc)
907    }
908
909    fn fract(self) -> Self {
910        self.map(Float::fract)
911    }
912
913    fn recip(self) -> Self {
914        self.map(Float::recip)
915    }
916
917    #[cfg(feature = "std")]
918    fn mul_add(self, a: Self, b: Self) -> Self {
919        let a = a.into_inner();
920        let b = b.into_inner();
921        // TODO: This implementation requires a `Float` bound and forwards to its `mul_add`.
922        //       Consider supporting `mul_add` via a trait that is more specific to floating-point
923        //       encoding than `BinaryRealFunction` and friends.
924        self.map(|inner| Float::mul_add(inner, a, b))
925    }
926
927    #[cfg(feature = "std")]
928    fn abs_sub(self, other: Self) -> Self {
929        self.zip_map(other, Float::abs_sub)
930    }
931
932    #[cfg(feature = "std")]
933    fn powi(self, n: i32) -> Self {
934        self.map(|inner| Float::powi(inner, n))
935    }
936
937    #[cfg(feature = "std")]
938    fn powf(self, n: Self) -> Self {
939        self.zip_map(n, Float::powf)
940    }
941
942    #[cfg(feature = "std")]
943    fn sqrt(self) -> Self {
944        self.map(Float::sqrt)
945    }
946
947    #[cfg(feature = "std")]
948    fn cbrt(self) -> Self {
949        self.map(Float::cbrt)
950    }
951
952    #[cfg(feature = "std")]
953    fn exp(self) -> Self {
954        self.map(Float::exp)
955    }
956
957    #[cfg(feature = "std")]
958    fn exp2(self) -> Self {
959        self.map(Float::exp2)
960    }
961
962    #[cfg(feature = "std")]
963    fn exp_m1(self) -> Self {
964        self.map(Float::exp_m1)
965    }
966
967    #[cfg(feature = "std")]
968    fn log(self, base: Self) -> Self {
969        self.zip_map(base, Float::log)
970    }
971
972    #[cfg(feature = "std")]
973    fn ln(self) -> Self {
974        self.map(Float::ln)
975    }
976
977    #[cfg(feature = "std")]
978    fn log2(self) -> Self {
979        self.map(Float::log2)
980    }
981
982    #[cfg(feature = "std")]
983    fn log10(self) -> Self {
984        self.map(Float::log10)
985    }
986
987    #[cfg(feature = "std")]
988    fn ln_1p(self) -> Self {
989        self.map(Float::ln_1p)
990    }
991
992    #[cfg(feature = "std")]
993    fn hypot(self, other: Self) -> Self {
994        BinaryRealFunction::hypot(self, other)
995    }
996
997    #[cfg(feature = "std")]
998    fn sin(self) -> Self {
999        self.map(Float::sin)
1000    }
1001
1002    #[cfg(feature = "std")]
1003    fn cos(self) -> Self {
1004        self.map(Float::cos)
1005    }
1006
1007    #[cfg(feature = "std")]
1008    fn tan(self) -> Self {
1009        self.map(Float::tan)
1010    }
1011
1012    #[cfg(feature = "std")]
1013    fn asin(self) -> Self {
1014        self.map(Float::asin)
1015    }
1016
1017    #[cfg(feature = "std")]
1018    fn acos(self) -> Self {
1019        self.map(Float::acos)
1020    }
1021
1022    #[cfg(feature = "std")]
1023    fn atan(self) -> Self {
1024        self.map(Float::atan)
1025    }
1026
1027    #[cfg(feature = "std")]
1028    fn atan2(self, other: Self) -> Self {
1029        BinaryRealFunction::atan2(self, other)
1030    }
1031
1032    #[cfg(feature = "std")]
1033    fn sin_cos(self) -> (Self, Self) {
1034        let (sin, cos) = Float::sin_cos(self.into_inner());
1035        (Constrained::<_, C>::new(sin), Constrained::<_, C>::new(cos))
1036    }
1037
1038    #[cfg(feature = "std")]
1039    fn sinh(self) -> Self {
1040        self.map(Float::sinh)
1041    }
1042
1043    #[cfg(feature = "std")]
1044    fn cosh(self) -> Self {
1045        self.map(Float::cosh)
1046    }
1047
1048    #[cfg(feature = "std")]
1049    fn tanh(self) -> Self {
1050        self.map(Float::tanh)
1051    }
1052
1053    #[cfg(feature = "std")]
1054    fn asinh(self) -> Self {
1055        self.map(Float::asinh)
1056    }
1057
1058    #[cfg(feature = "std")]
1059    fn acosh(self) -> Self {
1060        self.map(Float::acosh)
1061    }
1062
1063    #[cfg(feature = "std")]
1064    fn atanh(self) -> Self {
1065        self.map(Float::atanh)
1066    }
1067
1068    #[cfg(not(feature = "std"))]
1069    fn to_degrees(self) -> Self {
1070        self.map(Float::to_degrees)
1071    }
1072
1073    #[cfg(not(feature = "std"))]
1074    fn to_radians(self) -> Self {
1075        self.map(Float::to_radians)
1076    }
1077}
1078
1079impl<T, C> FloatConst for Constrained<T, C>
1080where
1081    T: Primitive,
1082    C: Constraint,
1083{
1084    fn E() -> Self {
1085        <Self as UnaryRealFunction>::E
1086    }
1087
1088    fn PI() -> Self {
1089        <Self as UnaryRealFunction>::PI
1090    }
1091
1092    fn SQRT_2() -> Self {
1093        <Self as UnaryRealFunction>::SQRT_2
1094    }
1095
1096    fn FRAC_1_PI() -> Self {
1097        <Self as UnaryRealFunction>::FRAC_1_PI
1098    }
1099
1100    fn FRAC_2_PI() -> Self {
1101        <Self as UnaryRealFunction>::FRAC_2_PI
1102    }
1103
1104    fn FRAC_1_SQRT_2() -> Self {
1105        <Self as UnaryRealFunction>::FRAC_1_SQRT_2
1106    }
1107
1108    fn FRAC_2_SQRT_PI() -> Self {
1109        <Self as UnaryRealFunction>::FRAC_2_SQRT_PI
1110    }
1111
1112    fn FRAC_PI_2() -> Self {
1113        <Self as UnaryRealFunction>::FRAC_PI_2
1114    }
1115
1116    fn FRAC_PI_3() -> Self {
1117        <Self as UnaryRealFunction>::FRAC_PI_3
1118    }
1119
1120    fn FRAC_PI_4() -> Self {
1121        <Self as UnaryRealFunction>::FRAC_PI_4
1122    }
1123
1124    fn FRAC_PI_6() -> Self {
1125        <Self as UnaryRealFunction>::FRAC_PI_6
1126    }
1127
1128    fn FRAC_PI_8() -> Self {
1129        <Self as UnaryRealFunction>::FRAC_PI_8
1130    }
1131
1132    fn LN_10() -> Self {
1133        <Self as UnaryRealFunction>::LN_10
1134    }
1135
1136    fn LN_2() -> Self {
1137        <Self as UnaryRealFunction>::LN_2
1138    }
1139
1140    fn LOG10_E() -> Self {
1141        <Self as UnaryRealFunction>::LOG10_E
1142    }
1143
1144    fn LOG2_E() -> Self {
1145        <Self as UnaryRealFunction>::LOG2_E
1146    }
1147}
1148
1149impl<T> From<Real<T>> for ExtendedReal<T>
1150where
1151    T: Primitive,
1152{
1153    fn from(other: Real<T>) -> Self {
1154        Self::from_subset(other)
1155    }
1156}
1157
1158impl<'a, T> From<&'a T> for &'a Total<T>
1159where
1160    T: Primitive,
1161{
1162    fn from(inner: &'a T) -> Self {
1163        // SAFETY: `Constrained<T>` is `repr(transparent)` and has the same binary representation
1164        //         as its input type `T`. This means that it is safe to transmute `T` to
1165        //         `Constrained<T>`.
1166        unsafe { &*(inner as *const T as *const Total<T>) }
1167    }
1168}
1169
1170impl<'a, T> From<&'a mut T> for &'a mut Total<T>
1171where
1172    T: Primitive,
1173{
1174    fn from(inner: &'a mut T) -> Self {
1175        // SAFETY: `Constrained<T>` is `repr(transparent)` and has the same binary representation
1176        //         as its input type `T`. This means that it is safe to transmute `T` to
1177        //         `Constrained<T>`.
1178        unsafe { &mut *(inner as *mut T as *mut Total<T>) }
1179    }
1180}
1181
1182impl<T> From<Real<T>> for Total<T>
1183where
1184    T: Primitive,
1185{
1186    fn from(other: Real<T>) -> Self {
1187        Self::from_subset(other)
1188    }
1189}
1190
1191impl<T> From<ExtendedReal<T>> for Total<T>
1192where
1193    T: Primitive,
1194{
1195    fn from(other: ExtendedReal<T>) -> Self {
1196        Self::from_subset(other)
1197    }
1198}
1199
1200impl<C> From<Constrained<f32, C>> for f32 {
1201    fn from(proxy: Constrained<f32, C>) -> Self {
1202        proxy.into_inner()
1203    }
1204}
1205
1206impl<C> From<Constrained<f64, C>> for f64 {
1207    fn from(proxy: Constrained<f64, C>) -> Self {
1208        proxy.into_inner()
1209    }
1210}
1211
1212#[cfg(feature = "serde")]
1213impl<T, C> From<Constrained<T, C>> for Serde<T>
1214where
1215    T: Copy,
1216{
1217    fn from(proxy: Constrained<T, C>) -> Self {
1218        Serde {
1219            inner: proxy.into_inner(),
1220        }
1221    }
1222}
1223
1224impl<T> From<T> for Total<T>
1225where
1226    T: Primitive,
1227{
1228    fn from(inner: T) -> Self {
1229        Self::unchecked(inner)
1230    }
1231}
1232
1233impl<T, C> FromPrimitive for Constrained<T, C>
1234where
1235    T: FromPrimitive + Primitive,
1236    C: Constraint,
1237{
1238    fn from_i8(value: i8) -> Option<Self> {
1239        T::from_i8(value).and_then(|inner| Constrained::try_new(inner).ok())
1240    }
1241
1242    fn from_u8(value: u8) -> Option<Self> {
1243        T::from_u8(value).and_then(|inner| Constrained::try_new(inner).ok())
1244    }
1245
1246    fn from_i16(value: i16) -> Option<Self> {
1247        T::from_i16(value).and_then(|inner| Constrained::try_new(inner).ok())
1248    }
1249
1250    fn from_u16(value: u16) -> Option<Self> {
1251        T::from_u16(value).and_then(|inner| Constrained::try_new(inner).ok())
1252    }
1253
1254    fn from_i32(value: i32) -> Option<Self> {
1255        T::from_i32(value).and_then(|inner| Constrained::try_new(inner).ok())
1256    }
1257
1258    fn from_u32(value: u32) -> Option<Self> {
1259        T::from_u32(value).and_then(|inner| Constrained::try_new(inner).ok())
1260    }
1261
1262    fn from_i64(value: i64) -> Option<Self> {
1263        T::from_i64(value).and_then(|inner| Constrained::try_new(inner).ok())
1264    }
1265
1266    fn from_u64(value: u64) -> Option<Self> {
1267        T::from_u64(value).and_then(|inner| Constrained::try_new(inner).ok())
1268    }
1269
1270    fn from_isize(value: isize) -> Option<Self> {
1271        T::from_isize(value).and_then(|inner| Constrained::try_new(inner).ok())
1272    }
1273
1274    fn from_usize(value: usize) -> Option<Self> {
1275        T::from_usize(value).and_then(|inner| Constrained::try_new(inner).ok())
1276    }
1277
1278    fn from_f32(value: f32) -> Option<Self> {
1279        T::from_f32(value).and_then(|inner| Constrained::try_new(inner).ok())
1280    }
1281
1282    fn from_f64(value: f64) -> Option<Self> {
1283        T::from_f64(value).and_then(|inner| Constrained::try_new(inner).ok())
1284    }
1285}
1286
1287impl<T, C, E> FromStr for Constrained<T, C>
1288where
1289    T: FromStr + Primitive,
1290    C: Constraint<Error = E>,
1291    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1292{
1293    type Err = <T as FromStr>::Err;
1294
1295    fn from_str(string: &str) -> Result<Self, Self::Err> {
1296        T::from_str(string).map(Self::new)
1297    }
1298}
1299
1300impl<T, C> Hash for Constrained<T, C>
1301where
1302    T: Primitive + ToCanonical,
1303{
1304    fn hash<H>(&self, state: &mut H)
1305    where
1306        H: Hasher,
1307    {
1308        self.hash_canonical(state)
1309    }
1310}
1311
1312impl<T, C> InfinityEncoding for Constrained<T, C>
1313where
1314    T: Primitive,
1315    C: Constraint + Member<InfinitySet>,
1316{
1317    const INFINITY: Self = Constrained::unchecked(T::INFINITY);
1318    const NEG_INFINITY: Self = Constrained::unchecked(T::NEG_INFINITY);
1319
1320    fn is_infinite(self) -> bool {
1321        self.into_inner().is_infinite()
1322    }
1323
1324    fn is_finite(self) -> bool {
1325        self.into_inner().is_finite()
1326    }
1327}
1328
1329impl<T, C> EmptyOrd for Constrained<T, C>
1330where
1331    T: Primitive,
1332    C: Constraint,
1333{
1334    type Empty = C::Empty<T>;
1335
1336    #[inline(always)]
1337    fn from_empty(empty: Self::Empty) -> Self {
1338        C::from_empty(empty)
1339    }
1340
1341    #[inline(always)]
1342    fn is_empty(&self) -> bool {
1343        C::is_empty(self.as_ref())
1344    }
1345
1346    fn cmp_empty(&self, other: &Self) -> Result<Ordering, Self::Empty> {
1347        match self.as_ref().cmp_empty(other.as_ref()) {
1348            Ok(ordering) => Ok(ordering),
1349            Err(_) => Err(C::empty()),
1350        }
1351    }
1352}
1353
1354impl<T> EmptyInhabitant for Total<T>
1355where
1356    T: Primitive,
1357{
1358    fn empty() -> Self {
1359        Total::NAN
1360    }
1361}
1362
1363impl<T, C> LowerExp for Constrained<T, C>
1364where
1365    T: LowerExp + Primitive,
1366{
1367    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1368        self.as_ref().fmt(f)
1369    }
1370}
1371
1372impl<T, C> Mul for Constrained<T, C>
1373where
1374    T: Primitive,
1375    C: Constraint,
1376{
1377    type Output = OutputFor<Self>;
1378
1379    fn mul(self, other: Self) -> Self::Output {
1380        self.zip_map(other, Mul::mul)
1381    }
1382}
1383
1384impl<T, C> Mul<T> for Constrained<T, C>
1385where
1386    T: Primitive,
1387    C: Constraint,
1388{
1389    type Output = OutputFor<Self>;
1390
1391    fn mul(self, other: T) -> Self::Output {
1392        self.map(|a| a * other)
1393    }
1394}
1395
1396impl<T, C, E> MulAssign for Constrained<T, C>
1397where
1398    T: Primitive,
1399    C: Constraint<Error = E>,
1400    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1401{
1402    fn mul_assign(&mut self, other: Self) {
1403        *self = *self * other;
1404    }
1405}
1406
1407impl<T, C, E> MulAssign<T> for Constrained<T, C>
1408where
1409    T: Primitive,
1410    C: Constraint<Error = E>,
1411    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1412{
1413    fn mul_assign(&mut self, other: T) {
1414        *self = *self * other;
1415    }
1416}
1417
1418impl<T, C> NanEncoding for Constrained<T, C>
1419where
1420    T: Primitive,
1421    C: Constraint + Member<NanSet>,
1422{
1423    type Nan = Self;
1424
1425    const NAN: Self::Nan = Constrained::unchecked(T::NAN.into_inner());
1426
1427    fn is_nan(self) -> bool {
1428        self.into_inner().is_nan()
1429    }
1430}
1431
1432impl<T, C> Neg for Constrained<T, C>
1433where
1434    T: Primitive,
1435{
1436    type Output = Self;
1437
1438    fn neg(self) -> Self::Output {
1439        // There is no constraint for which negating a value produces an invalid value.
1440        Constrained::unchecked(-self.into_inner())
1441    }
1442}
1443
1444impl<T, C, E> Num for Constrained<T, C>
1445where
1446    T: Num + Primitive,
1447    C: Constraint<Error = E>,
1448    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1449{
1450    // TODO: Differentiate between parse and contraint errors.
1451    type FromStrRadixErr = ();
1452
1453    fn from_str_radix(source: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
1454        T::from_str_radix(source, radix)
1455            .map_err(|_| ())
1456            .and_then(|inner| Constrained::try_new(inner).map_err(|_| ()))
1457    }
1458}
1459
1460impl<T, C> NumCast for Constrained<T, C>
1461where
1462    T: NumCast + Primitive + ToPrimitive,
1463    C: Constraint,
1464{
1465    fn from<U>(value: U) -> Option<Self>
1466    where
1467        U: ToPrimitive,
1468    {
1469        T::from(value).and_then(|inner| Constrained::try_new(inner).ok())
1470    }
1471}
1472
1473impl<T, C, E> One for Constrained<T, C>
1474where
1475    T: Primitive,
1476    C: Constraint<Error = E>,
1477    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1478{
1479    fn one() -> Self {
1480        UnaryRealFunction::ONE
1481    }
1482}
1483
1484impl<T, C> Ord for Constrained<T, C>
1485where
1486    T: Primitive,
1487{
1488    fn cmp(&self, other: &Self) -> Ordering {
1489        CanonicalOrd::cmp_canonical(self.as_ref(), other.as_ref())
1490    }
1491}
1492
1493impl<T, C> PartialEq for Constrained<T, C>
1494where
1495    T: Primitive,
1496{
1497    fn eq(&self, other: &Self) -> bool {
1498        self.eq_canonical(other)
1499    }
1500}
1501
1502impl<T, C> PartialEq<T> for Constrained<T, C>
1503where
1504    T: Primitive,
1505    C: Constraint,
1506{
1507    fn eq(&self, other: &T) -> bool {
1508        if let Ok(other) = Self::try_new(*other) {
1509            Self::eq(self, &other)
1510        }
1511        else {
1512            false
1513        }
1514    }
1515}
1516
1517impl<T, C> PartialOrd for Constrained<T, C>
1518where
1519    T: Primitive,
1520{
1521    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1522        Some(self.cmp(other))
1523    }
1524}
1525
1526impl<T, C> PartialOrd<T> for Constrained<T, C>
1527where
1528    T: Primitive,
1529    C: Constraint,
1530{
1531    fn partial_cmp(&self, other: &T) -> Option<Ordering> {
1532        Self::try_new(*other)
1533            .ok()
1534            .and_then(|other| Self::partial_cmp(self, &other))
1535    }
1536}
1537
1538impl<T, C, E> Product for Constrained<T, C>
1539where
1540    T: Primitive,
1541    C: Constraint<Error = E>,
1542    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1543{
1544    fn product<I>(input: I) -> Self
1545    where
1546        I: Iterator<Item = Self>,
1547    {
1548        input.fold(UnaryRealFunction::ONE, |a, b| a * b)
1549    }
1550}
1551
1552impl<T, C> Proxy for Constrained<T, C>
1553where
1554    T: Primitive,
1555{
1556    type Primitive = T;
1557}
1558
1559#[cfg(feature = "approx")]
1560impl<T, C> RelativeEq for Constrained<T, C>
1561where
1562    T: Primitive + RelativeEq<Epsilon = T>,
1563    C: Constraint,
1564{
1565    fn default_max_relative() -> Self::Epsilon {
1566        Self::assert(T::default_max_relative())
1567    }
1568
1569    fn relative_eq(
1570        &self,
1571        other: &Self,
1572        epsilon: Self::Epsilon,
1573        max_relative: Self::Epsilon,
1574    ) -> bool {
1575        self.into_inner().relative_eq(
1576            &other.into_inner(),
1577            epsilon.into_inner(),
1578            max_relative.into_inner(),
1579        )
1580    }
1581}
1582
1583impl<T, C> Rem for Constrained<T, C>
1584where
1585    T: Primitive,
1586    C: Constraint,
1587{
1588    type Output = OutputFor<Self>;
1589
1590    fn rem(self, other: Self) -> Self::Output {
1591        self.zip_map(other, Rem::rem)
1592    }
1593}
1594
1595impl<T, C> Rem<T> for Constrained<T, C>
1596where
1597    T: Primitive,
1598    C: Constraint,
1599{
1600    type Output = OutputFor<Self>;
1601
1602    fn rem(self, other: T) -> Self::Output {
1603        self.map(|inner| inner % other)
1604    }
1605}
1606
1607impl<T, C, E> RemAssign for Constrained<T, C>
1608where
1609    T: Primitive,
1610    C: Constraint<Error = E>,
1611    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1612{
1613    fn rem_assign(&mut self, other: Self) {
1614        *self = *self % other;
1615    }
1616}
1617
1618impl<T, C, E> RemAssign<T> for Constrained<T, C>
1619where
1620    T: Primitive,
1621    C: Constraint<Error = E>,
1622    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1623{
1624    fn rem_assign(&mut self, other: T) {
1625        *self = self.map(|inner| inner % other);
1626    }
1627}
1628
1629impl<T, C, E> Signed for Constrained<T, C>
1630where
1631    T: Primitive + Signed,
1632    C: Constraint<Error = E>,
1633    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1634{
1635    fn abs(&self) -> Self {
1636        self.map_unchecked(|inner| Signed::abs(&inner))
1637    }
1638
1639    fn abs_sub(&self, other: &Self) -> Self {
1640        self.zip_map(*other, |a, b| Signed::abs_sub(&a, &b))
1641    }
1642
1643    fn signum(&self) -> Self {
1644        self.map_unchecked(|inner| Signed::signum(&inner))
1645    }
1646
1647    fn is_positive(&self) -> bool {
1648        Signed::is_positive(self.as_ref())
1649    }
1650
1651    fn is_negative(&self) -> bool {
1652        Signed::is_negative(self.as_ref())
1653    }
1654}
1655
1656impl<T, C> Sub for Constrained<T, C>
1657where
1658    T: Primitive,
1659    C: Constraint,
1660{
1661    type Output = OutputFor<Self>;
1662
1663    fn sub(self, other: Self) -> Self::Output {
1664        self.zip_map(other, Sub::sub)
1665    }
1666}
1667
1668impl<T, C> Sub<T> for Constrained<T, C>
1669where
1670    T: Primitive,
1671    C: Constraint,
1672{
1673    type Output = OutputFor<Self>;
1674
1675    fn sub(self, other: T) -> Self::Output {
1676        self.map(|inner| inner - other)
1677    }
1678}
1679
1680impl<T, C, E> SubAssign for Constrained<T, C>
1681where
1682    T: Primitive,
1683    C: Constraint<Error = E>,
1684    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1685{
1686    fn sub_assign(&mut self, other: Self) {
1687        *self = *self - other
1688    }
1689}
1690
1691impl<T, C, E> SubAssign<T> for Constrained<T, C>
1692where
1693    T: Primitive,
1694    C: Constraint<Error = E>,
1695    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1696{
1697    fn sub_assign(&mut self, other: T) {
1698        *self = self.map(|inner| inner - other)
1699    }
1700}
1701
1702impl<T, C, E> Sum for Constrained<T, C>
1703where
1704    T: Primitive,
1705    C: Constraint<Error = E>,
1706    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
1707{
1708    fn sum<I>(input: I) -> Self
1709    where
1710        I: Iterator<Item = Self>,
1711    {
1712        input.fold(UnaryRealFunction::ZERO, |a, b| a + b)
1713    }
1714}
1715
1716impl<T, C> ToCanonical for Constrained<T, C>
1717where
1718    T: Primitive,
1719{
1720    type Canonical = <T as ToCanonical>::Canonical;
1721
1722    fn to_canonical(self) -> Self::Canonical {
1723        self.inner.to_canonical()
1724    }
1725}
1726
1727impl<T, C> ToPrimitive for Constrained<T, C>
1728where
1729    T: Primitive + ToPrimitive,
1730{
1731    fn to_i8(&self) -> Option<i8> {
1732        self.as_ref().to_i8()
1733    }
1734
1735    fn to_u8(&self) -> Option<u8> {
1736        self.as_ref().to_u8()
1737    }
1738
1739    fn to_i16(&self) -> Option<i16> {
1740        self.as_ref().to_i16()
1741    }
1742
1743    fn to_u16(&self) -> Option<u16> {
1744        self.as_ref().to_u16()
1745    }
1746
1747    fn to_i32(&self) -> Option<i32> {
1748        self.as_ref().to_i32()
1749    }
1750
1751    fn to_u32(&self) -> Option<u32> {
1752        self.as_ref().to_u32()
1753    }
1754
1755    fn to_i64(&self) -> Option<i64> {
1756        self.as_ref().to_i64()
1757    }
1758
1759    fn to_u64(&self) -> Option<u64> {
1760        self.as_ref().to_u64()
1761    }
1762
1763    fn to_isize(&self) -> Option<isize> {
1764        self.as_ref().to_isize()
1765    }
1766
1767    fn to_usize(&self) -> Option<usize> {
1768        self.as_ref().to_usize()
1769    }
1770
1771    fn to_f32(&self) -> Option<f32> {
1772        self.as_ref().to_f32()
1773    }
1774
1775    fn to_f64(&self) -> Option<f64> {
1776        self.as_ref().to_f64()
1777    }
1778}
1779
1780#[cfg(feature = "serde")]
1781impl<T, C> TryFrom<Serde<T>> for Constrained<T, C>
1782where
1783    T: Primitive,
1784    C: Constraint,
1785{
1786    type Error = C::Error;
1787
1788    fn try_from(container: Serde<T>) -> Result<Self, Self::Error> {
1789        Self::try_new(container.inner)
1790    }
1791}
1792
1793#[cfg(feature = "approx")]
1794impl<T, C> UlpsEq for Constrained<T, C>
1795where
1796    T: Primitive + UlpsEq<Epsilon = T>,
1797    C: Constraint,
1798{
1799    fn default_max_ulps() -> u32 {
1800        T::default_max_ulps()
1801    }
1802
1803    fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
1804        self.into_inner()
1805            .ulps_eq(&other.into_inner(), epsilon.into_inner(), max_ulps)
1806    }
1807}
1808
1809impl<T, C> UnaryRealFunction for Constrained<T, C>
1810where
1811    T: Primitive,
1812    C: Constraint,
1813{
1814    const ZERO: Self = Constrained::unchecked(UnaryRealFunction::ZERO);
1815    const ONE: Self = Constrained::unchecked(UnaryRealFunction::ONE);
1816    const E: Self = Constrained::unchecked(UnaryRealFunction::E);
1817    const PI: Self = Constrained::unchecked(UnaryRealFunction::PI);
1818    const FRAC_1_PI: Self = Constrained::unchecked(UnaryRealFunction::FRAC_1_PI);
1819    const FRAC_2_PI: Self = Constrained::unchecked(UnaryRealFunction::FRAC_2_PI);
1820    const FRAC_2_SQRT_PI: Self = Constrained::unchecked(UnaryRealFunction::FRAC_2_SQRT_PI);
1821    const FRAC_PI_2: Self = Constrained::unchecked(UnaryRealFunction::FRAC_PI_2);
1822    const FRAC_PI_3: Self = Constrained::unchecked(UnaryRealFunction::FRAC_PI_3);
1823    const FRAC_PI_4: Self = Constrained::unchecked(UnaryRealFunction::FRAC_PI_4);
1824    const FRAC_PI_6: Self = Constrained::unchecked(UnaryRealFunction::FRAC_PI_6);
1825    const FRAC_PI_8: Self = Constrained::unchecked(UnaryRealFunction::FRAC_PI_8);
1826    const SQRT_2: Self = Constrained::unchecked(UnaryRealFunction::SQRT_2);
1827    const FRAC_1_SQRT_2: Self = Constrained::unchecked(UnaryRealFunction::FRAC_1_SQRT_2);
1828    const LN_2: Self = Constrained::unchecked(UnaryRealFunction::LN_2);
1829    const LN_10: Self = Constrained::unchecked(UnaryRealFunction::LN_10);
1830    const LOG2_E: Self = Constrained::unchecked(UnaryRealFunction::LOG2_E);
1831    const LOG10_E: Self = Constrained::unchecked(UnaryRealFunction::LOG10_E);
1832
1833    fn is_zero(self) -> bool {
1834        self.into_inner().is_zero()
1835    }
1836
1837    fn is_one(self) -> bool {
1838        self.into_inner().is_zero()
1839    }
1840
1841    fn sign(self) -> Sign {
1842        self.with_inner(|inner| inner.sign())
1843    }
1844
1845    #[cfg(feature = "std")]
1846    fn abs(self) -> Self {
1847        self.map_unchecked(UnaryRealFunction::abs)
1848    }
1849
1850    #[cfg(feature = "std")]
1851    fn floor(self) -> Self {
1852        self.map_unchecked(UnaryRealFunction::floor)
1853    }
1854
1855    #[cfg(feature = "std")]
1856    fn ceil(self) -> Self {
1857        self.map_unchecked(UnaryRealFunction::ceil)
1858    }
1859
1860    #[cfg(feature = "std")]
1861    fn round(self) -> Self {
1862        self.map_unchecked(UnaryRealFunction::round)
1863    }
1864
1865    #[cfg(feature = "std")]
1866    fn trunc(self) -> Self {
1867        self.map_unchecked(UnaryRealFunction::trunc)
1868    }
1869
1870    #[cfg(feature = "std")]
1871    fn fract(self) -> Self {
1872        self.map_unchecked(UnaryRealFunction::fract)
1873    }
1874
1875    fn recip(self) -> Self::Codomain {
1876        self.map(UnaryRealFunction::recip)
1877    }
1878
1879    #[cfg(feature = "std")]
1880    fn powi(self, n: i32) -> Self::Codomain {
1881        self.map(|inner| UnaryRealFunction::powi(inner, n))
1882    }
1883
1884    #[cfg(feature = "std")]
1885    fn sqrt(self) -> Self::Codomain {
1886        self.map(UnaryRealFunction::sqrt)
1887    }
1888
1889    #[cfg(feature = "std")]
1890    fn cbrt(self) -> Self {
1891        self.map_unchecked(UnaryRealFunction::cbrt)
1892    }
1893
1894    #[cfg(feature = "std")]
1895    fn exp(self) -> Self::Codomain {
1896        self.map(UnaryRealFunction::exp)
1897    }
1898
1899    #[cfg(feature = "std")]
1900    fn exp2(self) -> Self::Codomain {
1901        self.map(UnaryRealFunction::exp2)
1902    }
1903
1904    #[cfg(feature = "std")]
1905    fn exp_m1(self) -> Self::Codomain {
1906        self.map(UnaryRealFunction::exp_m1)
1907    }
1908
1909    #[cfg(feature = "std")]
1910    fn ln(self) -> Self::Codomain {
1911        self.map(UnaryRealFunction::ln)
1912    }
1913
1914    #[cfg(feature = "std")]
1915    fn log2(self) -> Self::Codomain {
1916        self.map(UnaryRealFunction::log2)
1917    }
1918
1919    #[cfg(feature = "std")]
1920    fn log10(self) -> Self::Codomain {
1921        self.map(UnaryRealFunction::log10)
1922    }
1923
1924    #[cfg(feature = "std")]
1925    fn ln_1p(self) -> Self::Codomain {
1926        self.map(UnaryRealFunction::ln_1p)
1927    }
1928
1929    #[cfg(feature = "std")]
1930    fn to_degrees(self) -> Self::Codomain {
1931        self.map(UnaryRealFunction::to_degrees)
1932    }
1933
1934    #[cfg(feature = "std")]
1935    fn to_radians(self) -> Self {
1936        self.map_unchecked(UnaryRealFunction::to_radians)
1937    }
1938
1939    #[cfg(feature = "std")]
1940    fn sin(self) -> Self {
1941        self.map_unchecked(UnaryRealFunction::sin)
1942    }
1943
1944    #[cfg(feature = "std")]
1945    fn cos(self) -> Self {
1946        self.map_unchecked(UnaryRealFunction::cos)
1947    }
1948
1949    #[cfg(feature = "std")]
1950    fn tan(self) -> Self::Codomain {
1951        self.map(UnaryRealFunction::tan)
1952    }
1953
1954    #[cfg(feature = "std")]
1955    fn asin(self) -> Self::Codomain {
1956        self.map(UnaryRealFunction::asin)
1957    }
1958
1959    #[cfg(feature = "std")]
1960    fn acos(self) -> Self::Codomain {
1961        self.map(UnaryRealFunction::acos)
1962    }
1963
1964    #[cfg(feature = "std")]
1965    fn atan(self) -> Self {
1966        self.map_unchecked(UnaryRealFunction::atan)
1967    }
1968
1969    #[cfg(feature = "std")]
1970    fn sin_cos(self) -> (Self, Self) {
1971        let (sin, cos) = self.into_inner().sin_cos();
1972        (Constrained::unchecked(sin), Constrained::unchecked(cos))
1973    }
1974
1975    #[cfg(feature = "std")]
1976    fn sinh(self) -> Self {
1977        self.map_unchecked(UnaryRealFunction::sinh)
1978    }
1979
1980    #[cfg(feature = "std")]
1981    fn cosh(self) -> Self {
1982        self.map_unchecked(UnaryRealFunction::cosh)
1983    }
1984
1985    #[cfg(feature = "std")]
1986    fn tanh(self) -> Self {
1987        self.map_unchecked(UnaryRealFunction::tanh)
1988    }
1989
1990    #[cfg(feature = "std")]
1991    fn asinh(self) -> Self::Codomain {
1992        self.map(UnaryRealFunction::asinh)
1993    }
1994
1995    #[cfg(feature = "std")]
1996    fn acosh(self) -> Self::Codomain {
1997        self.map(UnaryRealFunction::acosh)
1998    }
1999
2000    #[cfg(feature = "std")]
2001    fn atanh(self) -> Self::Codomain {
2002        self.map(UnaryRealFunction::atanh)
2003    }
2004}
2005
2006impl<T, C> UpperExp for Constrained<T, C>
2007where
2008    T: UpperExp,
2009{
2010    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
2011        self.as_ref().fmt(f)
2012    }
2013}
2014
2015impl<T, C, E> Zero for Constrained<T, C>
2016where
2017    T: Primitive,
2018    C: Constraint<Error = E>,
2019    divergence::ContinueFor<C::Divergence>: NonResidual<Self, E>,
2020{
2021    fn zero() -> Self {
2022        UnaryRealFunction::ZERO
2023    }
2024
2025    fn is_zero(&self) -> bool {
2026        self.as_ref().is_zero()
2027    }
2028}
2029
2030macro_rules! impl_binary_operation_for_proxy {
2031    () => {
2032        with_binary_operations!(impl_binary_operation_for_proxy);
2033    };
2034    (operation => $trait:ident :: $method:ident) => {
2035        impl_binary_operation_for_proxy!(operation => $trait :: $method, |left, right| {
2036            right.map(|inner| $trait::$method(left, inner))
2037        });
2038    };
2039    (operation => $trait:ident :: $method:ident, |$left:ident, $right:ident| $f:block) => {
2040        macro_rules! impl_primitive_binary_operation_for_proxy {
2041            (primitive => $t:ty) => {
2042                impl<C> $trait<Constrained<$t, C>> for $t
2043                where
2044                    C: Constraint,
2045                {
2046                    type Output = OutputFor<Constrained<$t, C>>;
2047
2048                    fn $method(self, other: Constrained<$t, C>) -> Self::Output {
2049                        let $left = self;
2050                        let $right = other;
2051                        $f
2052                    }
2053                }
2054            };
2055        }
2056        with_primitives!(impl_primitive_binary_operation_for_proxy);
2057    };
2058}
2059impl_binary_operation_for_proxy!();
2060
2061/// Implements the `Real` trait from [`num-traits`](https://crates.io/crates/num-traits) for
2062/// non-`NaN` proxy types. Does nothing if the `std` feature is disabled.
2063///
2064/// A blanket implementation is not possible, because it conflicts with a very general blanket
2065/// implementation provided by [`num-traits`]. See the following issues:
2066///
2067/// - https://github.com/olson-sean-k/decorum/issues/10
2068/// - https://github.com/rust-num/num-traits/issues/49
2069macro_rules! impl_num_traits_real_for_proxy {
2070    () => {
2071        with_primitives!(impl_num_traits_real_for_proxy);
2072    };
2073    (primitive => $t:ty) => {
2074        impl_num_traits_real_for_proxy!(proxy => Real, primitive => $t);
2075        impl_num_traits_real_for_proxy!(proxy => ExtendedReal, primitive => $t);
2076    };
2077    (proxy => $p:ident, primitive => $t:ty) => {
2078        #[cfg(feature = "std")]
2079        impl<D> num_traits::real::Real for $p<$t, D>
2080        where
2081            D: Divergence,
2082            divergence::ContinueFor<D>: NonResidual<Self, ErrorFor<Self>>,
2083        {
2084            fn max_value() -> Self {
2085                BaseEncoding::MAX_FINITE
2086            }
2087
2088            fn min_value() -> Self {
2089                BaseEncoding::MIN_FINITE
2090            }
2091
2092            fn min_positive_value() -> Self {
2093                BaseEncoding::MIN_POSITIVE_NORMAL
2094            }
2095
2096            fn epsilon() -> Self {
2097                BaseEncoding::EPSILON
2098            }
2099
2100            fn min(self, other: Self) -> Self {
2101                self.zip_map(other, num_traits::real::Real::min)
2102            }
2103
2104            fn max(self, other: Self) -> Self {
2105                self.zip_map(other, num_traits::real::Real::max)
2106            }
2107
2108            fn is_sign_positive(self) -> bool {
2109                self.with_inner(num_traits::real::Real::is_sign_positive)
2110            }
2111
2112            fn is_sign_negative(self) -> bool {
2113                self.with_inner(num_traits::real::Real::is_sign_negative)
2114            }
2115
2116            fn signum(self) -> Self {
2117                self.map(num_traits::real::Real::signum)
2118            }
2119
2120            fn abs(self) -> Self {
2121                self.map(num_traits::real::Real::abs)
2122            }
2123
2124            fn floor(self) -> Self {
2125                self.map(num_traits::real::Real::floor)
2126            }
2127
2128            fn ceil(self) -> Self {
2129                self.map(num_traits::real::Real::ceil)
2130            }
2131
2132            fn round(self) -> Self {
2133                self.map(num_traits::real::Real::round)
2134            }
2135
2136            fn trunc(self) -> Self {
2137                self.map(num_traits::real::Real::trunc)
2138            }
2139
2140            fn fract(self) -> Self {
2141                self.map(num_traits::real::Real::fract)
2142            }
2143
2144            fn recip(self) -> Self {
2145                self.map(num_traits::real::Real::recip)
2146            }
2147
2148            fn mul_add(self, a: Self, b: Self) -> Self {
2149                let a = a.into_inner();
2150                let b = b.into_inner();
2151                self.map(|inner| inner.mul_add(a, b))
2152            }
2153
2154            fn abs_sub(self, other: Self) -> Self {
2155                self.zip_map(other, num_traits::real::Real::abs_sub)
2156            }
2157
2158            fn powi(self, n: i32) -> Self {
2159                self.map(|inner| num_traits::real::Real::powi(inner, n))
2160            }
2161
2162            fn powf(self, n: Self) -> Self {
2163                self.zip_map(n, num_traits::real::Real::powf)
2164            }
2165
2166            fn sqrt(self) -> Self {
2167                self.map(num_traits::real::Real::sqrt)
2168            }
2169
2170            fn cbrt(self) -> Self {
2171                self.map(num_traits::real::Real::cbrt)
2172            }
2173
2174            fn exp(self) -> Self {
2175                self.map(num_traits::real::Real::exp)
2176            }
2177
2178            fn exp2(self) -> Self {
2179                self.map(num_traits::real::Real::exp2)
2180            }
2181
2182            fn exp_m1(self) -> Self {
2183                self.map(num_traits::real::Real::exp_m1)
2184            }
2185
2186            fn log(self, base: Self) -> Self {
2187                self.zip_map(base, num_traits::real::Real::log)
2188            }
2189
2190            fn ln(self) -> Self {
2191                self.map(num_traits::real::Real::ln)
2192            }
2193
2194            fn log2(self) -> Self {
2195                self.map(num_traits::real::Real::log2)
2196            }
2197
2198            fn log10(self) -> Self {
2199                self.map(num_traits::real::Real::log10)
2200            }
2201
2202            fn to_degrees(self) -> Self {
2203                self.map(num_traits::real::Real::to_degrees)
2204            }
2205
2206            fn to_radians(self) -> Self {
2207                self.map(num_traits::real::Real::to_radians)
2208            }
2209
2210            fn ln_1p(self) -> Self {
2211                self.map(num_traits::real::Real::ln_1p)
2212            }
2213
2214            fn hypot(self, other: Self) -> Self {
2215                self.zip_map(other, num_traits::real::Real::hypot)
2216            }
2217
2218            fn sin(self) -> Self {
2219                self.map(num_traits::real::Real::sin)
2220            }
2221
2222            fn cos(self) -> Self {
2223                self.map(num_traits::real::Real::cos)
2224            }
2225
2226            fn tan(self) -> Self {
2227                self.map(num_traits::real::Real::tan)
2228            }
2229
2230            fn asin(self) -> Self {
2231                self.map(num_traits::real::Real::asin)
2232            }
2233
2234            fn acos(self) -> Self {
2235                self.map(num_traits::real::Real::acos)
2236            }
2237
2238            fn atan(self) -> Self {
2239                self.map(num_traits::real::Real::atan)
2240            }
2241
2242            fn atan2(self, other: Self) -> Self {
2243                self.zip_map(other, num_traits::real::Real::atan2)
2244            }
2245
2246            fn sin_cos(self) -> (Self, Self) {
2247                let (sin, cos) = self.with_inner(num_traits::real::Real::sin_cos);
2248                ($p::<_, D>::new(sin), $p::<_, D>::new(cos))
2249            }
2250
2251            fn sinh(self) -> Self {
2252                self.map(num_traits::real::Real::sinh)
2253            }
2254
2255            fn cosh(self) -> Self {
2256                self.map(num_traits::real::Real::cosh)
2257            }
2258
2259            fn tanh(self) -> Self {
2260                self.map(num_traits::real::Real::tanh)
2261            }
2262
2263            fn asinh(self) -> Self {
2264                self.map(num_traits::real::Real::asinh)
2265            }
2266
2267            fn acosh(self) -> Self {
2268                self.map(num_traits::real::Real::acosh)
2269            }
2270
2271            fn atanh(self) -> Self {
2272                self.map(num_traits::real::Real::atanh)
2273            }
2274        }
2275    };
2276}
2277impl_num_traits_real_for_proxy!();
2278
2279// `TryFrom` cannot be implemented over an open type `T` and cannot be implemented for constraints
2280// in general, because it would conflict with the `From` implementation for `Total`.
2281macro_rules! impl_try_from_for_proxy {
2282    () => {
2283        with_primitives!(impl_try_from_for_proxy);
2284    };
2285    (primitive => $t:ty) => {
2286        impl_try_from_for_proxy!(proxy => Real, primitive => $t);
2287        impl_try_from_for_proxy!(proxy => ExtendedReal, primitive => $t);
2288    };
2289    (proxy => $p:ident, primitive => $t:ty) => {
2290        impl<D> TryFrom<$t> for $p<$t, D>
2291        where
2292            D: Divergence,
2293        {
2294            type Error = ErrorFor<Self>;
2295
2296            fn try_from(inner: $t) -> Result<Self, Self::Error> {
2297                Self::try_new(inner)
2298            }
2299        }
2300
2301        impl<'a, D> TryFrom<&'a $t> for &'a $p<$t, D>
2302        where
2303            D: Divergence,
2304        {
2305            type Error = ErrorFor<$p<$t, D>>;
2306
2307            fn try_from(inner: &'a $t) -> Result<Self, Self::Error> {
2308                ConstraintFor::<$p<$t, D>>::check(*inner).map(|_| {
2309                    // SAFETY: `Constrained<T>` is `repr(transparent)` and has the same binary
2310                    //         representation as its input type `T`. This means that it is safe to
2311                    //         transmute `T` to `Constrained<T>`.
2312                    unsafe { mem::transmute::<&'a $t, Self>(inner) }
2313                })
2314            }
2315        }
2316
2317        impl<'a, D> TryFrom<&'a mut $t> for &'a mut $p<$t, D>
2318        where
2319            D: Divergence,
2320        {
2321            type Error = ErrorFor<$p<$t, D>>;
2322
2323            fn try_from(inner: &'a mut $t) -> Result<Self, Self::Error> {
2324                ConstraintFor::<$p<$t, D>>::check(*inner).map(move |_| {
2325                    // SAFETY: `Constrained<T>` is `repr(transparent)` and has the same binary
2326                    //         representation as its input type `T`. This means that it is safe to
2327                    //         transmute `T` to `Constrained<T>`.
2328                    unsafe { mem::transmute::<&'a mut $t, Self>(inner) }
2329                })
2330            }
2331        }
2332    };
2333}
2334impl_try_from_for_proxy!();
2335
2336#[cfg(test)]
2337mod tests {
2338    use crate::real::RealFunction;
2339    use crate::{ExtendedReal, InfinityEncoding, NanEncoding, Real, Total, E32, R32};
2340
2341    #[test]
2342    fn total_no_panic_on_inf() {
2343        let x: Total<f32> = 1.0.into();
2344        let y = x / 0.0;
2345        assert!(InfinityEncoding::is_infinite(y));
2346    }
2347
2348    #[test]
2349    fn total_no_panic_on_nan() {
2350        let x: Total<f32> = 0.0.into();
2351        let y = x / 0.0;
2352        assert!(NanEncoding::is_nan(y));
2353    }
2354
2355    // This is the most comprehensive and general test of reference conversions, as there are no
2356    // failure conditions. Other similar tests focus solely on success or failure, not completeness
2357    // of the APIs under test. This test is an ideal Miri target.
2358    #[test]
2359    #[allow(clippy::eq_op)]
2360    #[allow(clippy::float_cmp)]
2361    #[allow(clippy::zero_divided_by_zero)]
2362    fn total_no_panic_from_ref_slice() {
2363        let x = 0.0f64 / 0.0;
2364        let y: &Total<_> = (&x).into();
2365        assert!(y.is_nan());
2366
2367        let mut x = 0.0f64;
2368        let y: &mut Total<_> = (&mut x).into();
2369        *y = (0.0f64 / 0.0).into();
2370        assert!(y.is_nan());
2371
2372        let xs = [0.0f64, 1.0];
2373        let ys = Total::from_slice(&xs);
2374        assert_eq!(ys, &[0.0f64, 1.0]);
2375
2376        let xs = [0.0f64, 1.0];
2377        let ys = Total::from_slice(&xs);
2378        assert_eq!(ys, &[0.0f64, 1.0]);
2379    }
2380
2381    #[test]
2382    fn notnan_no_panic_on_inf() {
2383        let x: E32 = 1.0.try_into().unwrap();
2384        let y = x / 0.0;
2385        assert!(InfinityEncoding::is_infinite(y));
2386    }
2387
2388    #[test]
2389    #[should_panic]
2390    fn notnan_panic_on_nan() {
2391        let x: E32 = 0.0.try_into().unwrap();
2392        let _ = x / 0.0;
2393    }
2394
2395    #[test]
2396    #[allow(clippy::eq_op)]
2397    #[allow(clippy::float_cmp)]
2398    fn notnan_no_panic_from_inf_ref_slice() {
2399        let x = 1.0f64 / 0.0;
2400        let y: &ExtendedReal<_> = (&x).try_into().unwrap();
2401        assert!(y.is_infinite());
2402
2403        let xs = [0.0f64, 1.0 / 0.0];
2404        let ys = ExtendedReal::<f64>::try_from_slice(&xs).unwrap();
2405        assert_eq!(ys, &[0.0f64, InfinityEncoding::INFINITY]);
2406    }
2407
2408    #[test]
2409    #[should_panic]
2410    #[allow(clippy::zero_divided_by_zero)]
2411    fn notnan_panic_from_nan_ref() {
2412        let x = 0.0f64 / 0.0;
2413        let _: &ExtendedReal<_> = (&x).try_into().unwrap();
2414    }
2415
2416    #[test]
2417    #[should_panic]
2418    #[allow(clippy::zero_divided_by_zero)]
2419    fn notnan_panic_from_nan_slice() {
2420        let xs = [1.0f64, 0.0f64 / 0.0];
2421        let _ = ExtendedReal::<f64>::try_from_slice(&xs).unwrap();
2422    }
2423
2424    #[test]
2425    #[should_panic]
2426    fn finite_panic_on_nan() {
2427        let x: R32 = 0.0.try_into().unwrap();
2428        let _ = x / 0.0;
2429    }
2430
2431    #[test]
2432    #[should_panic]
2433    fn finite_panic_on_inf() {
2434        let x: R32 = 1.0.try_into().unwrap();
2435        let _ = x / 0.0;
2436    }
2437
2438    #[test]
2439    #[should_panic]
2440    fn finite_panic_on_neg_inf() {
2441        let x: R32 = (-1.0).try_into().unwrap();
2442        let _ = x / 0.0;
2443    }
2444
2445    #[test]
2446    #[should_panic]
2447    fn finite_panic_from_inf_ref() {
2448        let x = 1.0f64 / 0.0;
2449        let _: &Real<_> = (&x).try_into().unwrap();
2450    }
2451
2452    #[test]
2453    #[should_panic]
2454    fn finite_panic_from_inf_slice() {
2455        let xs = [1.0f64, 1.0f64 / 0.0];
2456        let _ = Real::<f64>::try_from_slice(&xs).unwrap();
2457    }
2458
2459    #[test]
2460    #[allow(clippy::eq_op)]
2461    #[allow(clippy::float_cmp)]
2462    #[allow(clippy::zero_divided_by_zero)]
2463    fn total_nan_eq() {
2464        let x: Total<f32> = (0.0 / 0.0).into();
2465        let y: Total<f32> = (0.0 / 0.0).into();
2466        assert_eq!(x, y);
2467
2468        let z: Total<f32> =
2469            (<f32 as InfinityEncoding>::INFINITY + <f32 as InfinityEncoding>::NEG_INFINITY).into();
2470        assert_eq!(x, z);
2471
2472        #[cfg(feature = "std")]
2473        {
2474            use crate::real::UnaryRealFunction;
2475
2476            let w: Total<f32> = (UnaryRealFunction::sqrt(-1.0f32)).into();
2477            assert_eq!(x, w);
2478        }
2479    }
2480
2481    #[test]
2482    #[allow(clippy::eq_op)]
2483    #[allow(clippy::float_cmp)]
2484    #[allow(clippy::zero_divided_by_zero)]
2485    #[allow(invalid_nan_comparisons)]
2486    fn cmp_proxy_primitive() {
2487        // Compare a canonicalized `NaN` with a primitive `NaN` with a different representation.
2488        let x: Total<f32> = (0.0 / 0.0).into();
2489        assert_eq!(x, f32::sqrt(-1.0));
2490
2491        // Compare a canonicalized `INF` with a primitive `NaN`.
2492        let y: Total<f32> = (1.0 / 0.0).into();
2493        assert!(y < (0.0 / 0.0));
2494
2495        // Compare a proxy that disallows `INF` to a primitive `INF`.
2496        let z: R32 = 0.0.try_into().unwrap();
2497        assert_eq!(z.partial_cmp(&(1.0 / 0.0)), None);
2498    }
2499
2500    #[test]
2501    fn sum() {
2502        let xs = [
2503            1.0.try_into().unwrap(),
2504            2.0.try_into().unwrap(),
2505            3.0.try_into().unwrap(),
2506        ];
2507        assert_eq!(xs.iter().cloned().sum::<R32>(), R32::assert(6.0));
2508    }
2509
2510    #[test]
2511    fn product() {
2512        let xs = [
2513            1.0.try_into().unwrap(),
2514            2.0.try_into().unwrap(),
2515            3.0.try_into().unwrap(),
2516        ];
2517        assert_eq!(xs.iter().cloned().product::<R32>(), R32::assert(6.0),);
2518    }
2519
2520    // TODO: This test is questionable.
2521    #[test]
2522    fn impl_traits() {
2523        fn as_infinite<T>(_: T)
2524        where
2525            T: InfinityEncoding,
2526        {
2527        }
2528
2529        fn as_nan<T>(_: T)
2530        where
2531            T: NanEncoding,
2532        {
2533        }
2534
2535        fn as_real<T>(_: T)
2536        where
2537            T: RealFunction,
2538        {
2539        }
2540
2541        let finite = Real::<f32>::default();
2542        as_real(finite);
2543
2544        let notnan = ExtendedReal::<f32>::default();
2545        as_infinite(notnan);
2546        as_real(notnan);
2547
2548        let ordered = Total::<f32>::default();
2549        as_infinite(ordered);
2550        as_nan(ordered);
2551    }
2552
2553    #[test]
2554    fn fmt() {
2555        let x: Total<f32> = 1.0.into();
2556        format_args!("{0} {0:e} {0:E} {0:?} {0:#?}", x);
2557        let y: ExtendedReal<f32> = 1.0.try_into().unwrap();
2558        format_args!("{0} {0:e} {0:E} {0:?} {0:#?}", y);
2559        let z: Real<f32> = 1.0.try_into().unwrap();
2560        format_args!("{0} {0:e} {0:E} {0:?} {0:#?}", z);
2561    }
2562
2563    #[cfg(feature = "serde")]
2564    #[test]
2565    fn deserialize() {
2566        assert_eq!(
2567            R32::assert(1.0),
2568            serde_json::from_str::<R32>("1.0").unwrap()
2569        );
2570    }
2571
2572    #[cfg(feature = "serde")]
2573    #[test]
2574    #[should_panic]
2575    fn deserialize_panic_on_violation() {
2576        // TODO: See `Serde`. This does not test a value that violates `E32`'s constraints;
2577        //       instead, this simply fails to deserialize `f32` from `"null"`.
2578        let _: E32 = serde_json::from_str("null").unwrap();
2579    }
2580
2581    #[cfg(feature = "serde")]
2582    #[test]
2583    fn serialize() {
2584        use crate::divergence::OrPanic;
2585
2586        assert_eq!(
2587            "1.0",
2588            serde_json::to_string(&E32::<OrPanic>::assert(1.0)).unwrap()
2589        );
2590        // TODO: See `Serde`.
2591        assert_eq!(
2592            "null",
2593            serde_json::to_string(&E32::<OrPanic>::INFINITY).unwrap()
2594        );
2595    }
2596}