Skip to main content

decimal_scaled/types/traits/
arithmetic.rs

1// SPDX-FileCopyrightText: 2026 John Moxley
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! The [`DecimalArithmetic`] trait — type info, operators, sign,
5//! pow / overflow-variant arithmetic, and reductions shared by every
6//! decimal width.
7//!
8//! Split out of the original [`crate::Decimal`] trait alongside
9//! [`crate::DecimalConvert`], [`crate::DecimalTranscendental`], and
10//! [`crate::DecimalConstants`]; `Decimal` is now a marker supertrait
11//! that requires all four. Callers who only need arithmetic (not
12//! conversions or transcendentals) can target this narrower bound:
13//!
14//! ```ignore
15//! use decimal_scaled::DecimalArithmetic;
16//!
17//! fn dot<T: DecimalArithmetic + Copy>(a: &[T], b: &[T]) -> T {
18//!     a.iter().zip(b).map(|(x, y)| (*x) * (*y))
19//!         .fold(T::ZERO, |acc, p| acc + p)
20//! }
21//! ```
22//!
23//! See [`crate::types::traits::decimal`] for the full scope rationale.
24
25/// Arithmetic surface shared by every decimal width: type info,
26/// constants, operators, sign methods, integer-shape predicates,
27/// integer-style division helpers, integer-exponent powers, the
28/// checked / wrapping / saturating / overflowing variants of every
29/// operator, and reductions (`sum` / `product`).
30///
31/// See module-level docs for usage; see [`crate::DecimalConvert`]
32/// for the conversion surface and [`crate::Decimal`] for the marker
33/// supertrait that combines all four halves.
34pub trait DecimalArithmetic:
35    Copy
36    + PartialEq
37    + Eq
38    + PartialOrd
39    + Ord
40    + Default
41    + core::fmt::Debug
42    + core::fmt::Display
43    + core::hash::Hash
44    + core::ops::Add<Output = Self>
45    + core::ops::Sub<Output = Self>
46    + core::ops::Mul<Output = Self>
47    + core::ops::Div<Output = Self>
48    + core::ops::Rem<Output = Self>
49    + core::ops::Neg<Output = Self>
50    + core::ops::AddAssign
51    + core::ops::SubAssign
52    + core::ops::MulAssign
53    + core::ops::DivAssign
54    + core::ops::RemAssign
55    + core::ops::BitAnd<Output = Self>
56    + core::ops::BitOr<Output = Self>
57    + core::ops::BitXor<Output = Self>
58    + core::ops::Not<Output = Self>
59    + core::ops::Shl<u32, Output = Self>
60    + core::ops::Shr<u32, Output = Self>
61{
62    /// Underlying integer storage type (e.g. `i128` for `D38<SCALE>`).
63    type Storage: Copy + PartialEq + Eq;
64
65    /// The decimal scale of this type.
66    const SCALE: u32;
67
68    /// The maximum legal `SCALE` for this width.
69    const MAX_SCALE: u32;
70
71    /// The additive identity.
72    const ZERO: Self;
73
74    /// The multiplicative identity.
75    const ONE: Self;
76
77    /// The largest representable value.
78    const MAX: Self;
79
80    /// The smallest representable value.
81    const MIN: Self;
82
83    /// Returns `10^SCALE`.
84    fn multiplier() -> Self::Storage;
85
86    // ── Sign ──────────────────────────────────────────────────────────
87
88    fn abs(self) -> Self;
89    fn signum(self) -> Self;
90    fn is_positive(self) -> bool;
91    fn is_negative(self) -> bool;
92
93    // ── Integer-shape predicates (always-const for decimals) ────────
94
95    fn is_nan(self) -> bool;
96    fn is_infinite(self) -> bool;
97    fn is_finite(self) -> bool;
98
99    // ── Integer methods ──────────────────────────────────────────────
100
101    fn div_euclid(self, rhs: Self) -> Self;
102    fn rem_euclid(self, rhs: Self) -> Self;
103    fn div_floor(self, rhs: Self) -> Self;
104    fn div_ceil(self, rhs: Self) -> Self;
105    fn abs_diff(self, rhs: Self) -> Self;
106    fn midpoint(self, rhs: Self) -> Self;
107    fn mul_add(self, a: Self, b: Self) -> Self;
108
109    // ── Integer-exponent powers ──────────────────────────────────────
110
111    fn pow(self, exp: u32) -> Self;
112    fn powi(self, exp: i32) -> Self;
113    fn checked_pow(self, exp: u32) -> Option<Self>;
114    fn wrapping_pow(self, exp: u32) -> Self;
115    fn saturating_pow(self, exp: u32) -> Self;
116    fn overflowing_pow(self, exp: u32) -> (Self, bool);
117
118    // ── Overflow-variant arithmetic ─────────────────────────────────
119
120    fn checked_add(self, rhs: Self) -> Option<Self>;
121    fn checked_sub(self, rhs: Self) -> Option<Self>;
122    fn checked_mul(self, rhs: Self) -> Option<Self>;
123    fn checked_div(self, rhs: Self) -> Option<Self>;
124    fn checked_neg(self) -> Option<Self>;
125    fn checked_rem(self, rhs: Self) -> Option<Self>;
126
127    fn wrapping_add(self, rhs: Self) -> Self;
128    fn wrapping_sub(self, rhs: Self) -> Self;
129    fn wrapping_mul(self, rhs: Self) -> Self;
130    fn wrapping_div(self, rhs: Self) -> Self;
131    fn wrapping_neg(self) -> Self;
132    fn wrapping_rem(self, rhs: Self) -> Self;
133
134    fn saturating_add(self, rhs: Self) -> Self;
135    fn saturating_sub(self, rhs: Self) -> Self;
136    fn saturating_mul(self, rhs: Self) -> Self;
137    fn saturating_div(self, rhs: Self) -> Self;
138    fn saturating_neg(self) -> Self;
139
140    fn overflowing_add(self, rhs: Self) -> (Self, bool);
141    fn overflowing_sub(self, rhs: Self) -> (Self, bool);
142    fn overflowing_mul(self, rhs: Self) -> (Self, bool);
143    fn overflowing_div(self, rhs: Self) -> (Self, bool);
144    fn overflowing_neg(self) -> (Self, bool);
145    fn overflowing_rem(self, rhs: Self) -> (Self, bool);
146
147    // ── Default reductions ───────────────────────────────────────────
148
149    #[inline]
150    fn is_zero(self) -> bool {
151        self == Self::ZERO
152    }
153
154    #[inline]
155    fn is_one(self) -> bool {
156        self == Self::ONE
157    }
158
159    #[inline]
160    fn is_normal(self) -> bool {
161        !self.is_zero()
162    }
163
164    #[inline]
165    fn sum<I>(iter: I) -> Self
166    where
167        I: IntoIterator<Item = Self>,
168    {
169        iter.into_iter().fold(Self::ZERO, |acc, x| acc + x)
170    }
171
172    #[inline]
173    fn product<I>(iter: I) -> Self
174    where
175        I: IntoIterator<Item = Self>,
176    {
177        iter.into_iter().fold(Self::ONE, |acc, x| acc * x)
178    }
179}