dec/
ordered.rs

1// Copyright Materialize, Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.inner (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License in the LICENSE file at the
6// root of this repository, or online at
7//
8//     http://www.apache.org/licenses/LICENSE-2.inner
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use std::cmp::Ordering;
17use std::fmt;
18use std::hash::{Hash, Hasher};
19use std::iter::{Product, Sum};
20use std::ops::{
21    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
22};
23use std::str::FromStr;
24
25#[cfg(feature = "serde")]
26use serde::{Deserialize, Serialize};
27
28use crate::context::Context;
29use crate::decimal::Decimal;
30use crate::decimal128::Decimal128;
31use crate::decimal32::Decimal32;
32use crate::decimal64::Decimal64;
33use crate::error::ParseDecimalError;
34
35/// A wrapper for a decimal number that provides an implementation of [`Ord`]
36/// and [`Hash`].
37///
38/// Like the [`OrderedFloat`] type provided by the [`ordered_float`] crate, but
39/// for decimals.
40///
41/// NaN is treated as equal to itself and greater than all non-NaN values. All
42/// other values are compared via their `PartialOrd` implementation.
43///
44/// At the moment `OrderedDecimal` can only wrap [`Decimal64`] and
45/// [`Decimal128`]. Support for [`Decimal32`](crate::Decimal32) is not planned,
46/// but support for [`Decimal<N>`](crate::Decimal) would be welcomed, provided a
47/// suitable implementation can be found.
48///
49/// Note that the order used by `OrderedDecimal` is *not* the same as the order
50/// used by the [`total_cmp`](Decimal64::total_cmp) method. The `total_cmp`
51/// method takes exponents into account and therefore does not consider e.g.
52/// `1.2` and `1.20` to be equal.
53///
54/// [`OrderedFloat`]: https://docs.rs/ordered-float/2.0.1/ordered_float/struct.OrderedFloat.html
55/// [`ordered_float`]: https://crates.io/crates/ordered-float
56#[derive(Debug, Clone, Copy)]
57#[repr(transparent)]
58#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
59pub struct OrderedDecimal<D>(pub D);
60
61impl<D> OrderedDecimal<D> {
62    /// Consumes the ordered decimal wrapper, returning the decimal within.
63    pub fn into_inner(self) -> D {
64        self.0
65    }
66}
67
68impl<D> fmt::Display for OrderedDecimal<D>
69where
70    D: fmt::Display,
71{
72    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73        self.0.fmt(f)
74    }
75}
76
77impl<D> PartialOrd for OrderedDecimal<D>
78where
79    Self: Ord,
80{
81    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
82        Some(self.cmp(other))
83    }
84}
85
86impl<D> PartialEq for OrderedDecimal<D>
87where
88    Self: Ord,
89{
90    fn eq(&self, other: &Self) -> bool {
91        self.cmp(other) == Ordering::Equal
92    }
93}
94
95impl<D> Eq for OrderedDecimal<D> where Self: Ord {}
96
97impl Ord for OrderedDecimal<Decimal64> {
98    fn cmp(&self, other: &Self) -> Ordering {
99        let mut cx = Context::<Decimal64>::default();
100        let lhs = cx.reduce(self.0);
101        let rhs = cx.reduce(other.0);
102        match cx.partial_cmp(lhs, rhs) {
103            Some(ordering) => ordering,
104            None => {
105                if lhs.is_nan() {
106                    if rhs.is_nan() {
107                        Ordering::Equal
108                    } else {
109                        Ordering::Greater
110                    }
111                } else {
112                    Ordering::Less
113                }
114            }
115        }
116    }
117}
118
119impl Hash for OrderedDecimal<Decimal64> {
120    fn hash<H>(&self, state: &mut H)
121    where
122        H: Hasher,
123    {
124        let d = if self.0.is_nan() {
125            Decimal64::NAN
126        } else if self.0.is_zero() {
127            Decimal64::ZERO
128        } else {
129            Context::<Decimal64>::default().reduce(self.0)
130        };
131        d.inner.bytes.hash(state)
132    }
133}
134
135impl Ord for OrderedDecimal<Decimal128> {
136    fn cmp(&self, other: &Self) -> Ordering {
137        let mut cx = Context::<Decimal128>::default();
138        let lhs = cx.reduce(self.0);
139        let rhs = cx.reduce(other.0);
140        match cx.partial_cmp(lhs, rhs) {
141            Some(ordering) => ordering,
142            None => {
143                if lhs.is_nan() {
144                    if rhs.is_nan() {
145                        Ordering::Equal
146                    } else {
147                        Ordering::Greater
148                    }
149                } else {
150                    Ordering::Less
151                }
152            }
153        }
154    }
155}
156
157impl Hash for OrderedDecimal<Decimal128> {
158    fn hash<H>(&self, state: &mut H)
159    where
160        H: Hasher,
161    {
162        let d = if self.0.is_nan() {
163            Decimal128::NAN
164        } else if self.0.is_zero() {
165            Decimal128::ZERO
166        } else {
167            Context::<Decimal128>::default().reduce(self.0)
168        };
169        d.inner.bytes.hash(state)
170    }
171}
172
173impl<const N: usize> Ord for OrderedDecimal<Decimal<N>> {
174    fn cmp(&self, other: &Self) -> Ordering {
175        let mut cx = Context::<Decimal<N>>::default();
176        let mut lhs = self.0.clone();
177        let mut rhs = other.0.clone();
178        cx.reduce(&mut lhs);
179        cx.reduce(&mut rhs);
180        match cx.partial_cmp(&lhs, &rhs) {
181            Some(ordering) => ordering,
182            None => {
183                if lhs.is_nan() {
184                    if rhs.is_nan() {
185                        Ordering::Equal
186                    } else {
187                        Ordering::Greater
188                    }
189                } else {
190                    Ordering::Less
191                }
192            }
193        }
194    }
195}
196
197impl<const N: usize> Hash for OrderedDecimal<Decimal<N>> {
198    fn hash<H>(&self, state: &mut H)
199    where
200        H: Hasher,
201    {
202        let d = if self.0.is_nan() {
203            Decimal::<N>::nan()
204        } else if self.0.is_infinite() {
205            let mut d = Decimal::<N>::infinity();
206            if self.0.is_negative() {
207                Context::<Decimal<N>>::default().minus(&mut d);
208            }
209            d
210        } else if self.0.is_zero() {
211            Decimal::<N>::zero()
212        } else {
213            let mut d = self.0.clone();
214            Context::<Decimal<N>>::default().reduce(&mut d);
215            d
216        };
217        d.digits.hash(state);
218        d.exponent.hash(state);
219        d.bits.hash(state);
220        d.coefficient_units().hash(state);
221    }
222}
223
224impl<D> Default for OrderedDecimal<D>
225where
226    D: Default,
227{
228    fn default() -> Self {
229        OrderedDecimal(D::default())
230    }
231}
232
233impl<D> FromStr for OrderedDecimal<D>
234where
235    D: FromStr<Err = ParseDecimalError>,
236{
237    type Err = ParseDecimalError;
238
239    fn from_str(s: &str) -> Result<OrderedDecimal<D>, ParseDecimalError> {
240        Ok(OrderedDecimal(D::from_str(s)?))
241    }
242}
243
244impl<D> From<i32> for OrderedDecimal<D>
245where
246    D: From<i32>,
247{
248    fn from(n: i32) -> OrderedDecimal<D> {
249        OrderedDecimal(D::from(n))
250    }
251}
252
253impl<D> From<u32> for OrderedDecimal<D>
254where
255    D: From<u32>,
256{
257    fn from(n: u32) -> OrderedDecimal<D> {
258        OrderedDecimal(D::from(n))
259    }
260}
261
262impl<D> From<Decimal32> for OrderedDecimal<D>
263where
264    D: From<Decimal32>,
265{
266    fn from(n: Decimal32) -> OrderedDecimal<D> {
267        OrderedDecimal(D::from(n))
268    }
269}
270
271impl<D> From<Decimal64> for OrderedDecimal<D>
272where
273    D: From<Decimal64>,
274{
275    fn from(n: Decimal64) -> OrderedDecimal<D> {
276        OrderedDecimal(D::from(n))
277    }
278}
279
280impl<D> From<Decimal128> for OrderedDecimal<D>
281where
282    D: From<Decimal128>,
283{
284    fn from(n: Decimal128) -> OrderedDecimal<D> {
285        OrderedDecimal(D::from(n))
286    }
287}
288
289impl<D> Add for OrderedDecimal<D>
290where
291    D: Add<Output = D>,
292{
293    type Output = Self;
294
295    fn add(self, other: OrderedDecimal<D>) -> Self {
296        OrderedDecimal(self.0 + other.0)
297    }
298}
299
300impl<D> Add<D> for OrderedDecimal<D>
301where
302    D: Add<Output = D>,
303{
304    type Output = Self;
305
306    fn add(self, other: D) -> Self {
307        OrderedDecimal(self.0 + other)
308    }
309}
310
311impl Add<OrderedDecimal<Decimal64>> for Decimal64 {
312    type Output = Self;
313
314    fn add(self, other: OrderedDecimal<Decimal64>) -> Self {
315        self + other.0
316    }
317}
318
319impl Add<OrderedDecimal<Decimal128>> for Decimal128 {
320    type Output = Self;
321
322    fn add(self, other: OrderedDecimal<Decimal128>) -> Self {
323        self + other.0
324    }
325}
326
327impl<D> AddAssign for OrderedDecimal<D>
328where
329    D: AddAssign,
330{
331    fn add_assign(&mut self, other: Self) {
332        self.0 += other.0;
333    }
334}
335
336/// Adds inner directly.
337impl<D> AddAssign<D> for OrderedDecimal<D>
338where
339    D: Add<Output = D> + Copy,
340{
341    fn add_assign(&mut self, other: D) {
342        *self = *self + other;
343    }
344}
345
346impl<D> Sub for OrderedDecimal<D>
347where
348    D: Sub<Output = D>,
349{
350    type Output = Self;
351
352    fn sub(self, other: OrderedDecimal<D>) -> Self {
353        OrderedDecimal(self.0 - other.0)
354    }
355}
356
357impl<D> Sub<D> for OrderedDecimal<D>
358where
359    D: Sub<Output = D>,
360{
361    type Output = Self;
362
363    fn sub(self, other: D) -> Self {
364        OrderedDecimal(self.0 - other)
365    }
366}
367
368impl Sub<OrderedDecimal<Decimal64>> for Decimal64 {
369    type Output = Self;
370
371    fn sub(self, other: OrderedDecimal<Decimal64>) -> Self {
372        self - other.0
373    }
374}
375
376impl Sub<OrderedDecimal<Decimal128>> for Decimal128 {
377    type Output = Self;
378
379    fn sub(self, other: OrderedDecimal<Decimal128>) -> Self {
380        self - other.0
381    }
382}
383
384impl<D> SubAssign for OrderedDecimal<D>
385where
386    D: SubAssign,
387{
388    fn sub_assign(&mut self, other: Self) {
389        self.0 -= other.0;
390    }
391}
392
393/// Subs inner directly.
394impl<D> SubAssign<D> for OrderedDecimal<D>
395where
396    D: Sub<Output = D> + Copy,
397{
398    fn sub_assign(&mut self, other: D) {
399        *self = *self - other;
400    }
401}
402impl<D> Mul for OrderedDecimal<D>
403where
404    D: Mul<Output = D>,
405{
406    type Output = Self;
407
408    fn mul(self, other: OrderedDecimal<D>) -> Self {
409        OrderedDecimal(self.0 * other.0)
410    }
411}
412
413impl<D> Mul<D> for OrderedDecimal<D>
414where
415    D: Mul<Output = D>,
416{
417    type Output = Self;
418
419    fn mul(self, other: D) -> Self {
420        OrderedDecimal(self.0 * other)
421    }
422}
423
424impl Mul<OrderedDecimal<Decimal64>> for Decimal64 {
425    type Output = Self;
426
427    fn mul(self, other: OrderedDecimal<Decimal64>) -> Self {
428        self * other.0
429    }
430}
431
432impl Mul<OrderedDecimal<Decimal128>> for Decimal128 {
433    type Output = Self;
434
435    fn mul(self, other: OrderedDecimal<Decimal128>) -> Self {
436        self * other.0
437    }
438}
439
440impl<D> MulAssign for OrderedDecimal<D>
441where
442    D: MulAssign,
443{
444    fn mul_assign(&mut self, other: Self) {
445        self.0 *= other.0;
446    }
447}
448
449/// Muls inner directly.
450impl<D> MulAssign<D> for OrderedDecimal<D>
451where
452    D: Mul<Output = D> + Copy,
453{
454    fn mul_assign(&mut self, other: D) {
455        *self = *self * other;
456    }
457}
458
459impl<D> Div for OrderedDecimal<D>
460where
461    D: Div<Output = D>,
462{
463    type Output = Self;
464
465    fn div(self, other: OrderedDecimal<D>) -> Self {
466        OrderedDecimal(self.0 / other.0)
467    }
468}
469
470impl<D> Div<D> for OrderedDecimal<D>
471where
472    D: Div<Output = D>,
473{
474    type Output = Self;
475
476    fn div(self, other: D) -> Self {
477        OrderedDecimal(self.0 / other)
478    }
479}
480
481impl Div<OrderedDecimal<Decimal64>> for Decimal64 {
482    type Output = Self;
483
484    fn div(self, other: OrderedDecimal<Decimal64>) -> Self {
485        self / other.0
486    }
487}
488
489impl Div<OrderedDecimal<Decimal128>> for Decimal128 {
490    type Output = Self;
491
492    fn div(self, other: OrderedDecimal<Decimal128>) -> Self {
493        self / other.0
494    }
495}
496
497impl<D> DivAssign for OrderedDecimal<D>
498where
499    D: DivAssign,
500{
501    fn div_assign(&mut self, other: Self) {
502        self.0 /= other.0;
503    }
504}
505
506/// Divs inner directly.
507impl<D> DivAssign<D> for OrderedDecimal<D>
508where
509    D: Div<Output = D> + Copy,
510{
511    fn div_assign(&mut self, other: D) {
512        *self = *self / other;
513    }
514}
515
516impl<D> Rem for OrderedDecimal<D>
517where
518    D: Rem<Output = D>,
519{
520    type Output = Self;
521
522    fn rem(self, other: OrderedDecimal<D>) -> Self {
523        OrderedDecimal(self.0 % other.0)
524    }
525}
526
527impl<D> Rem<D> for OrderedDecimal<D>
528where
529    D: Rem<Output = D>,
530{
531    type Output = Self;
532
533    fn rem(self, other: D) -> Self {
534        OrderedDecimal(self.0 % other)
535    }
536}
537
538impl Rem<OrderedDecimal<Decimal64>> for Decimal64 {
539    type Output = Self;
540
541    fn rem(self, other: OrderedDecimal<Decimal64>) -> Self {
542        self % other.0
543    }
544}
545
546impl Rem<OrderedDecimal<Decimal128>> for Decimal128 {
547    type Output = Self;
548
549    fn rem(self, other: OrderedDecimal<Decimal128>) -> Self {
550        self % other.0
551    }
552}
553
554impl<D> RemAssign for OrderedDecimal<D>
555where
556    D: RemAssign,
557{
558    fn rem_assign(&mut self, other: Self) {
559        self.0 %= other.0;
560    }
561}
562
563/// Rems inner directly.
564impl<D> RemAssign<D> for OrderedDecimal<D>
565where
566    D: Rem<Output = D> + Copy,
567{
568    fn rem_assign(&mut self, other: D) {
569        *self = *self % other;
570    }
571}
572
573impl<D> Neg for OrderedDecimal<D>
574where
575    D: Neg<Output = D>,
576{
577    type Output = Self;
578
579    fn neg(self) -> Self {
580        OrderedDecimal(-self.0)
581    }
582}
583
584impl<D> Sum for OrderedDecimal<D>
585where
586    D: Sum,
587{
588    fn sum<I>(iter: I) -> Self
589    where
590        I: Iterator<Item = OrderedDecimal<D>>,
591    {
592        OrderedDecimal(iter.map(|v| v.0).sum())
593    }
594}
595
596impl<'a, D> Sum<&'a OrderedDecimal<D>> for OrderedDecimal<D>
597where
598    D: Sum<&'a D> + 'a,
599{
600    fn sum<I>(iter: I) -> Self
601    where
602        I: Iterator<Item = &'a OrderedDecimal<D>>,
603    {
604        OrderedDecimal(iter.map(|v| &v.0).sum())
605    }
606}
607
608impl<D> Product for OrderedDecimal<D>
609where
610    D: Product,
611{
612    fn product<I>(iter: I) -> Self
613    where
614        I: Iterator<Item = OrderedDecimal<D>>,
615    {
616        OrderedDecimal(iter.map(|v| v.0).product())
617    }
618}
619
620impl<'a, D> Product<&'a OrderedDecimal<D>> for OrderedDecimal<D>
621where
622    D: Product<&'a D> + 'a,
623{
624    fn product<I>(iter: I) -> Self
625    where
626        I: Iterator<Item = &'a OrderedDecimal<D>>,
627    {
628        OrderedDecimal(iter.map(|v| &v.0).product())
629    }
630}