decorum/
expression.rs

1use core::cmp::Ordering;
2use core::convert::Infallible;
3use core::fmt::Debug;
4use core::hint;
5#[cfg(all(nightly, feature = "unstable"))]
6use core::ops::{self, ControlFlow, FromResidual};
7use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
8
9use crate::cmp::{self, EmptyOrd};
10use crate::constraint::{Constraint, Member, NanSet};
11use crate::divergence::{AsExpression, Divergence, OrError};
12use crate::proxy::{Constrained, ErrorFor, ExpressionFor};
13use crate::real::{BinaryRealFunction, Function, Sign, UnaryRealFunction};
14use crate::{with_binary_operations, with_primitives, InfinityEncoding, NanEncoding, Primitive};
15
16pub use Expression::Defined;
17pub use Expression::Undefined;
18
19/// Unwraps an [`Expression`] or propagates its error.
20///
21/// This macro mirrors the standard [`try`] macro but operates on [`Expression`]s rather than
22/// [`Result`]s. If the given [`Expression`] is the `Defined` variant, then the expression (of the
23/// macro) is the accompanying value. Otherwise, the error in the `Undefined` variant is converted
24/// via [`From`] and returned in the constructed [`Expression`].
25#[macro_export]
26macro_rules! try_expression {
27    ($x:expr $(,)?) => {{
28        let expression: $crate::expression::Expression<_, _> = $x;
29        match expression {
30            $crate::expression::Expression::Defined(inner) => inner,
31            $crate::expression::Expression::Undefined(error) => {
32                return $crate::expression::Expression::Undefined(core::convert::From::from(error));
33            }
34        }
35    }};
36    ($x:block $(,)?) => {
37        let expression: $crate::expression::Expression<_, _> = $x;
38        try_expression!(expression);
39    };
40}
41pub use try_expression;
42
43/// The result of an arithmetic expression that may or may not be defined.
44///
45/// `Expression` is a fallible output of arithmetic expressions over [`Constrained`] types. It
46/// resembles [`Result`], but `Expression` crucially implements numeric traits and can be used in
47/// arithmetic expressions. This allows complex expressions to defer matching or trying for more
48/// fluent syntax.
49///
50/// When the `unstable` Cargo feature is enabled with a nightly Rust toolchain, [`Expression`] also
51/// implements the unstable (at time of writing) [`Try`] trait and supports the try operator `?`.
52///
53/// # Examples
54///
55/// The following two examples contrast deferred matching and trying of `Expression`s versus
56/// immediate matching and trying of `Result`s.
57///
58/// ```rust
59/// use decorum::constraint::IsReal;
60/// use decorum::divergence::OrError;
61/// use decorum::proxy::{Constrained, OutputFor};
62/// use decorum::real::UnaryRealFunction;
63/// use decorum::try_expression;
64///
65/// pub type Real = Constrained<f64, IsReal<OrError>>;
66/// pub type Expr = OutputFor<Real>;
67///
68/// # fn fallible() -> Expr {
69/// fn f(x: Real, y: Real, z: Real) -> Expr {
70///     let w = (x + y + z);
71///     w / Real::ONE
72/// }
73///
74/// let x = Real::ONE;
75/// let y: Real = try_expression!(f(x, x, x));
76/// // ...
77/// # f(x, x, x)
78/// # }
79/// ```
80///
81/// ```rust
82/// use decorum::constraint::IsReal;
83/// use decorum::divergence::{AsResult, OrError};
84/// use decorum::proxy::{Constrained, OutputFor};
85/// use decorum::real::UnaryRealFunction;
86///
87/// pub type Real = Constrained<f64, IsReal<OrError<AsResult>>>;
88/// pub type RealResult = OutputFor<Real>;
89///
90/// # fn fallible() -> RealResult {
91/// fn f(x: Real, y: Real, z: Real) -> RealResult {
92///     // The expression `x + y` outputs a `Result`, which cannot be used in a mathematical
93///     // expression, so it must be tried first.
94///     let w = ((x + y)? + z)?;
95///     w / Real::ONE
96/// }
97///
98/// let x = Real::ONE;
99/// let y: Real = f(x, x, x)?;
100/// // ...
101/// # f(x, x, x)
102/// # }
103/// ```
104///
105/// When the `unstable` Cargo feature is enabled with a nightly Rust toolchain, `Expression`
106/// supports the try operator `?`.
107///
108/// ```rust,ignore
109/// use decorum::constraint::IsReal;
110/// use decorum::divergence::{AsExpression, OrError};
111/// use decorum::proxy::{Constrained, OutputFor};
112/// use decorum::real::UnaryRealFunction;
113///
114/// pub type Real = Constrained<f64, IsReal<OrError<AsExpression>>>;
115/// pub type Expr = OutputFor<Real>;
116///
117/// # fn fallible() -> Expr {
118/// fn f(x: Real, y: Real, z: Real) -> Expr {
119///     let w = (x + y + z)?; // Try.
120///     eprintln!("x + y + z => defined!");
121///     w / Real::ONE
122/// }
123///
124/// let x = Real::ONE;
125/// let y = Real::ZERO;
126/// let z = f(x, y, x)?; // Try.
127/// eprintln!("f(x, y, x) => defined!");
128/// // ...
129/// # f(x, y, x)
130/// # }
131/// ```
132///
133/// [`Try`]: core::ops::Try
134#[derive(Clone, Copy, Debug)]
135pub enum Expression<T, E = ()> {
136    Defined(T),
137    Undefined(E),
138}
139
140impl<T, E> Expression<T, E> {
141    pub fn unwrap(self) -> T {
142        match self {
143            Defined(defined) => defined,
144            _ => panic!(),
145        }
146    }
147
148    pub fn as_ref(&self) -> Expression<&T, &E> {
149        match self {
150            Defined(ref defined) => Defined(defined),
151            Undefined(ref undefined) => Undefined(undefined),
152        }
153    }
154
155    pub fn map<U, F>(self, f: F) -> Expression<U, E>
156    where
157        F: FnOnce(T) -> U,
158    {
159        match self {
160            Defined(defined) => Defined(f(defined)),
161            Undefined(undefined) => Undefined(undefined),
162        }
163    }
164
165    pub fn and_then<U, F>(self, f: F) -> Expression<U, E>
166    where
167        F: FnOnce(T) -> Expression<U, E>,
168    {
169        match self {
170            Defined(defined) => f(defined),
171            Undefined(undefined) => Undefined(undefined),
172        }
173    }
174
175    pub fn defined(self) -> Option<T> {
176        match self {
177            Defined(defined) => Some(defined),
178            _ => None,
179        }
180    }
181
182    pub fn undefined(self) -> Option<E> {
183        match self {
184            Undefined(undefined) => Some(undefined),
185            _ => None,
186        }
187    }
188
189    pub fn is_defined(&self) -> bool {
190        matches!(self, Defined(_))
191    }
192
193    pub fn is_undefined(&self) -> bool {
194        matches!(self, Undefined(_))
195    }
196}
197
198impl<T, E> Expression<&'_ T, E> {
199    pub fn copied(self) -> Expression<T, E>
200    where
201        T: Copy,
202    {
203        match self {
204            Defined(defined) => Defined(*defined),
205            Undefined(undefined) => Undefined(undefined),
206        }
207    }
208
209    pub fn cloned(self) -> Expression<T, E>
210    where
211        T: Clone,
212    {
213        match self {
214            Defined(defined) => Defined(defined.clone()),
215            Undefined(undefined) => Undefined(undefined),
216        }
217    }
218}
219
220impl<T, E> Expression<&'_ mut T, E> {
221    pub fn copied(self) -> Expression<T, E>
222    where
223        T: Copy,
224    {
225        match self {
226            Defined(defined) => Defined(*defined),
227            Undefined(undefined) => Undefined(undefined),
228        }
229    }
230
231    pub fn cloned(self) -> Expression<T, E>
232    where
233        T: Clone,
234    {
235        match self {
236            Defined(defined) => Defined(defined.clone()),
237            Undefined(undefined) => Undefined(undefined),
238        }
239    }
240}
241
242impl<T> Expression<T, Infallible> {
243    pub fn into_defined(self) -> T {
244        #[allow(unreachable_patterns)]
245        match self {
246            Defined(defined) => defined,
247            // SAFETY: `Infallible` is uninhabited, so it is not possible to construct the
248            //         `Undefined` variant here.
249            Undefined(_) => unsafe { hint::unreachable_unchecked() },
250        }
251    }
252
253    pub fn get(&self) -> &T {
254        #[allow(unreachable_patterns)]
255        match self {
256            Defined(ref defined) => defined,
257            // SAFETY: `Infallible` is uninhabited, so it is not possible to construct the
258            //         `Undefined` variant here.
259            Undefined(_) => unsafe { hint::unreachable_unchecked() },
260        }
261    }
262}
263
264impl<E> Expression<Infallible, E> {
265    pub fn into_undefined(self) -> E {
266        #[allow(unreachable_patterns)]
267        match self {
268            Undefined(undefined) => undefined,
269            // SAFETY: `Infallible` is uninhabited, so it is not possible to construct the
270            //         `Defined` variant here.
271            Defined(_) => unsafe { hint::unreachable_unchecked() },
272        }
273    }
274}
275
276impl<T, C> BinaryRealFunction for ExpressionFor<Constrained<T, C>>
277where
278    ErrorFor<Constrained<T, C>>: Clone + cmp::EmptyInhabitant,
279    T: Primitive,
280    C: Constraint,
281    C::Divergence: Divergence<Continue = AsExpression>,
282{
283    #[cfg(feature = "std")]
284    fn div_euclid(self, n: Self) -> Self::Codomain {
285        BinaryRealFunction::div_euclid(try_expression!(self), try_expression!(n))
286    }
287
288    #[cfg(feature = "std")]
289    fn rem_euclid(self, n: Self) -> Self::Codomain {
290        BinaryRealFunction::rem_euclid(try_expression!(self), try_expression!(n))
291    }
292
293    #[cfg(feature = "std")]
294    fn pow(self, n: Self) -> Self::Codomain {
295        BinaryRealFunction::pow(try_expression!(self), try_expression!(n))
296    }
297
298    #[cfg(feature = "std")]
299    fn log(self, base: Self) -> Self::Codomain {
300        BinaryRealFunction::log(try_expression!(self), try_expression!(base))
301    }
302
303    #[cfg(feature = "std")]
304    fn hypot(self, other: Self) -> Self::Codomain {
305        BinaryRealFunction::hypot(try_expression!(self), try_expression!(other))
306    }
307
308    #[cfg(feature = "std")]
309    fn atan2(self, other: Self) -> Self::Codomain {
310        BinaryRealFunction::atan2(try_expression!(self), try_expression!(other))
311    }
312}
313
314impl<T, C> BinaryRealFunction<T> for ExpressionFor<Constrained<T, C>>
315where
316    ErrorFor<Constrained<T, C>>: Clone + cmp::EmptyInhabitant,
317    T: Primitive,
318    C: Constraint,
319    C::Divergence: Divergence<Continue = AsExpression>,
320{
321    #[cfg(feature = "std")]
322    fn div_euclid(self, n: T) -> Self::Codomain {
323        BinaryRealFunction::div_euclid(
324            try_expression!(self),
325            try_expression!(Constrained::<T, C>::new(n)),
326        )
327    }
328
329    #[cfg(feature = "std")]
330    fn rem_euclid(self, n: T) -> Self::Codomain {
331        BinaryRealFunction::rem_euclid(
332            try_expression!(self),
333            try_expression!(Constrained::<T, C>::new(n)),
334        )
335    }
336
337    #[cfg(feature = "std")]
338    fn pow(self, n: T) -> Self::Codomain {
339        BinaryRealFunction::pow(
340            try_expression!(self),
341            try_expression!(Constrained::<T, C>::new(n)),
342        )
343    }
344
345    #[cfg(feature = "std")]
346    fn log(self, base: T) -> Self::Codomain {
347        BinaryRealFunction::log(
348            try_expression!(self),
349            try_expression!(Constrained::<T, C>::new(base)),
350        )
351    }
352
353    #[cfg(feature = "std")]
354    fn hypot(self, other: T) -> Self::Codomain {
355        BinaryRealFunction::hypot(
356            try_expression!(self),
357            try_expression!(Constrained::<T, C>::new(other)),
358        )
359    }
360
361    #[cfg(feature = "std")]
362    fn atan2(self, other: T) -> Self::Codomain {
363        BinaryRealFunction::atan2(
364            try_expression!(self),
365            try_expression!(Constrained::<T, C>::new(other)),
366        )
367    }
368}
369
370impl<T, C> BinaryRealFunction<Constrained<T, C>> for ExpressionFor<Constrained<T, C>>
371where
372    ErrorFor<Constrained<T, C>>: Clone + cmp::EmptyInhabitant,
373    T: Primitive,
374    C: Constraint,
375    C::Divergence: Divergence<Continue = AsExpression>,
376{
377    #[cfg(feature = "std")]
378    fn div_euclid(self, n: Constrained<T, C>) -> Self::Codomain {
379        BinaryRealFunction::div_euclid(try_expression!(self), n)
380    }
381
382    #[cfg(feature = "std")]
383    fn rem_euclid(self, n: Constrained<T, C>) -> Self::Codomain {
384        BinaryRealFunction::rem_euclid(try_expression!(self), n)
385    }
386
387    #[cfg(feature = "std")]
388    fn pow(self, n: Constrained<T, C>) -> Self::Codomain {
389        BinaryRealFunction::pow(try_expression!(self), n)
390    }
391
392    #[cfg(feature = "std")]
393    fn log(self, base: Constrained<T, C>) -> Self::Codomain {
394        BinaryRealFunction::log(try_expression!(self), base)
395    }
396
397    #[cfg(feature = "std")]
398    fn hypot(self, other: Constrained<T, C>) -> Self::Codomain {
399        BinaryRealFunction::hypot(try_expression!(self), other)
400    }
401
402    #[cfg(feature = "std")]
403    fn atan2(self, other: Constrained<T, C>) -> Self::Codomain {
404        BinaryRealFunction::atan2(try_expression!(self), other)
405    }
406}
407
408impl<T, C> BinaryRealFunction<ExpressionFor<Constrained<T, C>>> for Constrained<T, C>
409where
410    ErrorFor<Constrained<T, C>>: Clone + cmp::EmptyInhabitant,
411    T: Primitive,
412    C: Constraint,
413    C::Divergence: Divergence<Continue = AsExpression>,
414{
415    #[cfg(feature = "std")]
416    fn div_euclid(self, n: ExpressionFor<Constrained<T, C>>) -> Self::Codomain {
417        BinaryRealFunction::div_euclid(self, try_expression!(n))
418    }
419
420    #[cfg(feature = "std")]
421    fn rem_euclid(self, n: ExpressionFor<Constrained<T, C>>) -> Self::Codomain {
422        BinaryRealFunction::rem_euclid(self, try_expression!(n))
423    }
424
425    #[cfg(feature = "std")]
426    fn pow(self, n: ExpressionFor<Constrained<T, C>>) -> Self::Codomain {
427        BinaryRealFunction::pow(self, try_expression!(n))
428    }
429
430    #[cfg(feature = "std")]
431    fn log(self, base: ExpressionFor<Constrained<T, C>>) -> Self::Codomain {
432        BinaryRealFunction::log(self, try_expression!(base))
433    }
434
435    #[cfg(feature = "std")]
436    fn hypot(self, other: ExpressionFor<Constrained<T, C>>) -> Self::Codomain {
437        BinaryRealFunction::hypot(self, try_expression!(other))
438    }
439
440    #[cfg(feature = "std")]
441    fn atan2(self, other: ExpressionFor<Constrained<T, C>>) -> Self::Codomain {
442        BinaryRealFunction::atan2(self, try_expression!(other))
443    }
444}
445
446impl<T, C> From<T> for Expression<Constrained<T, C>, ErrorFor<Constrained<T, C>>>
447where
448    T: Primitive,
449    C: Constraint,
450{
451    fn from(inner: T) -> Self {
452        Constrained::try_new(inner).into()
453    }
454}
455
456impl<'a, T, C> From<&'a T> for ExpressionFor<Constrained<T, C>>
457where
458    Constrained<T, C>: TryFrom<&'a T, Error = C::Error>,
459    T: Primitive,
460    C: Constraint<Divergence = OrError<AsExpression>>,
461{
462    fn from(inner: &'a T) -> Self {
463        Constrained::<T, C>::try_from(inner).into()
464    }
465}
466
467impl<'a, T, C> From<&'a mut T> for ExpressionFor<Constrained<T, C>>
468where
469    Constrained<T, C>: TryFrom<&'a mut T, Error = C::Error>,
470    T: Primitive,
471    C: Constraint<Divergence = OrError<AsExpression>>,
472{
473    fn from(inner: &'a mut T) -> Self {
474        Constrained::<T, C>::try_from(inner).into()
475    }
476}
477
478impl<T, C> From<Constrained<T, C>> for Expression<Constrained<T, C>, ErrorFor<Constrained<T, C>>>
479where
480    T: Primitive,
481    C: Constraint,
482{
483    fn from(proxy: Constrained<T, C>) -> Self {
484        Defined(proxy)
485    }
486}
487
488impl<T, E> From<Result<T, E>> for Expression<T, E> {
489    fn from(result: Result<T, E>) -> Self {
490        match result {
491            Ok(output) => Defined(output),
492            Err(error) => Undefined(error),
493        }
494    }
495}
496
497impl<T, E> From<Expression<T, E>> for Result<T, E> {
498    fn from(result: Expression<T, E>) -> Self {
499        match result {
500            Defined(defined) => Ok(defined),
501            Undefined(undefined) => Err(undefined),
502        }
503    }
504}
505
506#[cfg(all(nightly, feature = "unstable"))]
507impl<T, E> FromResidual for Expression<T, E> {
508    fn from_residual(residual: Expression<Infallible, E>) -> Self {
509        Undefined(residual.into_undefined())
510    }
511}
512
513impl<T, C> Function for ExpressionFor<Constrained<T, C>>
514where
515    ErrorFor<Constrained<T, C>>: cmp::EmptyInhabitant,
516    T: Primitive,
517    C: Constraint,
518    C::Divergence: Divergence<Continue = AsExpression>,
519{
520    type Codomain = Self;
521}
522
523impl<T, C> InfinityEncoding for ExpressionFor<Constrained<T, C>>
524where
525    ErrorFor<Constrained<T, C>>: Copy,
526    Constrained<T, C>: InfinityEncoding,
527    T: Primitive,
528    C: Constraint,
529    C::Divergence: Divergence<Continue = AsExpression>,
530{
531    const INFINITY: Self = Defined(InfinityEncoding::INFINITY);
532    const NEG_INFINITY: Self = Defined(InfinityEncoding::NEG_INFINITY);
533
534    fn is_infinite(self) -> bool {
535        self.defined().is_some_and(InfinityEncoding::is_infinite)
536    }
537
538    fn is_finite(self) -> bool {
539        self.defined().is_some_and(InfinityEncoding::is_finite)
540    }
541}
542
543impl<T, C> EmptyOrd for ExpressionFor<Constrained<T, C>>
544where
545    T: Primitive,
546    C: Constraint<Error = Infallible> + Member<NanSet>,
547{
548    type Empty = Self;
549
550    #[inline(always)]
551    fn from_empty(empty: <Self as EmptyOrd>::Empty) -> Self {
552        empty
553    }
554
555    fn is_empty(&self) -> bool {
556        self.get().is_nan()
557    }
558
559    fn cmp_empty(&self, other: &Self) -> Result<Ordering, <Self as EmptyOrd>::Empty> {
560        match (self.is_undefined(), other.is_undefined()) {
561            (true, _) => Err(*self),
562            (_, true) => Err(*other),
563            (false, false) => Ok(self.get().cmp(other.get())),
564        }
565    }
566}
567
568impl<T, C> Neg for ExpressionFor<Constrained<T, C>>
569where
570    T: Primitive,
571    C: Constraint,
572    C::Divergence: Divergence<Continue = AsExpression>,
573{
574    type Output = Self;
575
576    fn neg(self) -> Self::Output {
577        self.map(|defined| -defined)
578    }
579}
580
581impl<T, E> PartialEq for Expression<T, E>
582where
583    T: PartialEq,
584{
585    fn eq(&self, other: &Self) -> bool {
586        self.as_ref()
587            .defined()
588            .zip(other.as_ref().defined())
589            .is_some_and(|(left, right)| left.eq(right))
590    }
591}
592
593impl<T, E> PartialOrd for Expression<T, E>
594where
595    T: PartialOrd,
596{
597    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
598        self.as_ref()
599            .defined()
600            .zip(other.as_ref().defined())
601            .and_then(|(left, right)| left.partial_cmp(right))
602    }
603}
604
605#[cfg(all(nightly, feature = "unstable"))]
606impl<T, E> ops::Try for Expression<T, E> {
607    type Output = T;
608    type Residual = Expression<Infallible, E>;
609
610    fn from_output(output: T) -> Self {
611        Defined(output)
612    }
613
614    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
615        match self {
616            Defined(defined) => ControlFlow::Continue(defined),
617            Undefined(undefined) => ControlFlow::Break(Undefined(undefined)),
618        }
619    }
620}
621
622impl<T, C> UnaryRealFunction for ExpressionFor<Constrained<T, C>>
623where
624    ErrorFor<Constrained<T, C>>: Clone + cmp::EmptyInhabitant,
625    T: Primitive,
626    C: Constraint,
627    C::Divergence: Divergence<Continue = AsExpression>,
628{
629    const ZERO: Self = Defined(UnaryRealFunction::ZERO);
630    const ONE: Self = Defined(UnaryRealFunction::ONE);
631    const E: Self = Defined(UnaryRealFunction::E);
632    const PI: Self = Defined(UnaryRealFunction::PI);
633    const FRAC_1_PI: Self = Defined(UnaryRealFunction::FRAC_1_PI);
634    const FRAC_2_PI: Self = Defined(UnaryRealFunction::FRAC_2_PI);
635    const FRAC_2_SQRT_PI: Self = Defined(UnaryRealFunction::FRAC_2_SQRT_PI);
636    const FRAC_PI_2: Self = Defined(UnaryRealFunction::FRAC_PI_2);
637    const FRAC_PI_3: Self = Defined(UnaryRealFunction::FRAC_PI_3);
638    const FRAC_PI_4: Self = Defined(UnaryRealFunction::FRAC_PI_4);
639    const FRAC_PI_6: Self = Defined(UnaryRealFunction::FRAC_PI_6);
640    const FRAC_PI_8: Self = Defined(UnaryRealFunction::FRAC_PI_8);
641    const SQRT_2: Self = Defined(UnaryRealFunction::SQRT_2);
642    const FRAC_1_SQRT_2: Self = Defined(UnaryRealFunction::FRAC_1_SQRT_2);
643    const LN_2: Self = Defined(UnaryRealFunction::LN_2);
644    const LN_10: Self = Defined(UnaryRealFunction::LN_10);
645    const LOG2_E: Self = Defined(UnaryRealFunction::LOG2_E);
646    const LOG10_E: Self = Defined(UnaryRealFunction::LOG10_E);
647
648    fn is_zero(self) -> bool {
649        self.defined().is_some_and(UnaryRealFunction::is_zero)
650    }
651
652    fn is_one(self) -> bool {
653        self.defined().is_some_and(UnaryRealFunction::is_one)
654    }
655
656    fn sign(self) -> Sign {
657        self.defined().map_or(Sign::Zero, |defined| defined.sign())
658    }
659
660    #[cfg(feature = "std")]
661    fn abs(self) -> Self {
662        self.map(UnaryRealFunction::abs)
663    }
664
665    #[cfg(feature = "std")]
666    fn floor(self) -> Self {
667        self.map(UnaryRealFunction::floor)
668    }
669
670    #[cfg(feature = "std")]
671    fn ceil(self) -> Self {
672        self.map(UnaryRealFunction::ceil)
673    }
674
675    #[cfg(feature = "std")]
676    fn round(self) -> Self {
677        self.map(UnaryRealFunction::round)
678    }
679
680    #[cfg(feature = "std")]
681    fn trunc(self) -> Self {
682        self.map(UnaryRealFunction::trunc)
683    }
684
685    #[cfg(feature = "std")]
686    fn fract(self) -> Self {
687        self.map(UnaryRealFunction::fract)
688    }
689
690    fn recip(self) -> Self::Codomain {
691        self.and_then(UnaryRealFunction::recip)
692    }
693
694    #[cfg(feature = "std")]
695    fn powi(self, n: i32) -> Self::Codomain {
696        self.and_then(|defined| UnaryRealFunction::powi(defined, n))
697    }
698
699    #[cfg(feature = "std")]
700    fn sqrt(self) -> Self::Codomain {
701        self.and_then(UnaryRealFunction::sqrt)
702    }
703
704    #[cfg(feature = "std")]
705    fn cbrt(self) -> Self {
706        self.map(UnaryRealFunction::cbrt)
707    }
708
709    #[cfg(feature = "std")]
710    fn exp(self) -> Self::Codomain {
711        self.and_then(UnaryRealFunction::exp)
712    }
713
714    #[cfg(feature = "std")]
715    fn exp2(self) -> Self::Codomain {
716        self.and_then(UnaryRealFunction::exp2)
717    }
718
719    #[cfg(feature = "std")]
720    fn exp_m1(self) -> Self::Codomain {
721        self.and_then(UnaryRealFunction::exp_m1)
722    }
723
724    #[cfg(feature = "std")]
725    fn ln(self) -> Self::Codomain {
726        self.and_then(UnaryRealFunction::ln)
727    }
728
729    #[cfg(feature = "std")]
730    fn log2(self) -> Self::Codomain {
731        self.and_then(UnaryRealFunction::log2)
732    }
733
734    #[cfg(feature = "std")]
735    fn log10(self) -> Self::Codomain {
736        self.and_then(UnaryRealFunction::log10)
737    }
738
739    #[cfg(feature = "std")]
740    fn ln_1p(self) -> Self::Codomain {
741        self.and_then(UnaryRealFunction::ln_1p)
742    }
743
744    #[cfg(feature = "std")]
745    fn to_degrees(self) -> Self::Codomain {
746        self.and_then(UnaryRealFunction::to_degrees)
747    }
748
749    #[cfg(feature = "std")]
750    fn to_radians(self) -> Self {
751        self.map(UnaryRealFunction::to_radians)
752    }
753
754    #[cfg(feature = "std")]
755    fn sin(self) -> Self {
756        self.map(UnaryRealFunction::sin)
757    }
758
759    #[cfg(feature = "std")]
760    fn cos(self) -> Self {
761        self.map(UnaryRealFunction::cos)
762    }
763
764    #[cfg(feature = "std")]
765    fn tan(self) -> Self::Codomain {
766        self.and_then(UnaryRealFunction::tan)
767    }
768
769    #[cfg(feature = "std")]
770    fn asin(self) -> Self::Codomain {
771        self.and_then(UnaryRealFunction::asin)
772    }
773
774    #[cfg(feature = "std")]
775    fn acos(self) -> Self::Codomain {
776        self.and_then(UnaryRealFunction::acos)
777    }
778
779    #[cfg(feature = "std")]
780    fn atan(self) -> Self {
781        self.map(UnaryRealFunction::atan)
782    }
783
784    #[cfg(feature = "std")]
785    fn sin_cos(self) -> (Self, Self) {
786        match self {
787            Defined(defined) => {
788                let (sin, cos) = defined.sin_cos();
789                (Defined(sin), Defined(cos))
790            }
791            Undefined(undefined) => (Undefined(undefined.clone()), Undefined(undefined)),
792        }
793    }
794
795    #[cfg(feature = "std")]
796    fn sinh(self) -> Self {
797        self.map(UnaryRealFunction::sinh)
798    }
799
800    #[cfg(feature = "std")]
801    fn cosh(self) -> Self {
802        self.map(UnaryRealFunction::cosh)
803    }
804
805    #[cfg(feature = "std")]
806    fn tanh(self) -> Self {
807        self.map(UnaryRealFunction::tanh)
808    }
809
810    #[cfg(feature = "std")]
811    fn asinh(self) -> Self::Codomain {
812        self.and_then(UnaryRealFunction::asinh)
813    }
814
815    #[cfg(feature = "std")]
816    fn acosh(self) -> Self::Codomain {
817        self.and_then(UnaryRealFunction::acosh)
818    }
819
820    #[cfg(feature = "std")]
821    fn atanh(self) -> Self::Codomain {
822        self.and_then(UnaryRealFunction::atanh)
823    }
824}
825
826impl<T, E> cmp::EmptyInhabitant for Expression<T, E>
827where
828    E: cmp::EmptyInhabitant,
829{
830    #[inline(always)]
831    fn empty() -> Self {
832        Expression::Undefined(E::empty())
833    }
834}
835
836macro_rules! impl_binary_operation_for_expression {
837    () => {
838        with_binary_operations!(impl_binary_operation_for_expression);
839    };
840    (operation => $trait:ident :: $method:ident) => {
841        impl_binary_operation_for_expression!(operation => $trait :: $method, |left, right| {
842            left.zip_map(right, $trait::$method)
843        });
844    };
845    (operation => $trait:ident :: $method:ident, |$left:ident, $right:ident| $f:block) => {
846        macro_rules! impl_primitive_binary_operation_for_expression {
847            () => {
848                with_primitives!(impl_primitive_binary_operation_for_expression);
849            };
850            (primitive => $t:ty) => {
851                impl<C> $trait<ExpressionFor<Constrained<$t, C>>> for $t
852                where
853                    C: Constraint,
854                    C::Divergence: Divergence<Continue = AsExpression>,
855                {
856                    type Output = ExpressionFor<Constrained<$t, C>>;
857
858                    fn $method(self, other: ExpressionFor<Constrained<$t, C>>) -> Self::Output {
859                        let $left = try_expression!(Constrained::<_, C>::new(self));
860                        let $right = try_expression!(other);
861                        $f
862                    }
863                }
864            };
865        }
866        impl_primitive_binary_operation_for_expression!();
867
868        impl<T, C> $trait<ExpressionFor<Self>> for Constrained<T, C>
869        where
870            T: Primitive,
871            C: Constraint,
872            C::Divergence: Divergence<Continue = AsExpression>,
873        {
874            type Output = ExpressionFor<Self>;
875
876            fn $method(self, other: ExpressionFor<Self>) -> Self::Output {
877                let $left = self;
878                let $right = try_expression!(other);
879                $f
880            }
881        }
882
883        impl<T, C> $trait<Constrained<T, C>> for ExpressionFor<Constrained<T, C>>
884        where
885            T: Primitive,
886            C: Constraint,
887            C::Divergence: Divergence<Continue = AsExpression>,
888        {
889            type Output = Self;
890
891            fn $method(self, other: Constrained<T, C>) -> Self::Output {
892                let $left = try_expression!(self);
893                let $right = other;
894                $f
895            }
896        }
897
898        impl<T, C> $trait<ExpressionFor<Constrained<T, C>>> for ExpressionFor<Constrained<T, C>>
899        where
900            T: Primitive,
901            C: Constraint,
902            C::Divergence: Divergence<Continue = AsExpression>,
903        {
904            type Output = Self;
905
906            fn $method(self, other: Self) -> Self::Output {
907                let $left = try_expression!(self);
908                let $right = try_expression!(other);
909                $f
910            }
911        }
912
913        impl<T, C> $trait<T> for ExpressionFor<Constrained<T, C>>
914        where
915            T: Primitive,
916            C: Constraint,
917            C::Divergence: Divergence<Continue = AsExpression>,
918        {
919            type Output = Self;
920
921            fn $method(self, other: T) -> Self::Output {
922                let $left = try_expression!(self);
923                let $right = try_expression!(Constrained::<_, C>::new(other));
924                $f
925            }
926        }
927    };
928}
929impl_binary_operation_for_expression!();
930
931macro_rules! impl_try_from_for_expression {
932    () => {
933        with_primitives!(impl_try_from_for_expression);
934    };
935    (primitive => $t:ty) => {
936        impl<C> TryFrom<Expression<Constrained<$t, C>, C::Error>> for Constrained<$t, C>
937        where
938            C: Constraint,
939        {
940            type Error = C::Error;
941
942            fn try_from(
943                expression: Expression<Constrained<$t, C>, C::Error>,
944            ) -> Result<Self, Self::Error> {
945                match expression {
946                    Defined(defined) => Ok(defined),
947                    Undefined(undefined) => Err(undefined),
948                }
949            }
950        }
951
952        impl<C> TryFrom<Expression<Constrained<$t, C>, C::Error>> for $t
953        where
954            C: Constraint,
955        {
956            type Error = C::Error;
957
958            fn try_from(
959                expression: Expression<Constrained<$t, C>, C::Error>,
960            ) -> Result<Self, Self::Error> {
961                match expression {
962                    Defined(defined) => Ok(defined.into()),
963                    Undefined(undefined) => Err(undefined),
964                }
965            }
966        }
967    };
968}
969impl_try_from_for_expression!();