Skip to main content

bitcoin_units/amount/
ops.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Implements mathematical operators from [`core::ops`] and basic conversions.
4
5use core::num::{NonZeroI64, NonZeroU64};
6use core::ops;
7
8use NumOpResult as R;
9
10use super::{Amount, SignedAmount};
11use crate::internal_macros::{
12    impl_add_assign_for_results, impl_div_assign, impl_mul_assign, impl_rem_assign,
13    impl_sub_assign_for_results,
14};
15use crate::result::{MathErrorKind, MathOp, NumOpResult, OptionExt};
16
17impl From<Amount> for NumOpResult<Amount> {
18    #[inline]
19    fn from(a: Amount) -> Self { Self::Valid(a) }
20}
21impl From<&Amount> for NumOpResult<Amount> {
22    #[inline]
23    fn from(a: &Amount) -> Self { Self::Valid(*a) }
24}
25
26impl From<SignedAmount> for NumOpResult<SignedAmount> {
27    #[inline]
28    fn from(a: SignedAmount) -> Self { Self::Valid(a) }
29}
30impl From<&SignedAmount> for NumOpResult<SignedAmount> {
31    #[inline]
32    fn from(a: &SignedAmount) -> Self { Self::Valid(*a) }
33}
34
35crate::internal_macros::impl_op_for_references! {
36    impl ops::Add<Amount> for Amount {
37        type Output = NumOpResult<Amount>;
38
39        fn add(self, rhs: Amount) -> Self::Output { self.checked_add(rhs).valid_or_error(MathErrorKind::Overflow { op: MathOp::Add, is_negative: false }) }
40    }
41    impl ops::Add<NumOpResult<Amount>> for Amount {
42        type Output = NumOpResult<Amount>;
43
44        fn add(self, rhs: NumOpResult<Amount>) -> Self::Output { rhs.and_then(|a| a + self) }
45    }
46
47    impl ops::Sub<Amount> for Amount {
48        type Output = NumOpResult<Amount>;
49
50        fn sub(self, rhs: Amount) -> Self::Output { self.checked_sub(rhs).valid_or_error(MathErrorKind::Overflow { op: MathOp::Sub, is_negative: true }) }
51    }
52    impl ops::Sub<NumOpResult<Amount>> for Amount {
53        type Output = NumOpResult<Amount>;
54
55        fn sub(self, rhs: NumOpResult<Amount>) -> Self::Output {
56            match rhs {
57                R::Valid(amount) => self - amount,
58                R::Error(_) => rhs,
59            }
60        }
61    }
62
63    impl ops::Mul<u64> for Amount {
64        type Output = NumOpResult<Amount>;
65
66        fn mul(self, rhs: u64) -> Self::Output { self.checked_mul(rhs).valid_or_error(MathErrorKind::Overflow { op: MathOp::Mul, is_negative: false }) }
67    }
68    impl ops::Mul<u64> for NumOpResult<Amount> {
69        type Output = NumOpResult<Amount>;
70
71        fn mul(self, rhs: u64) -> Self::Output { self.and_then(|lhs| lhs * rhs) }
72    }
73    impl ops::Mul<Amount> for u64 {
74        type Output = NumOpResult<Amount>;
75
76        fn mul(self, rhs: Amount) -> Self::Output { rhs.checked_mul(self).valid_or_error(MathErrorKind::Overflow { op: MathOp::Mul, is_negative: false }) }
77    }
78    impl ops::Mul<NumOpResult<Amount>> for u64 {
79        type Output = NumOpResult<Amount>;
80
81        fn mul(self, rhs: NumOpResult<Amount>) -> Self::Output { rhs.and_then(|rhs| self * rhs) }
82    }
83
84    impl ops::Div<u64> for Amount {
85        type Output = NumOpResult<Amount>;
86
87        fn div(self, rhs: u64) -> Self::Output { self.checked_div(rhs).valid_or_error(MathErrorKind::DivByZero) }
88    }
89    impl ops::Div<u64> for NumOpResult<Amount> {
90        type Output = NumOpResult<Amount>;
91
92        fn div(self, rhs: u64) -> Self::Output { self.and_then(|lhs| lhs / rhs) }
93    }
94    impl ops::Div<Amount> for Amount {
95        type Output = NumOpResult<u64>;
96
97        fn div(self, rhs: Amount) -> Self::Output {
98            self.to_sat().checked_div(rhs.to_sat()).valid_or_error(MathErrorKind::DivByZero)
99        }
100    }
101    impl ops::Div<NonZeroU64> for Amount {
102        type Output = Amount;
103
104        fn div(self, rhs: NonZeroU64) -> Self::Output { Self::from_sat(self.to_sat() / rhs).expect("construction after division cannot fail") }
105    }
106    impl ops::Div<NonZeroU64> for NumOpResult<Amount> {
107        type Output = NumOpResult<Amount>;
108
109        fn div(self, rhs: NonZeroU64) -> Self::Output { self.map(|lhs| lhs / rhs) }
110    }
111    impl ops::Rem<u64> for Amount {
112        type Output = NumOpResult<Amount>;
113
114        fn rem(self, modulus: u64) -> Self::Output { self.checked_rem(modulus).valid_or_error(MathErrorKind::RemByZero) }
115    }
116    impl ops::Rem<NonZeroU64> for Amount {
117        type Output = Amount;
118
119        fn rem(self, modulus: NonZeroU64) -> Self::Output { Self::from_sat(self.to_sat() % modulus).expect("construction from remainder cannot fail") }
120    }
121    impl ops::Rem<u64> for NumOpResult<Amount> {
122        type Output = NumOpResult<Amount>;
123
124        fn rem(self, modulus: u64) -> Self::Output { self.and_then(|lhs| lhs % modulus) }
125    }
126    impl ops::Rem<NonZeroU64> for NumOpResult<Amount> {
127        type Output = NumOpResult<Amount>;
128
129        fn rem(self, modulus: NonZeroU64) -> Self::Output { self.map(|lhs| lhs % modulus) }
130    }
131
132    impl ops::Add<SignedAmount> for SignedAmount {
133        type Output = NumOpResult<SignedAmount>;
134
135        fn add(self, rhs: SignedAmount) -> Self::Output {
136            let kind = MathErrorKind::Overflow { op: MathOp::Add, is_negative: rhs.is_negative() };
137            self.checked_add(rhs).valid_or_error(kind)
138        }
139    }
140    impl ops::Add<NumOpResult<SignedAmount>> for SignedAmount {
141        type Output = NumOpResult<SignedAmount>;
142
143        fn add(self, rhs: NumOpResult<SignedAmount>) -> Self::Output { rhs.and_then(|a| a + self) }
144    }
145
146    impl ops::Sub<SignedAmount> for SignedAmount {
147        type Output = NumOpResult<SignedAmount>;
148
149        fn sub(self, rhs: SignedAmount) -> Self::Output {
150            let kind = MathErrorKind::Overflow { op: MathOp::Sub, is_negative: !rhs.is_negative() };
151            self.checked_sub(rhs).valid_or_error(kind)
152        }
153    }
154    impl ops::Sub<NumOpResult<SignedAmount>> for SignedAmount {
155        type Output = NumOpResult<SignedAmount>;
156
157        fn sub(self, rhs: NumOpResult<SignedAmount>) -> Self::Output {
158            match rhs {
159                R::Valid(amount) => self - amount,
160                R::Error(_) => rhs,
161            }
162        }
163    }
164
165    impl ops::Mul<i64> for SignedAmount {
166        type Output = NumOpResult<SignedAmount>;
167
168        fn mul(self, rhs: i64) -> Self::Output {
169            let is_negative = self.is_negative() != rhs.is_negative();
170            self.checked_mul(rhs).valid_or_error(MathErrorKind::Overflow { op: MathOp::Mul, is_negative })
171        }
172    }
173    impl ops::Mul<i64> for NumOpResult<SignedAmount> {
174        type Output = NumOpResult<SignedAmount>;
175
176        fn mul(self, rhs: i64) -> Self::Output { self.and_then(|lhs| lhs * rhs) }
177    }
178    impl ops::Mul<SignedAmount> for i64 {
179        type Output = NumOpResult<SignedAmount>;
180
181        fn mul(self, rhs: SignedAmount) -> Self::Output {
182            let is_negative = self.is_negative() != rhs.is_negative();
183            rhs.checked_mul(self).valid_or_error(MathErrorKind::Overflow { op: MathOp::Mul, is_negative })
184        }
185    }
186    impl ops::Mul<NumOpResult<SignedAmount>> for i64 {
187        type Output = NumOpResult<SignedAmount>;
188
189        fn mul(self, rhs: NumOpResult<SignedAmount>) -> Self::Output { rhs.and_then(|rhs| self * rhs) }
190    }
191
192    impl ops::Div<i64> for SignedAmount {
193        type Output = NumOpResult<SignedAmount>;
194
195        fn div(self, rhs: i64) -> Self::Output { self.checked_div(rhs).valid_or_error(MathErrorKind::DivByZero) }
196    }
197    impl ops::Div<i64> for NumOpResult<SignedAmount> {
198        type Output = NumOpResult<SignedAmount>;
199
200        fn div(self, rhs: i64) -> Self::Output { self.and_then(|lhs| lhs / rhs) }
201    }
202    impl ops::Div<SignedAmount> for SignedAmount {
203        type Output = NumOpResult<i64>;
204
205        fn div(self, rhs: SignedAmount) -> Self::Output {
206            self.to_sat().checked_div(rhs.to_sat()).valid_or_error(MathErrorKind::DivByZero)
207        }
208    }
209    impl ops::Div<NonZeroI64> for SignedAmount {
210        type Output = SignedAmount;
211
212        fn div(self, rhs: NonZeroI64) -> Self::Output { Self::from_sat(self.to_sat() / rhs.get()).expect("construction after division cannot fail") }
213    }
214    impl ops::Div<NonZeroI64> for NumOpResult<SignedAmount> {
215        type Output = NumOpResult<SignedAmount>;
216
217        fn div(self, rhs: NonZeroI64) -> Self::Output { self.map(|lhs| lhs / rhs) }
218    }
219    impl ops::Rem<i64> for SignedAmount {
220        type Output = NumOpResult<SignedAmount>;
221
222        fn rem(self, modulus: i64) -> Self::Output { self.checked_rem(modulus).valid_or_error(MathErrorKind::RemByZero) }
223    }
224    impl ops::Rem<NonZeroI64> for SignedAmount {
225        type Output = SignedAmount;
226
227        fn rem(self, modulus: NonZeroI64) -> Self::Output { SignedAmount::from_sat(self.to_sat() % modulus.get()).expect("construction from remainder cannot fail") }
228    }
229    impl ops::Rem<i64> for NumOpResult<SignedAmount> {
230        type Output = NumOpResult<SignedAmount>;
231
232        fn rem(self, modulus: i64) -> Self::Output { self.and_then(|lhs| lhs % modulus) }
233    }
234    impl ops::Rem<NonZeroI64> for NumOpResult<SignedAmount> {
235        type Output = NumOpResult<SignedAmount>;
236
237        fn rem(self, modulus: NonZeroI64) -> Self::Output { self.map(|lhs| lhs % modulus) }
238    }
239}
240
241impl_mul_assign!(NumOpResult<Amount>, u64);
242impl_mul_assign!(NumOpResult<SignedAmount>, i64);
243impl_div_assign!(NumOpResult<Amount>, u64);
244impl_div_assign!(NumOpResult<SignedAmount>, i64);
245impl_div_assign!(Amount, NonZeroU64);
246impl_div_assign!(SignedAmount, NonZeroI64);
247impl_div_assign!(NumOpResult<Amount>, NonZeroU64);
248impl_div_assign!(NumOpResult<SignedAmount>, NonZeroI64);
249impl_rem_assign!(NumOpResult<Amount>, u64);
250impl_rem_assign!(NumOpResult<SignedAmount>, i64);
251impl_rem_assign!(Amount, NonZeroU64);
252impl_rem_assign!(SignedAmount, NonZeroI64);
253impl_rem_assign!(NumOpResult<Amount>, NonZeroU64);
254impl_rem_assign!(NumOpResult<SignedAmount>, NonZeroI64);
255
256impl_add_assign_for_results!(Amount);
257impl_add_assign_for_results!(SignedAmount);
258impl_sub_assign_for_results!(Amount);
259impl_sub_assign_for_results!(SignedAmount);
260
261impl ops::Neg for Amount {
262    type Output = SignedAmount;
263
264    #[inline]
265    fn neg(self) -> Self::Output { self.to_signed().neg() }
266}
267
268impl ops::Neg for SignedAmount {
269    type Output = Self;
270
271    #[inline]
272    fn neg(self) -> Self::Output {
273        Self::from_sat(self.to_sat().neg()).expect("all +ve and -ve values are valid")
274    }
275}
276
277impl ops::Neg for NumOpResult<Amount> {
278    type Output = NumOpResult<SignedAmount>;
279
280    #[inline]
281    fn neg(self) -> Self::Output { self.map(ops::Neg::neg) }
282}
283
284impl ops::Neg for NumOpResult<SignedAmount> {
285    type Output = Self;
286
287    #[inline]
288    fn neg(self) -> Self::Output { self.map(ops::Neg::neg) }
289}
290
291/// Note: it's unspecified how many items from the iterator this implementation consumes if overflow occurs.
292impl core::iter::Sum<Amount> for NumOpResult<Amount> {
293    fn sum<I>(mut iter: I) -> Self
294    where
295        I: Iterator<Item = Amount>,
296    {
297        let result = iter.try_fold(Amount::ZERO, |acc, amount| (acc + amount).into_result());
298        Self::from_result(result)
299    }
300}
301
302/// Note: it's unspecified how many items from the iterator this implementation consumes if overflow occurs.
303impl<'a> core::iter::Sum<&'a Amount> for NumOpResult<Amount> {
304    fn sum<I>(mut iter: I) -> Self
305    where
306        I: Iterator<Item = &'a Amount>,
307    {
308        let result = iter.try_fold(Amount::ZERO, |acc, amount| (acc + amount).into_result());
309        Self::from_result(result)
310    }
311}
312
313/// Note: it's unspecified how many items from the iterator this implementation consumes if overflow occurs.
314impl core::iter::Sum<Self> for NumOpResult<Amount> {
315    fn sum<I>(mut iter: I) -> Self
316    where
317        I: Iterator<Item = Self>,
318    {
319        let result =
320            iter.try_fold(Amount::ZERO, |acc, amount| (acc + amount.into_result()?).into_result());
321        Self::from_result(result)
322    }
323}
324/// Note: it's unspecified how many items from the iterator this implementation consumes if overflow occurs.
325impl<'a> core::iter::Sum<&'a Self> for NumOpResult<Amount> {
326    fn sum<I>(mut iter: I) -> Self
327    where
328        I: Iterator<Item = &'a Self>,
329    {
330        let result =
331            iter.try_fold(Amount::ZERO, |acc, amount| (acc + amount.into_result()?).into_result());
332        Self::from_result(result)
333    }
334}
335
336/// Note: it's unspecified how many items from the iterator this implementation consumes if overflow occurs.
337impl core::iter::Sum<SignedAmount> for NumOpResult<SignedAmount> {
338    fn sum<I>(mut iter: I) -> Self
339    where
340        I: Iterator<Item = SignedAmount>,
341    {
342        let result = iter.try_fold(SignedAmount::ZERO, |acc, amount| (acc + amount).into_result());
343        Self::from_result(result)
344    }
345}
346
347/// Note: it's unspecified how many items from the iterator this implementation consumes if overflow occurs.
348impl<'a> core::iter::Sum<&'a SignedAmount> for NumOpResult<SignedAmount> {
349    fn sum<I>(mut iter: I) -> Self
350    where
351        I: Iterator<Item = &'a SignedAmount>,
352    {
353        let result = iter.try_fold(SignedAmount::ZERO, |acc, amount| (acc + amount).into_result());
354        Self::from_result(result)
355    }
356}
357
358/// Note: it's unspecified how many items from the iterator this implementation consumes if overflow occurs.
359impl core::iter::Sum<Self> for NumOpResult<SignedAmount> {
360    fn sum<I>(mut iter: I) -> Self
361    where
362        I: Iterator<Item = Self>,
363    {
364        let result = iter.try_fold(SignedAmount::ZERO, |acc, amount| {
365            (acc + amount.into_result()?).into_result()
366        });
367        Self::from_result(result)
368    }
369}
370
371/// Note: it's unspecified how many items from the iterator this implementation consumes if overflow occurs.
372impl<'a> core::iter::Sum<&'a Self> for NumOpResult<SignedAmount> {
373    fn sum<I>(mut iter: I) -> Self
374    where
375        I: Iterator<Item = &'a Self>,
376    {
377        let result = iter.try_fold(SignedAmount::ZERO, |acc, amount| {
378            (acc + amount.into_result()?).into_result()
379        });
380        Self::from_result(result)
381    }
382}
383#[cfg(test)]
384mod tests {
385    use super::*;
386    use crate::result::NumOpError;
387
388    #[test]
389    fn sum_amounts() {
390        let amounts =
391            [Amount::from_sat_u32(100), Amount::from_sat_u32(200), Amount::from_sat_u32(300)];
392
393        let sum: NumOpResult<Amount> = amounts.into_iter().sum();
394        assert_eq!(sum, NumOpResult::Valid(Amount::from_sat_u32(600)));
395    }
396
397    #[test]
398    fn sum_amounts_with_references() {
399        let amounts =
400            [Amount::from_sat_u32(100), Amount::from_sat_u32(200), Amount::from_sat_u32(300)];
401
402        let sum: NumOpResult<Amount> = amounts.iter().sum();
403        assert_eq!(sum, NumOpResult::Valid(Amount::from_sat_u32(600)));
404    }
405
406    #[test]
407    fn sum_preserves_division_by_zero_error() {
408        let err = [Amount::ONE_SAT / 0_u64];
409        let sum: NumOpResult<Amount> = err.into_iter().sum();
410        assert!(sum.unwrap_err().operation().is_division());
411        let sum: NumOpResult<Amount> = err.iter().sum();
412        assert!(sum.unwrap_err().operation().is_division());
413
414        let err = [SignedAmount::ONE_SAT / 0_i64];
415        let sum: NumOpResult<SignedAmount> = err.into_iter().sum();
416        assert!(sum.unwrap_err().operation().is_division());
417        let sum: NumOpResult<SignedAmount> = err.iter().sum();
418        assert!(sum.unwrap_err().operation().is_division());
419    }
420
421    #[test]
422    fn sum_amount_results() {
423        let amounts = [
424            NumOpResult::Valid(Amount::from_sat_u32(100)),
425            NumOpResult::Valid(Amount::from_sat_u32(200)),
426            NumOpResult::Valid(Amount::from_sat_u32(300)),
427        ];
428
429        let sum: NumOpResult<Amount> = amounts.into_iter().sum();
430        assert_eq!(sum, NumOpResult::Valid(Amount::from_sat_u32(600)));
431    }
432
433    #[test]
434    fn sum_amount_results_with_references() {
435        let amounts = [
436            NumOpResult::Valid(Amount::from_sat_u32(100)),
437            NumOpResult::Valid(Amount::from_sat_u32(200)),
438            NumOpResult::Valid(Amount::from_sat_u32(300)),
439        ];
440
441        let sum: NumOpResult<Amount> = amounts.iter().sum();
442        assert_eq!(sum, NumOpResult::Valid(Amount::from_sat_u32(600)));
443    }
444
445    #[test]
446    fn sum_amount_with_error_propagation() {
447        let amounts = [
448            NumOpResult::Valid(Amount::from_sat_u32(100)),
449            NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
450                op: MathOp::Add,
451                is_negative: false,
452            })),
453            NumOpResult::Valid(Amount::from_sat_u32(200)),
454        ];
455
456        let sum: NumOpResult<Amount> = amounts.into_iter().sum();
457        assert!(matches!(sum, NumOpResult::Error(_)));
458    }
459
460    #[test]
461    fn sum_signed_amounts() {
462        let amounts = [
463            SignedAmount::from_sat_i32(100),
464            SignedAmount::from_sat_i32(-50),
465            SignedAmount::from_sat_i32(200),
466        ];
467
468        let sum: NumOpResult<SignedAmount> = amounts.into_iter().sum();
469        assert_eq!(sum, NumOpResult::Valid(SignedAmount::from_sat_i32(250)));
470    }
471
472    #[test]
473    fn sum_signed_amounts_with_references() {
474        let amounts = [
475            SignedAmount::from_sat_i32(100),
476            SignedAmount::from_sat_i32(-50),
477            SignedAmount::from_sat_i32(200),
478        ];
479
480        let sum: NumOpResult<SignedAmount> = amounts.iter().sum();
481        assert_eq!(sum, NumOpResult::Valid(SignedAmount::from_sat_i32(250)));
482    }
483
484    #[test]
485    fn sum_signed_amount_results() {
486        let amounts = [
487            NumOpResult::Valid(SignedAmount::from_sat_i32(100)),
488            NumOpResult::Valid(SignedAmount::from_sat_i32(-50)),
489            NumOpResult::Valid(SignedAmount::from_sat_i32(200)),
490        ];
491
492        let sum: NumOpResult<SignedAmount> = amounts.into_iter().sum();
493        assert_eq!(sum, NumOpResult::Valid(SignedAmount::from_sat_i32(250)));
494    }
495
496    #[test]
497    fn sum_signed_amount_results_with_references() {
498        let amounts = [
499            NumOpResult::Valid(SignedAmount::from_sat_i32(100)),
500            NumOpResult::Valid(SignedAmount::from_sat_i32(-50)),
501            NumOpResult::Valid(SignedAmount::from_sat_i32(200)),
502        ];
503
504        let sum: NumOpResult<SignedAmount> = amounts.iter().sum();
505        assert_eq!(sum, NumOpResult::Valid(SignedAmount::from_sat_i32(250)));
506    }
507
508    #[test]
509    fn sum_signed_amount_with_error_propagation() {
510        let amounts = [
511            NumOpResult::Valid(SignedAmount::from_sat_i32(100)),
512            NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
513                op: MathOp::Add,
514                is_negative: false,
515            })),
516            NumOpResult::Valid(SignedAmount::from_sat_i32(200)),
517        ];
518
519        let sum: NumOpResult<SignedAmount> = amounts.into_iter().sum();
520        assert!(matches!(sum, NumOpResult::Error(_)));
521    }
522
523    #[test]
524    fn op_assign_amount() {
525        let sat = Amount::from_sat_u32(50);
526
527        let mut res = sat + sat;
528        res += Amount::from_sat_u32(50);
529        assert_eq!(res, NumOpResult::Valid(Amount::from_sat_u32(150)));
530
531        let add_err = NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
532            op: MathOp::Add,
533            is_negative: false,
534        }));
535        res += add_err; // Add an error result
536        assert_eq!(res, add_err);
537
538        let mut res = sat + sat;
539        res -= Amount::from_sat_u32(20);
540        assert_eq!(res, NumOpResult::Valid(Amount::from_sat_u32(80)));
541
542        let sub_err = NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
543            op: MathOp::Sub,
544            is_negative: true,
545        }));
546        res -= sub_err; // Subtract an error result
547        assert_eq!(res, sub_err);
548    }
549
550    #[test]
551    fn op_assign_signed_amount() {
552        let ssat = SignedAmount::from_sat_i32(50);
553
554        let mut res = ssat + ssat;
555        res += SignedAmount::from_sat_i32(-30);
556        assert_eq!(res, NumOpResult::Valid(SignedAmount::from_sat_i32(70)));
557
558        let add_err = NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
559            op: MathOp::Add,
560            is_negative: false,
561        }));
562        res += add_err; // Add an error result
563        assert_eq!(res, add_err);
564
565        let mut res = ssat + ssat;
566        res -= SignedAmount::from_sat_i32(25);
567        assert_eq!(res, NumOpResult::Valid(SignedAmount::from_sat_i32(75)));
568
569        let sub_err = NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
570            op: MathOp::Sub,
571            is_negative: true,
572        }));
573        res -= sub_err; // Subtract an error result
574        assert_eq!(res, sub_err);
575    }
576
577    #[test]
578    fn rem_assign_amount() {
579        let sat = Amount::from_sat_u32(50);
580        let mut res = sat + sat;
581        res %= 30_u64;
582        assert_eq!(res, NumOpResult::Valid(Amount::from_sat_u32(10)));
583
584        res %= &4_u64;
585        assert_eq!(res, NumOpResult::Valid(Amount::from_sat_u32(2)));
586
587        res %= 0_u64;
588        assert_eq!(res, NumOpResult::Error(NumOpError::while_doing(MathErrorKind::RemByZero)));
589
590        res %= 5_u64;
591        assert_eq!(res, NumOpResult::Error(NumOpError::while_doing(MathErrorKind::RemByZero)));
592    }
593
594    #[test]
595    fn rem_assign_nz_amount() {
596        fn nz(x: u64) -> NonZeroU64 { NonZeroU64::new(x).unwrap() }
597
598        let mut res = Amount::from_sat_u32(100);
599        res %= nz(30_u64);
600        assert_eq!(res, Amount::from_sat_u32(10));
601
602        res %= &nz(4_u64);
603        assert_eq!(res, Amount::from_sat_u32(2));
604
605        res %= nz(5_u64);
606        assert_eq!(res, Amount::from_sat_u32(2));
607    }
608
609    #[test]
610    fn rem_assign_signed_amount() {
611        let ssat = SignedAmount::from_sat_i32(-50);
612
613        let mut res = ssat + ssat;
614        res %= 30_i64;
615        assert_eq!(res, NumOpResult::Valid(SignedAmount::from_sat_i32(-10)));
616
617        res %= &4_i64;
618        assert_eq!(res, NumOpResult::Valid(SignedAmount::from_sat_i32(-2)));
619
620        res %= 0_i64;
621        assert_eq!(res, NumOpResult::Error(NumOpError::while_doing(MathErrorKind::RemByZero)));
622
623        res %= 5_i64;
624        assert_eq!(res, NumOpResult::Error(NumOpError::while_doing(MathErrorKind::RemByZero)));
625    }
626
627    #[test]
628    fn rem_assign_nz_signed_amount() {
629        fn nz(x: i64) -> NonZeroI64 { NonZeroI64::new(x).unwrap() }
630
631        let mut res = SignedAmount::from_sat_i32(-100);
632        res %= nz(30_i64);
633        assert_eq!(res, SignedAmount::from_sat_i32(-10));
634
635        res %= &nz(4_i64);
636        assert_eq!(res, SignedAmount::from_sat_i32(-2));
637
638        res %= nz(5_i64);
639        assert_eq!(res, SignedAmount::from_sat_i32(-2));
640    }
641
642    #[test]
643    fn div_assign_amount_nonzero() {
644        let mut amount = Amount::from_sat_u32(100);
645        amount /= NonZeroU64::new(12).unwrap();
646        assert_eq!(amount, Amount::from_sat_u32(8));
647
648        // Division truncates towards zero.
649        amount /= NonZeroU64::new(10).unwrap();
650        assert_eq!(amount, Amount::ZERO);
651
652        let mut res = amount + Amount::from_sat_u32(100);
653        res /= NonZeroU64::new(4).unwrap();
654        assert_eq!(res, NumOpResult::Valid(Amount::from_sat_u32(25)));
655
656        // An error result stays an error, keeping the original operation.
657        let mut res: NumOpResult<Amount> =
658            NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
659                op: MathOp::Add,
660                is_negative: false,
661            }));
662        res /= NonZeroU64::new(2).unwrap();
663        assert_eq!(
664            res,
665            NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
666                op: MathOp::Add,
667                is_negative: false
668            }))
669        );
670    }
671
672    #[test]
673    fn div_assign_signed_amount_nonzero() {
674        let mut ssat = SignedAmount::from_sat_i32(-100);
675        ssat /= NonZeroI64::new(4).unwrap();
676        assert_eq!(ssat, SignedAmount::from_sat_i32(-25));
677
678        ssat /= &NonZeroI64::new(-5).unwrap();
679        assert_eq!(ssat, SignedAmount::from_sat_i32(5));
680
681        // Division truncates towards zero.
682        ssat /= NonZeroI64::new(-10).unwrap();
683        assert_eq!(ssat, SignedAmount::ZERO);
684
685        let mut res = ssat - SignedAmount::from_sat_i32(100);
686        res /= NonZeroI64::new(4).unwrap();
687        assert_eq!(res, NumOpResult::Valid(SignedAmount::from_sat_i32(-25)));
688
689        let mut res: NumOpResult<SignedAmount> =
690            NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
691                op: MathOp::Sub,
692                is_negative: true,
693            }));
694        res /= NonZeroI64::new(2).unwrap();
695        assert_eq!(
696            res,
697            NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
698                op: MathOp::Sub,
699                is_negative: true
700            }))
701        );
702    }
703
704    #[test]
705    fn op_assign_amount_error() {
706        let mut res: NumOpResult<Amount> =
707            NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
708                op: MathOp::Mul,
709                is_negative: false,
710            }));
711        let orig_res = res;
712
713        // All assign ops to an error should preserve the error
714        res += Amount::from_sat_u32(10);
715        assert_eq!(res, orig_res);
716
717        res += NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
718            op: MathOp::Sub,
719            is_negative: true,
720        }));
721        assert_eq!(res, orig_res);
722
723        res -= Amount::from_sat_u32(10);
724        assert_eq!(res, orig_res);
725
726        res -= NumOpResult::Error(NumOpError::while_doing(MathErrorKind::Overflow {
727            op: MathOp::Add,
728            is_negative: false,
729        }));
730        assert_eq!(res, orig_res);
731    }
732}