positive/
positive.rs

1/******************************************************************************
2   Author: Joaquín Béjar García
3   Email: jb@taunais.com
4   Date: 25/12/24
5******************************************************************************/
6
7//! Core implementation of the Positive type.
8
9use 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
23/// Default epsilon value for approximate comparisons.
24pub const EPSILON: Decimal = dec!(1e-16);
25
26/// A wrapper type that represents a guaranteed positive decimal value.
27///
28/// This type encapsulates a `Decimal` value and ensures through its API that
29/// the contained value is always positive (greater than or equal to zero).
30#[derive(PartialEq, Clone, Copy, Hash)]
31#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
32pub struct Positive(pub Decimal);
33
34/// Macro for creating a `Positive` value from the given expression.
35///
36/// Returns `Ok(Positive)` if the value is valid and non-negative,
37/// otherwise returns `Err(PositiveError)`.
38///
39/// # Example
40///
41/// ```rust
42/// use positive::pos;
43///
44/// let valid = pos!(5.0);
45/// assert!(valid.is_ok());
46///
47/// let invalid = pos!(-5.0);
48/// assert!(invalid.is_err());
49/// ```
50#[macro_export]
51macro_rules! pos {
52    ($val:expr) => {
53        $crate::Positive::new($val)
54    };
55}
56
57/// Macro for creating a new `Positive` value that panics on invalid input.
58///
59/// Use this macro when you are certain the value is valid and want to
60/// avoid handling the `Result`. For safer alternatives, use `pos!()` which
61/// returns `Result<Positive, PositiveError>`.
62///
63/// # Panics
64///
65/// This macro will panic if the provided value cannot be converted to a `Positive` value
66/// (e.g., negative numbers or values that cannot be represented as `Decimal`).
67///
68/// # Example
69///
70/// ```rust
71/// use positive::pos_or_panic;
72///
73/// let value = pos_or_panic!(5.0);
74/// assert_eq!(value.to_f64(), 5.0);
75/// ```
76#[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 for creating an optional `Positive` value from the given expression.
84///
85/// Returns `Some(Positive)` if the value is valid and non-negative,
86/// otherwise returns `None`. This is useful when you want to ignore errors.
87///
88/// # Example
89///
90/// ```rust
91/// use positive::spos;
92///
93/// let valid = spos!(5.0);
94/// assert!(valid.is_some());
95///
96/// let invalid = spos!(-5.0);
97/// assert!(invalid.is_none());
98/// ```
99#[macro_export]
100macro_rules! spos {
101    ($val:expr) => {
102        $crate::Positive::new($val).ok()
103    };
104}
105
106/// Determines if the given type parameter `T` is the `Positive` type.
107#[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    /// A zero value represented as a `Positive` value.
114    pub const ZERO: Positive = Positive(Decimal::ZERO);
115    /// A value of one represented as a `Positive` value.
116    pub const ONE: Positive = Positive(Decimal::ONE);
117    /// A value of two represented as a `Positive` value.
118    pub const TWO: Positive = Positive(Decimal::TWO);
119    /// Represents the maximum positive value possible (effectively infinity).
120    pub const INFINITY: Positive = Positive(Decimal::MAX);
121    /// A value of ten represented as a `Positive` value.
122    pub const TEN: Positive = Positive(Decimal::TEN);
123    /// A value of one hundred represented as a `Positive` value.
124    pub const HUNDRED: Positive = Positive(Decimal::ONE_HUNDRED);
125    /// A value of one thousand represented as a `Positive` value.
126    pub const THOUSAND: Positive = Positive(Decimal::ONE_THOUSAND);
127    /// The mathematical constant π (pi) represented as a `Positive` value.
128    pub const PI: Positive = Positive(Decimal::PI);
129
130    /// The mathematical constant e (Euler's number) represented as a `Positive` value.
131    pub const E: Positive = Positive(Decimal::E);
132
133    /// Creates a new `Positive` value from a 64-bit floating-point number.
134    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    /// Creates a new `Positive` value directly from a `Decimal`.
152    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    /// Returns the inner `Decimal` value.
165    #[must_use]
166    pub fn value(&self) -> Decimal {
167        self.0
168    }
169
170    /// Returns the inner `Decimal` value (alias for `value()`).
171    #[must_use]
172    pub fn to_dec(&self) -> Decimal {
173        self.0
174    }
175
176    /// Returns the inner `Decimal` ref.
177    #[must_use]
178    pub fn to_dec_ref(&self) -> &Decimal {
179        &self.0
180    }
181
182    /// Converts the value to a 64-bit floating-point number.
183    ///
184    /// # Panics
185    ///
186    /// This method will panic if the conversion fails. Use `to_f64_checked()`
187    /// or `to_f64_lossy()` for non-panicking alternatives.
188    #[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    /// Converts the value to f64, returning None if conversion fails.
196    #[must_use]
197    pub fn to_f64_checked(&self) -> Option<f64> {
198        self.0.to_f64()
199    }
200
201    /// Converts the value to f64 with lossy conversion (returns 0.0 on failure).
202    #[must_use]
203    pub fn to_f64_lossy(&self) -> f64 {
204        self.0.to_f64().unwrap_or(0.0)
205    }
206
207    /// Converts the value to a 64-bit signed integer.
208    ///
209    /// # Panics
210    ///
211    /// This method will panic if the conversion fails. Use `to_i64_checked()`
212    /// for a non-panicking alternative.
213    #[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    /// Converts the value to i64, returning None if conversion fails.
221    #[must_use]
222    pub fn to_i64_checked(&self) -> Option<i64> {
223        self.0.to_i64()
224    }
225
226    /// Converts the inner value to a `u64`.
227    ///
228    /// # Panics
229    ///
230    /// This method will panic if the conversion fails. Use `to_u64_checked()`
231    /// for a non-panicking alternative.
232    #[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    /// Converts the value to u64, returning None if conversion fails.
240    #[must_use]
241    pub fn to_u64_checked(&self) -> Option<u64> {
242        self.0.to_u64()
243    }
244
245    /// Converts the value to a usize.
246    ///
247    /// # Panics
248    ///
249    /// This method will panic if the conversion fails. Use `to_usize_checked()`
250    /// for a non-panicking alternative.
251    #[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    /// Converts the value to usize, returning None if conversion fails.
259    #[must_use]
260    pub fn to_usize_checked(&self) -> Option<usize> {
261        self.0.to_usize()
262    }
263
264    /// Returns the maximum of two `Positive` values.
265    #[must_use]
266    pub fn max(self, other: Positive) -> Positive {
267        if self.0 > other.0 { self } else { other }
268    }
269
270    /// Returns the minimum of two `Positive` values.
271    #[must_use]
272    pub fn min(self, other: Positive) -> Positive {
273        if self.0 < other.0 { self } else { other }
274    }
275
276    /// Rounds the value down to the nearest integer.
277    #[must_use]
278    pub fn floor(&self) -> Positive {
279        Positive(self.0.floor())
280    }
281
282    /// Raises this value to an integer power.
283    #[must_use]
284    pub fn powi(&self, n: i64) -> Positive {
285        Positive(self.0.powi(n))
286    }
287
288    /// Computes the result of raising the current value to the power of the given exponent.
289    #[must_use]
290    pub fn pow(&self, n: Positive) -> Positive {
291        Positive(self.0.pow(n.to_dec()))
292    }
293
294    /// Raises the current value to the power of `n` using unsigned integer exponentiation.
295    #[must_use]
296    pub fn powu(&self, n: u64) -> Positive {
297        Positive(self.0.powu(n))
298    }
299
300    /// Raises this value to a decimal power.
301    #[must_use]
302    pub fn powd(&self, p0: Decimal) -> Positive {
303        Positive(self.0.powd(p0))
304    }
305
306    /// Rounds the value to the nearest integer.
307    #[must_use]
308    pub fn round(&self) -> Positive {
309        Positive(self.0.round())
310    }
311
312    /// Rounds the current value to a "nice" number, based on its magnitude.
313    #[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    /// Calculates the square root of the value.
331    ///
332    /// # Panics
333    ///
334    /// This method will panic if the square root calculation fails.
335    /// Use `sqrt_checked()` for a non-panicking alternative.
336    #[must_use]
337    pub fn sqrt(&self) -> Positive {
338        Positive(self.0.sqrt().expect("Square root calculation failed"))
339    }
340
341    /// Calculates the square root, returning an error if it fails.
342    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    /// Calculates the natural logarithm of the value.
349    #[must_use]
350    pub fn ln(&self) -> Positive {
351        Positive(self.0.ln())
352    }
353
354    /// Rounds the value to a specified number of decimal places.
355    #[must_use]
356    pub fn round_to(&self, decimal_places: u32) -> Positive {
357        Positive(self.0.round_dp(decimal_places))
358    }
359
360    /// Formats the value with a fixed number of decimal places.
361    #[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    /// Calculates the exponential function e^x for this value.
368    #[must_use]
369    pub fn exp(&self) -> Positive {
370        Positive(self.0.exp())
371    }
372
373    /// Clamps the value between a minimum and maximum.
374    #[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    /// Checks if the value is exactly zero.
386    #[must_use]
387    pub fn is_zero(&self) -> bool {
388        self.0.is_zero()
389    }
390
391    /// Returns the smallest integer greater than or equal to the value.
392    #[must_use]
393    pub fn ceiling(&self) -> Positive {
394        Positive::from(self.to_dec().ceil())
395    }
396
397    /// Computes the base-10 logarithm of the value.
398    #[must_use]
399    pub fn log10(&self) -> Positive {
400        Positive(self.0.log10())
401    }
402
403    /// Subtracts a decimal value, returning zero if the result would be negative.
404    #[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    /// Subtracts a decimal value, returning None if the result would be negative.
414    #[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    /// Checked subtraction that returns Result instead of panicking.
424    pub fn checked_sub(&self, rhs: &Self) -> Result<Self, PositiveError> {
425        Positive::new_decimal(self.0 - rhs.0)
426    }
427
428    /// Saturating subtraction that returns ZERO instead of negative.
429    #[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    /// Checked division that returns Result instead of panicking.
439    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    /// Checks whether the value is a multiple of another f64 value.
451    #[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    /// Checks whether the value is a multiple of another Positive value.
462    #[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}