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#[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#[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 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 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 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!();