pure_decimal/
pure_decimal.rs

1use decimal::d128;
2use std::str::FromStr;
3use std::fmt;
4use std::hash::{Hash, Hasher};
5use std::default::Default;
6use std::ops::{Add, Div, Mul, Neg, Rem, Sub, AddAssign, SubAssign, MulAssign};
7use std::borrow::Borrow;
8use std::iter::Sum;
9
10use super::error::Error;
11
12
13///
14/// # Examples:
15/// ```
16/// # #[macro_use]
17/// # extern crate pure_decimal;
18///
19/// # use std::collections::BTreeMap;
20///
21/// # fn main() {
22///
23/// // Use as keys in BTree
24/// let mut map = BTreeMap::new();
25/// map.insert(dec!(1.0), dec!(1.0));
26/// map.insert(dec!(1), dec!(2.0));
27///
28/// assert!(map.len() == 1);
29/// assert!(map.contains_key(&dec!(1.00)));
30/// assert!(map.get(&dec!(1.00)) == Some(&dec!(2.0)));
31///
32/// # }
33/// ```
34#[derive(Clone, Copy)]
35pub struct Decimal(pub(crate) d128);
36
37impl Decimal {
38    /// Creates a Decimal with `0` as value
39    pub fn zero() -> Self {
40        Decimal(d128::zero())
41    }
42
43    /// returns the larger of `self` and `other`
44    pub fn max<O: AsRef<Decimal>>(self, other: O) -> Decimal {
45        Decimal(self.0.max(other.as_ref().0))
46    }
47
48    /// returns the smaller of `self` and `other`
49    pub fn min<O: AsRef<Decimal>>(self, other: O) -> Decimal {
50        Decimal(self.0.min(other.as_ref().0))
51    }
52
53    /// returns absolute value of `self`
54    pub fn abs(&self) -> Decimal {
55        Decimal(self.0.abs())
56    }
57
58    /// Calculates the fused multiply-add `self` × `a` + `b` and returns the result. The multiply
59    /// is carried out first and is exact, so this operation has only the one, final, rounding.
60    pub fn mul_add<O: AsRef<Decimal>>(self, a: O, b: O) -> Decimal {
61        Decimal(self.0.mul_add(a.as_ref().0, b.as_ref().0))
62    }
63
64    /// returns true if `self` is less than zero
65    pub fn is_negative(&self) -> bool {
66        self.0.is_negative()
67    }
68
69    pub fn is_positive(&self) -> bool {
70        self.0.is_positive()
71    }
72
73    /// returns true if `self` is zero
74    pub fn is_zero(&self) -> bool {
75        self.0.is_zero()
76    }
77
78    /// see ```[decimal::d128::pow]```
79    pub fn pow<O: AsRef<Decimal>>(self, exp: O) -> Decimal {
80        Decimal(self.as_ref().0.pow(exp.as_ref().0))
81    }
82}
83
84impl Default for Decimal {
85    fn default() -> Self {
86        Self::zero()
87    }
88}
89
90impl Hash for Decimal {
91    fn hash<H: Hasher>(&self, state: &mut H) {
92        self.0.hash(state);
93    }
94}
95
96impl FromStr for Decimal {
97    type Err = Error;
98
99    fn from_str(s: &str) -> Result<Self, Error> {
100        let val = d128::from_str(s);
101        if val.is_ok() {
102            let dec = val.unwrap();
103            if dec.is_nan() {
104                Err(Error::new("NaN is not supported"))
105            } else if dec.is_infinite() {
106                Err(Error::new("Infinity is not supported"))
107            } else {
108                Ok(Decimal(dec))
109            }
110        } else {
111            Err(Error::new("Failed to parse"))
112        }
113    }
114}
115
116/// Delegates to d128.
117impl fmt::Display for Decimal {
118    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
119        self.0.fmt(fmt)
120    }
121}
122
123/// Delegates to d128.
124impl fmt::Debug for Decimal {
125    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
126        self.0.fmt(fmt)
127    }
128}
129
130/// Delegates to d128.
131impl fmt::LowerExp for Decimal {
132    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
133        self.0.fmt(fmt)
134    }
135}
136
137/// Delegates to d128.
138impl fmt::LowerHex for Decimal {
139    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
140        self.0.fmt(fmt)
141    }
142}
143
144
145impl PartialEq<Decimal> for Decimal {
146    fn eq(&self, other: &Decimal) -> bool {
147        self.0.eq(&other.0)
148    }
149}
150
151impl Eq for Decimal {}
152
153impl PartialOrd<Decimal> for Decimal {
154    fn partial_cmp(&self, other: &Decimal) -> Option<::std::cmp::Ordering> {
155        self.0.partial_cmp(&other.0)
156    }
157}
158
159impl Ord for Decimal {
160    fn cmp(&self, other: &Decimal) -> ::std::cmp::Ordering {
161        let res = self.0.partial_cmp(&other.0);
162        match res {
163            None => panic!("Ordering not possible. Possible bug"),
164            Some(ord) => ord,
165        }
166    }
167}
168
169impl From<i32> for Decimal {
170    fn from(val: i32) -> Decimal {
171        Decimal(d128::from(val))
172    }
173}
174
175/// Converts an u32 to d128. The result is exact and no error is possible.
176impl From<u32> for Decimal {
177    fn from(val: u32) -> Decimal {
178        Decimal(d128::from(val))
179    }
180}
181
182/// Converts an u64 to d128. The result is exact and no error is possible.
183impl From<u64> for Decimal {
184    fn from(val: u64) -> Decimal {
185        Decimal(d128::from(val))
186    }
187}
188
189/// Converts an i64 to d128. The result is exact and no error is possible.
190impl From<i64> for Decimal {
191    fn from(val: i64) -> Decimal {
192        Decimal(d128::from(val))
193    }
194}
195
196impl AsRef<Decimal> for Decimal {
197    fn as_ref(&self) -> &Decimal {
198        self
199    }
200}
201
202macro_rules! unary_op {
203    ($(#[$attr:meta])* impl $op:ident, $method:ident) => {
204        $(#[$attr])*
205        impl $op for Decimal {
206            type Output = Decimal;
207
208            fn $method(self) -> Decimal {
209                Decimal((self.0).$method())
210            }
211        }
212
213        impl<'a> $op for &'a Decimal {
214            type Output = Decimal;
215
216            fn $method(self) -> Decimal {
217                Decimal((self.0).$method())
218            }
219        }
220    }
221}
222
223unary_op!(impl Neg, neg);
224
225macro_rules! binary_op {
226    ($(#[$attr:meta])* impl $op:ident, $method:ident, $t:ident) => {
227        $(#[$attr])*
228        impl $op<$t> for $t {
229            type Output = $t;
230
231            fn $method(self, other: $t) -> $t {
232                Decimal((self.0).$method(other.0))
233            }
234        }
235
236        impl<'a> $op<$t> for &'a $t {
237            type Output = $t;
238
239            fn $method(self, other: $t) -> $t {
240                Decimal((self.0).$method(other.0))
241            }
242        }
243
244        impl<'a> $op<&'a$t> for $t {
245            type Output = $t;
246
247            fn $method(self, other: &'a $t) -> $t {
248                Decimal((self.0).$method(other.0))
249            }
250        }
251
252        impl<'a, 'b> $op<&'a $t> for &'b $t {
253            type Output = $t;
254
255            fn $method(self, other: &'a $t) -> $t {
256                Decimal((self.0).$method(other.0))
257            }
258        }
259    }
260}
261
262binary_op!(impl Add, add, Decimal);
263binary_op!(impl Sub, sub, Decimal);
264binary_op!(impl Mul, mul, Decimal);
265
266macro_rules! guarded_binary_op {
267    ($(#[$attr:meta])* impl $op:ident, $method:ident, $t:ident) => {
268
269
270        $(#[$attr])*
271        impl $op<$t> for $t {
272            type Output = ::std::result::Result<$t, Error>;
273
274            /// Returns `Ok(Decimal)` if result is finite `Err` otherwise
275            fn $method(self, other: $t) -> ::std::result::Result<$t, Error> {
276                let val = (self.0).$method(other.0);
277                if val.is_finite() {
278                    Ok(Decimal(val))
279                }else{
280                 Err(Error::new("Only finite value are supported"))
281                }
282            }
283        }
284
285        impl<'a> $op<$t> for &'a $t {
286            type Output = ::std::result::Result<$t, Error>;
287
288            /// Returns `Ok(Decimal)` if result is finite `Err` otherwise
289            fn $method(self, other: $t) -> ::std::result::Result<$t, Error> {
290                let val = (self.0).$method(other.0);
291                if val.is_finite() {
292                    Ok(Decimal(val))
293                }else{
294                 Err(Error::new("Only finite value are supported"))
295                }
296            }
297        }
298
299        impl<'a> $op<&'a$t> for $t {
300            type Output = ::std::result::Result<$t, Error>;
301
302            /// Returns `Ok(Decimal)` if result is finite `Err` otherwise
303            fn $method(self, other: &'a $t) -> ::std::result::Result<$t, Error> {
304                let val = (self.0).$method(other.0);
305                if val.is_finite() {
306                    Ok(Decimal(val))
307                }else{
308                 Err(Error::new("Only finite value are supported"))
309                }
310            }
311        }
312
313        impl<'a, 'b> $op<&'a $t> for &'b $t {
314            type Output = ::std::result::Result<$t, Error>;
315
316            /// Returns `Ok(Decimal)` if result is finite `Err` otherwise
317            fn $method(self, other: &'a $t) -> ::std::result::Result<$t, Error> {
318                let val = (self.0).$method(other.0);
319                if val.is_finite() {
320                    Ok(Decimal(val))
321                }else{
322                 Err(Error::new("Only finite value are supported"))
323                }
324            }
325        }
326    }
327}
328
329guarded_binary_op!(impl Div, div, Decimal);
330guarded_binary_op!(impl Rem, rem, Decimal);
331
332
333macro_rules! unary_assign_op {
334    ($(#[$attr:meta])* impl $op:ident, $method:ident, $t:ident) => {
335        $(#[$attr])*
336        impl $op<$t> for $t {
337            fn $method(&mut self, other: $t) {
338                (self.0).$method(other.0);
339            }
340        }
341    }
342}
343
344unary_assign_op!(impl AddAssign, add_assign, Decimal);
345unary_assign_op!(impl SubAssign, sub_assign, Decimal);
346unary_assign_op!(impl MulAssign, mul_assign, Decimal);
347
348
349impl<T> Sum<T> for Decimal where T: Borrow<Decimal> {
350    fn sum<I: IntoIterator<Item=T>>(iter: I) -> Decimal {
351        iter.into_iter()
352            .fold(Decimal::zero(), |acc, val| acc + val.borrow())
353    }
354}
355
356
357
358#[cfg(test)]
359mod tests {
360    use super::*;
361
362    #[test]
363    fn default() {
364        use std::str::FromStr;
365
366        assert_eq!(Decimal::zero(), Decimal::default());
367        assert_eq!(Decimal::zero(), Default::default());
368        assert_eq!(Decimal::zero(), Decimal::from_str("0").unwrap());
369        assert_eq!(Decimal::zero(), Decimal::from_str("0.0").unwrap());
370    }
371
372    #[test]
373    fn unary_op() {
374        assert_eq!(dec!(-1.1), -dec!(1.1));
375        assert_eq!(dec!(-1.1), -&dec!(1.1));
376    }
377
378    #[test]
379    fn utility_functions() {
380        assert!(dec!(0.0).is_zero());
381        assert_ne!(true,dec!(0.0).is_negative());
382        assert_ne!(true,dec!(0.0).is_positive());
383
384        assert_ne!(true,dec!(0.1).is_zero());
385        assert_ne!(true,dec!(0.1).is_negative());
386        assert!(dec!(0.1).is_positive());
387
388        assert_ne!(true,dec!(-0.1).is_zero());
389        assert!(dec!(-0.1).is_negative());
390        assert_ne!(true,dec!(-0.1).is_positive());
391
392    }
393
394    #[test]
395    fn binary_op() {
396        assert_eq!(dec!(3.33), dec!(1.11) + dec!(2.22));
397        assert_eq!(dec!(3.33), &dec!(1.11) + dec!(2.22));
398        assert_eq!(dec!(3.33), dec!(1.11) + &dec!(2.22));
399        assert_eq!(dec!(3.33), &dec!(1.11) + &dec!(2.22));
400        //assert_eq!(dec!(5) << 2, dec!(500));
401        //assert_eq!(dec!(500) >> 1, dec!(50));
402    }
403
404    #[test]
405    fn as_ref_operand() {
406        assert_eq!(dec!(1.1), dec!(1.1).min(dec!(2.2)));
407        assert_eq!(dec!(1.1), dec!(1.1).min(&dec!(2.2)));
408    }
409
410
411    #[test]
412    fn assign_op() {
413        let mut x = dec!(1);
414        x += dec!(2);
415        assert_eq!(x, dec!(3));
416        x *= dec!(3);
417        assert_eq!(x, dec!(9));
418        x -= dec!(1);
419        assert_eq!(x, dec!(8));
420    }
421
422    #[test]
423    fn test_sum() {
424        let decimals = vec![dec!(1), dec!(2), dec!(3), dec!(4)];
425        assert_eq!(dec!(10), decimals.iter().sum());
426        assert_eq!(dec!(10), decimals.into_iter().sum());
427    }
428}