1use crate::error::PositiveError;
10use approx::{AbsDiffEq, RelativeEq};
11use num_traits::{FromPrimitive, Pow, ToPrimitive};
12use rust_decimal::{Decimal, MathematicalOps};
13use rust_decimal_macros::dec;
14use serde::de::Visitor;
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16use std::cmp::{Ordering, PartialEq};
17use std::fmt;
18use std::fmt::Display;
19use std::iter::Sum;
20use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub};
21use std::str::FromStr;
22
23pub const EPSILON: Decimal = dec!(1e-16);
25
26#[derive(PartialEq, Clone, Copy, Hash)]
31#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
32pub struct Positive(pub Decimal);
33
34#[macro_export]
51macro_rules! pos {
52 ($val:expr) => {
53 $crate::Positive::new($val)
54 };
55}
56
57#[macro_export]
77macro_rules! pos_or_panic {
78 ($val:expr) => {
79 $crate::Positive::new($val).expect("Failed to create Positive value")
80 };
81}
82
83#[macro_export]
100macro_rules! spos {
101 ($val:expr) => {
102 $crate::Positive::new($val).ok()
103 };
104}
105
106#[must_use]
108pub fn is_positive<T: 'static>() -> bool {
109 std::any::TypeId::of::<T>() == std::any::TypeId::of::<Positive>()
110}
111
112impl Positive {
113 pub const ZERO: Positive = Positive(Decimal::ZERO);
115 pub const ONE: Positive = Positive(Decimal::ONE);
117 pub const TWO: Positive = Positive(Decimal::TWO);
119 pub const INFINITY: Positive = Positive(Decimal::MAX);
121 pub const TEN: Positive = Positive(Decimal::TEN);
123 pub const HUNDRED: Positive = Positive(Decimal::ONE_HUNDRED);
125 pub const THOUSAND: Positive = Positive(Decimal::ONE_THOUSAND);
127 pub const PI: Positive = Positive(Decimal::PI);
129
130 pub const E: Positive = Positive(Decimal::E);
132
133 pub fn new(value: f64) -> Result<Self, PositiveError> {
135 let dec = Decimal::from_f64(value);
136 match dec {
137 Some(value) if value >= Decimal::ZERO => Ok(Positive(value)),
138 Some(value) => Err(PositiveError::OutOfBounds {
139 value: value.to_f64().unwrap_or(0.0),
140 min: 0.0,
141 max: f64::MAX,
142 }),
143 None => Err(PositiveError::ConversionError {
144 from_type: "f64".to_string(),
145 to_type: "Positive".to_string(),
146 reason: "failed to parse Decimal".to_string(),
147 }),
148 }
149 }
150
151 pub fn new_decimal(value: Decimal) -> Result<Self, PositiveError> {
153 if value >= Decimal::ZERO {
154 Ok(Positive(value))
155 } else {
156 Err(PositiveError::OutOfBounds {
157 value: value.to_f64().unwrap_or(0.0),
158 min: 0.0,
159 max: f64::INFINITY,
160 })
161 }
162 }
163
164 #[must_use]
166 pub fn value(&self) -> Decimal {
167 self.0
168 }
169
170 #[must_use]
172 pub fn to_dec(&self) -> Decimal {
173 self.0
174 }
175
176 #[must_use]
178 pub fn to_dec_ref(&self) -> &Decimal {
179 &self.0
180 }
181
182 #[must_use]
189 pub fn to_f64(&self) -> f64 {
190 self.0
191 .to_f64()
192 .expect("Decimal to f64 conversion failed - value out of range")
193 }
194
195 #[must_use]
197 pub fn to_f64_checked(&self) -> Option<f64> {
198 self.0.to_f64()
199 }
200
201 #[must_use]
203 pub fn to_f64_lossy(&self) -> f64 {
204 self.0.to_f64().unwrap_or(0.0)
205 }
206
207 #[must_use]
214 pub fn to_i64(&self) -> i64 {
215 self.0
216 .to_i64()
217 .expect("Decimal to i64 conversion failed - value out of range")
218 }
219
220 #[must_use]
222 pub fn to_i64_checked(&self) -> Option<i64> {
223 self.0.to_i64()
224 }
225
226 #[must_use]
233 pub fn to_u64(&self) -> u64 {
234 self.0
235 .to_u64()
236 .expect("Decimal to u64 conversion failed - value out of range")
237 }
238
239 #[must_use]
241 pub fn to_u64_checked(&self) -> Option<u64> {
242 self.0.to_u64()
243 }
244
245 #[must_use]
252 pub fn to_usize(&self) -> usize {
253 self.0
254 .to_usize()
255 .expect("Decimal to usize conversion failed - value out of range")
256 }
257
258 #[must_use]
260 pub fn to_usize_checked(&self) -> Option<usize> {
261 self.0.to_usize()
262 }
263
264 #[must_use]
266 pub fn max(self, other: Positive) -> Positive {
267 if self.0 > other.0 { self } else { other }
268 }
269
270 #[must_use]
272 pub fn min(self, other: Positive) -> Positive {
273 if self.0 < other.0 { self } else { other }
274 }
275
276 #[must_use]
278 pub fn floor(&self) -> Positive {
279 Positive(self.0.floor())
280 }
281
282 #[must_use]
284 pub fn powi(&self, n: i64) -> Positive {
285 Positive(self.0.powi(n))
286 }
287
288 #[must_use]
290 pub fn pow(&self, n: Positive) -> Positive {
291 Positive(self.0.pow(n.to_dec()))
292 }
293
294 #[must_use]
296 pub fn powu(&self, n: u64) -> Positive {
297 Positive(self.0.powu(n))
298 }
299
300 #[must_use]
302 pub fn powd(&self, p0: Decimal) -> Positive {
303 Positive(self.0.powd(p0))
304 }
305
306 #[must_use]
308 pub fn round(&self) -> Positive {
309 Positive(self.0.round())
310 }
311
312 #[must_use]
314 pub fn round_to_nice_number(&self) -> Positive {
315 let magnitude = self.log10().floor();
316 let ten_pow = Positive::TEN.pow(magnitude);
317 let normalized = self / &ten_pow;
318 let nice_number = if normalized < dec!(1.5) {
319 Positive::ONE
320 } else if normalized < pos_or_panic!(3.0) {
321 Positive::TWO
322 } else if normalized < pos_or_panic!(7.0) {
323 pos_or_panic!(5.0)
324 } else {
325 Positive::TEN
326 };
327 nice_number * pos_or_panic!(10.0).powu(magnitude.to_u64())
328 }
329
330 #[must_use]
337 pub fn sqrt(&self) -> Positive {
338 Positive(self.0.sqrt().expect("Square root calculation failed"))
339 }
340
341 pub fn sqrt_checked(&self) -> Result<Positive, PositiveError> {
343 self.0.sqrt().map(Positive).ok_or_else(|| {
344 PositiveError::arithmetic_error("sqrt", "square root calculation failed")
345 })
346 }
347
348 #[must_use]
350 pub fn ln(&self) -> Positive {
351 Positive(self.0.ln())
352 }
353
354 #[must_use]
356 pub fn round_to(&self, decimal_places: u32) -> Positive {
357 Positive(self.0.round_dp(decimal_places))
358 }
359
360 #[must_use]
362 pub fn format_fixed_places(&self, decimal_places: u32) -> String {
363 let rounded = self.round_to(decimal_places).to_f64();
364 format!("{:.1$}", rounded, decimal_places as usize)
365 }
366
367 #[must_use]
369 pub fn exp(&self) -> Positive {
370 Positive(self.0.exp())
371 }
372
373 #[must_use]
375 pub fn clamp(&self, min: Positive, max: Positive) -> Positive {
376 if self < &min {
377 min
378 } else if self > &max {
379 max
380 } else {
381 *self
382 }
383 }
384
385 #[must_use]
387 pub fn is_zero(&self) -> bool {
388 self.0.is_zero()
389 }
390
391 #[must_use]
393 pub fn ceiling(&self) -> Positive {
394 Positive::from(self.to_dec().ceil())
395 }
396
397 #[must_use]
399 pub fn log10(&self) -> Positive {
400 Positive(self.0.log10())
401 }
402
403 #[must_use]
405 pub fn sub_or_zero(&self, other: &Decimal) -> Positive {
406 if &self.0 > other {
407 Positive(self.0 - other)
408 } else {
409 Positive(Decimal::ZERO)
410 }
411 }
412
413 #[must_use]
415 pub fn sub_or_none(&self, other: &Decimal) -> Option<Positive> {
416 if &self.0 >= other {
417 Some(Positive(self.0 - other))
418 } else {
419 None
420 }
421 }
422
423 pub fn checked_sub(&self, rhs: &Self) -> Result<Self, PositiveError> {
425 Positive::new_decimal(self.0 - rhs.0)
426 }
427
428 #[must_use]
430 pub fn saturating_sub(&self, rhs: &Self) -> Self {
431 if self.0 > rhs.0 {
432 Positive(self.0 - rhs.0)
433 } else {
434 Positive::ZERO
435 }
436 }
437
438 pub fn checked_div(&self, rhs: &Self) -> Result<Self, PositiveError> {
440 if rhs.is_zero() {
441 Err(PositiveError::arithmetic_error(
442 "division",
443 "division by zero",
444 ))
445 } else {
446 Ok(Positive(self.0 / rhs.0))
447 }
448 }
449
450 #[must_use]
452 pub fn is_multiple(&self, other: f64) -> bool {
453 let value = self.to_f64();
454 if !value.is_finite() {
455 return false;
456 }
457 let remainder = value % other;
458 remainder.abs() < f64::EPSILON || (other - remainder.abs()).abs() < f64::EPSILON
459 }
460
461 #[must_use]
463 pub fn is_multiple_of(&self, other: &Positive) -> bool {
464 if other.is_zero() {
465 return false;
466 }
467 let remainder = self.0 % other.0;
468 remainder.abs() < EPSILON
469 }
470}
471
472impl From<Positive> for Decimal {
473 fn from(value: Positive) -> Self {
474 value.0
475 }
476}
477
478impl PartialEq<&Positive> for Positive {
479 fn eq(&self, other: &&Positive) -> bool {
480 self == *other
481 }
482}
483
484impl From<Positive> for u64 {
485 fn from(pos_u64: Positive) -> Self {
486 pos_u64.0.to_u64().unwrap_or(0)
487 }
488}
489
490impl From<&Positive> for f64 {
491 fn from(value: &Positive) -> Self {
492 value.0.to_f64().unwrap_or(0.0)
493 }
494}
495
496impl From<Positive> for f64 {
497 fn from(value: Positive) -> Self {
498 value.0.to_f64().unwrap_or(0.0)
499 }
500}
501
502impl From<Positive> for usize {
503 fn from(value: Positive) -> Self {
504 value.0.to_f64().unwrap_or(0.0) as usize
505 }
506}
507
508impl PartialEq<&Positive> for f64 {
509 fn eq(&self, other: &&Positive) -> bool {
510 self == &other.0.to_f64().unwrap_or(0.0)
511 }
512}
513
514impl PartialOrd<&Positive> for f64 {
515 fn partial_cmp(&self, other: &&Positive) -> Option<Ordering> {
516 self.partial_cmp(&other.0.to_f64().unwrap_or(0.0))
517 }
518}
519
520impl PartialEq<Positive> for f64 {
521 fn eq(&self, other: &Positive) -> bool {
522 self == &other.0.to_f64().unwrap_or(0.0)
523 }
524}
525
526impl PartialOrd<Positive> for f64 {
527 fn partial_cmp(&self, other: &Positive) -> Option<Ordering> {
528 self.partial_cmp(&other.0.to_f64().unwrap_or(0.0))
529 }
530}
531
532impl Mul<Positive> for f64 {
533 type Output = f64;
534 fn mul(self, rhs: Positive) -> Self::Output {
535 self * rhs.to_f64()
536 }
537}
538
539impl Div<Positive> for f64 {
540 type Output = f64;
541 fn div(self, rhs: Positive) -> Self::Output {
542 self / rhs.to_f64()
543 }
544}
545
546impl Sub<Positive> for f64 {
547 type Output = f64;
548 fn sub(self, rhs: Positive) -> Self::Output {
549 self - rhs.to_f64()
550 }
551}
552
553impl Add<Positive> for f64 {
554 type Output = f64;
555 fn add(self, rhs: Positive) -> Self::Output {
556 self + rhs.to_f64()
557 }
558}
559
560impl FromStr for Positive {
561 type Err = String;
562 fn from_str(s: &str) -> Result<Self, Self::Err> {
563 match s.parse::<Decimal>() {
564 Ok(value) if value >= Decimal::ZERO => Ok(Positive(value)),
565 Ok(value) => Err(format!("Value must be positive, got {value}")),
566 Err(e) => Err(format!("Failed to parse as Decimal: {e}")),
567 }
568 }
569}
570
571impl From<f64> for Positive {
572 fn from(value: f64) -> Self {
573 Positive::new(value).expect("Value must be positive")
574 }
575}
576
577impl From<usize> for Positive {
578 fn from(value: usize) -> Self {
579 Positive::new(value as f64).expect("Value must be positive")
580 }
581}
582
583impl From<Decimal> for Positive {
584 fn from(value: Decimal) -> Self {
585 Positive::new_decimal(value).expect("Value must be positive")
586 }
587}
588
589impl From<&Decimal> for Positive {
590 fn from(value: &Decimal) -> Self {
591 Positive::new_decimal(*value).expect("Value must be positive")
592 }
593}
594
595impl From<&Positive> for Positive {
596 fn from(value: &Positive) -> Self {
597 Positive(value.0)
598 }
599}
600
601impl Mul<f64> for Positive {
602 type Output = Positive;
603 fn mul(self, rhs: f64) -> Positive {
604 (self.to_f64() * rhs).into()
605 }
606}
607
608impl Div<f64> for Positive {
609 type Output = Positive;
610 fn div(self, rhs: f64) -> Positive {
611 (self.to_f64() / rhs).into()
612 }
613}
614
615impl Div<f64> for &Positive {
616 type Output = Positive;
617 fn div(self, rhs: f64) -> Positive {
618 (self.to_f64() / rhs).into()
619 }
620}
621
622impl Sub<f64> for Positive {
623 type Output = Positive;
624 fn sub(self, rhs: f64) -> Self::Output {
625 (self.to_f64() - rhs).into()
626 }
627}
628
629impl Add<f64> for Positive {
630 type Output = Positive;
631 fn add(self, rhs: f64) -> Self::Output {
632 (self.to_f64() + rhs).into()
633 }
634}
635
636impl PartialOrd<f64> for Positive {
637 fn partial_cmp(&self, other: &f64) -> Option<Ordering> {
638 self.0.to_f64().unwrap_or(0.0).partial_cmp(other)
639 }
640}
641
642impl PartialEq<f64> for &Positive {
643 fn eq(&self, other: &f64) -> bool {
644 self.0.to_f64().unwrap_or(0.0) == *other
645 }
646}
647
648impl PartialOrd<f64> for &Positive {
649 fn partial_cmp(&self, other: &f64) -> Option<Ordering> {
650 self.0.to_f64().unwrap_or(0.0).partial_cmp(other)
651 }
652}
653
654impl PartialEq<f64> for Positive {
655 fn eq(&self, other: &f64) -> bool {
656 self.to_f64() == *other
657 }
658}
659
660impl Display for Positive {
661 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
662 if *self == Positive::INFINITY {
663 write!(f, "{}", f64::MAX)
664 } else if self.0.scale() == 0 {
665 match self.0.to_i64() {
666 Some(val) => write!(f, "{val}"),
667 None => write!(f, "{}", self.0),
668 }
669 } else if let Some(precision) = f.precision() {
670 write!(f, "{:.1$}", self.0, precision)
671 } else {
672 let s = self.0.to_string();
673 let trimmed = s.trim_end_matches('0').trim_end_matches('.');
674 write!(f, "{trimmed}")
675 }
676 }
677}
678
679impl fmt::Debug for Positive {
680 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
681 if *self == Positive::INFINITY {
682 write!(f, "{}", f64::MAX)
683 } else if self.0.scale() == 0 {
684 match self.0.to_i64() {
685 Some(val) => write!(f, "{val}"),
686 None => write!(f, "{}", self.0),
687 }
688 } else {
689 write!(f, "{}", self.0)
690 }
691 }
692}
693
694impl PartialEq<Decimal> for Positive {
695 fn eq(&self, other: &Decimal) -> bool {
696 (self.0 - *other).abs() <= EPSILON * Decimal::from(100)
697 }
698}
699
700impl Serialize for Positive {
701 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
702 where
703 S: Serializer,
704 {
705 if *self == Positive::INFINITY {
706 return serializer.serialize_f64(f64::MAX);
707 }
708 if self.0.scale() == 0 {
709 serializer.serialize_i64(
710 self.0
711 .to_i64()
712 .ok_or_else(|| serde::ser::Error::custom("Failed to convert to i64"))?,
713 )
714 } else {
715 serializer.serialize_f64(
716 self.0
717 .to_f64()
718 .ok_or_else(|| serde::ser::Error::custom("Failed to convert to f64"))?,
719 )
720 }
721 }
722}
723
724impl<'de> Deserialize<'de> for Positive {
725 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
726 where
727 D: Deserializer<'de>,
728 {
729 struct PositiveVisitor;
730
731 impl Visitor<'_> for PositiveVisitor {
732 type Value = Positive;
733
734 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
735 formatter.write_str("a positive number")
736 }
737
738 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
739 where
740 E: serde::de::Error,
741 {
742 Err(serde::de::Error::custom(format!(
743 "Invalid string: '{value}'. Expected a positive number."
744 )))
745 }
746
747 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
748 where
749 E: serde::de::Error,
750 {
751 if value < 0 {
752 Err(serde::de::Error::custom("Expected a non-negative integer"))
753 } else {
754 Positive::new_decimal(Decimal::from(value)).map_err(serde::de::Error::custom)
755 }
756 }
757
758 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
759 where
760 E: serde::de::Error,
761 {
762 Positive::new_decimal(Decimal::from(value)).map_err(serde::de::Error::custom)
763 }
764
765 fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
766 where
767 E: serde::de::Error,
768 {
769 if value.is_infinite() && value.is_sign_positive() {
770 return Ok(Positive::INFINITY);
771 }
772 if value == f64::MAX {
773 return Ok(Positive::INFINITY);
774 }
775 let decimal = Decimal::from_f64(value)
776 .ok_or_else(|| serde::de::Error::custom("Failed to convert f64 to Decimal"))?;
777 if value < 0.0 {
778 Err(serde::de::Error::custom("Expected a non-negative float"))
779 } else {
780 Positive::new_decimal(decimal).map_err(serde::de::Error::custom)
781 }
782 }
783 }
784
785 deserializer.deserialize_any(PositiveVisitor)
786 }
787}
788
789impl Add for Positive {
790 type Output = Positive;
791 fn add(self, other: Positive) -> Positive {
792 Positive(self.0 + other.0)
793 }
794}
795
796impl Sub for Positive {
797 type Output = Positive;
798 fn sub(self, rhs: Self) -> Self::Output {
799 let result = self.0 - rhs.0;
800 if result < Decimal::ZERO {
801 panic!("Resulting value must be positive");
802 } else {
803 Positive(result)
804 }
805 }
806}
807
808impl Div for Positive {
809 type Output = Positive;
810 fn div(self, other: Positive) -> Self::Output {
811 Positive(self.0 / other.0)
812 }
813}
814
815impl Div for &Positive {
816 type Output = Positive;
817 fn div(self, other: &Positive) -> Self::Output {
818 Positive(self.0 / other.0)
819 }
820}
821
822impl Add<Decimal> for Positive {
823 type Output = Positive;
824 fn add(self, rhs: Decimal) -> Positive {
825 Positive(self.0 + rhs)
826 }
827}
828
829impl Add<&Decimal> for Positive {
830 type Output = Positive;
831 fn add(self, rhs: &Decimal) -> Self::Output {
832 (self.0 + rhs).into()
833 }
834}
835
836impl Sub<Decimal> for Positive {
837 type Output = Positive;
838 fn sub(self, rhs: Decimal) -> Positive {
839 Positive::new_decimal(self.0 - rhs).expect("Resulting value must be positive")
840 }
841}
842
843impl Sub<&Decimal> for Positive {
844 type Output = Positive;
845 fn sub(self, rhs: &Decimal) -> Self::Output {
846 Positive::new_decimal(self.0 - rhs).expect("Resulting value must be positive")
847 }
848}
849
850impl AddAssign for Positive {
851 fn add_assign(&mut self, other: Positive) {
852 self.0 += other.0;
853 }
854}
855
856impl AddAssign<Decimal> for Positive {
857 fn add_assign(&mut self, rhs: Decimal) {
858 self.0 += rhs;
859 }
860}
861
862impl MulAssign<Decimal> for Positive {
863 fn mul_assign(&mut self, rhs: Decimal) {
864 self.0 *= rhs;
865 }
866}
867
868impl Div<Decimal> for Positive {
869 type Output = Positive;
870 fn div(self, rhs: Decimal) -> Positive {
871 Positive(self.0 / rhs)
872 }
873}
874
875impl Div<&Decimal> for Positive {
876 type Output = Positive;
877 fn div(self, rhs: &Decimal) -> Self::Output {
878 (self.0 / rhs).into()
879 }
880}
881
882impl PartialOrd<Decimal> for Positive {
883 fn partial_cmp(&self, other: &Decimal) -> Option<Ordering> {
884 self.0.partial_cmp(other)
885 }
886}
887
888impl PartialOrd for Positive {
889 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
890 Some(self.cmp(other))
891 }
892
893 fn le(&self, other: &Self) -> bool {
894 self.0 <= other.0
895 }
896
897 fn ge(&self, other: &Self) -> bool {
898 self.0 >= other.0
899 }
900}
901
902impl Eq for Positive {}
903
904impl Ord for Positive {
905 fn cmp(&self, other: &Self) -> Ordering {
906 self.0.partial_cmp(&other.0).unwrap_or(Ordering::Equal)
907 }
908}
909
910impl Neg for Positive {
911 type Output = Self;
912 fn neg(self) -> Self::Output {
913 panic!("Cannot negate a Positive value!");
914 }
915}
916
917impl Mul for Positive {
918 type Output = Positive;
919 fn mul(self, other: Positive) -> Positive {
920 Positive(self.0 * other.0)
921 }
922}
923
924impl Mul<Decimal> for Positive {
925 type Output = Positive;
926 fn mul(self, rhs: Decimal) -> Positive {
927 Positive(self.0 * rhs)
928 }
929}
930
931impl Mul<Positive> for Decimal {
932 type Output = Decimal;
933 fn mul(self, rhs: Positive) -> Decimal {
934 self * rhs.0
935 }
936}
937
938impl Div<Positive> for Decimal {
939 type Output = Decimal;
940 fn div(self, rhs: Positive) -> Decimal {
941 self / rhs.0
942 }
943}
944
945impl Sub<Positive> for Decimal {
946 type Output = Decimal;
947 fn sub(self, rhs: Positive) -> Decimal {
948 self - rhs.0
949 }
950}
951
952impl Sub<&Positive> for Decimal {
953 type Output = Decimal;
954 fn sub(self, rhs: &Positive) -> Decimal {
955 self - rhs.0
956 }
957}
958
959impl Add<Positive> for Decimal {
960 type Output = Decimal;
961 fn add(self, rhs: Positive) -> Decimal {
962 self + rhs.0
963 }
964}
965
966impl Add<&Positive> for Decimal {
967 type Output = Decimal;
968 fn add(self, rhs: &Positive) -> Decimal {
969 self + rhs.0
970 }
971}
972
973impl std::ops::AddAssign<Positive> for Decimal {
974 fn add_assign(&mut self, rhs: Positive) {
975 *self += rhs.0;
976 }
977}
978
979impl std::ops::AddAssign<&Positive> for Decimal {
980 fn add_assign(&mut self, rhs: &Positive) {
981 *self += rhs.0;
982 }
983}
984
985impl std::ops::MulAssign<Positive> for Decimal {
986 fn mul_assign(&mut self, rhs: Positive) {
987 *self *= rhs.0;
988 }
989}
990
991impl std::ops::MulAssign<&Positive> for Decimal {
992 fn mul_assign(&mut self, rhs: &Positive) {
993 *self *= rhs.0;
994 }
995}
996
997impl PartialEq<Positive> for Decimal {
998 fn eq(&self, other: &Positive) -> bool {
999 *self == other.0
1000 }
1001}
1002
1003impl From<&Positive> for Decimal {
1004 fn from(pos: &Positive) -> Self {
1005 pos.0
1006 }
1007}
1008
1009impl Default for Positive {
1010 fn default() -> Self {
1011 Positive::ZERO
1012 }
1013}
1014
1015impl AbsDiffEq for Positive {
1016 type Epsilon = Decimal;
1017
1018 fn default_epsilon() -> Self::Epsilon {
1019 EPSILON
1020 }
1021
1022 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
1023 (self.0 - other.0).abs() <= epsilon
1024 }
1025}
1026
1027impl RelativeEq for Positive {
1028 fn default_max_relative() -> Self::Epsilon {
1029 EPSILON * Decimal::from(100)
1030 }
1031
1032 fn relative_eq(
1033 &self,
1034 other: &Self,
1035 epsilon: Self::Epsilon,
1036 max_relative: Self::Epsilon,
1037 ) -> bool {
1038 let abs_diff = (self.0 - other.0).abs();
1039 let largest = self.0.abs().max(other.0.abs());
1040 abs_diff <= epsilon || abs_diff <= max_relative * largest
1041 }
1042}
1043
1044impl Sum for Positive {
1045 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1046 let sum = iter.fold(Decimal::ZERO, |acc, x| acc + x.value());
1047 Positive::new_decimal(sum).unwrap_or(Positive::ZERO)
1048 }
1049}
1050
1051impl<'a> Sum<&'a Positive> for Positive {
1052 fn sum<I: Iterator<Item = &'a Positive>>(iter: I) -> Self {
1053 let sum = iter.fold(Decimal::ZERO, |acc, x| acc + x.value());
1054 Positive::new_decimal(sum).unwrap_or(Positive::ZERO)
1055 }
1056}