ink_primitives/
arithmetic.rs

1// Copyright (C) Use Ink (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Primitive traits for runtime arithmetic, copied from substrate
16
17use core::ops::{
18    Add,
19    AddAssign,
20    Div,
21    DivAssign,
22    Mul,
23    MulAssign,
24    Sub,
25    SubAssign,
26};
27use num_traits::{
28    checked_pow,
29    Bounded,
30    CheckedMul,
31    One,
32    Unsigned,
33    Zero,
34};
35
36/// Types that allow for simple arithmetic operations.
37///
38/// Subset of all trait bounds copied over from what Substrate defines
39/// for its `BaseArithmetic` types. We can extend this in the future
40/// if needed.
41pub trait BaseArithmetic:
42    Sized
43    + From<u8>
44    + Bounded
45    + Ord
46    + PartialOrd<Self>
47    + Zero
48    + One
49    + Bounded
50    + Add<Self, Output = Self>
51    + AddAssign<Self>
52    + Sub<Self, Output = Self>
53    + SubAssign<Self>
54    + Mul<Self, Output = Self>
55    + MulAssign<Self>
56    + Div<Self, Output = Self>
57    + DivAssign<Self>
58    + CheckedMul
59    + Saturating
60    + TryFrom<u16>
61    + TryFrom<u32>
62    + TryFrom<u64>
63    + TryFrom<u128>
64    + TryFrom<usize>
65    + TryInto<u16>
66    + TryInto<u32>
67    + TryInto<u64>
68    + TryInto<u128>
69    + TryInto<usize>
70// Further trait bounds from the original BaseArithmetic trait
71// that we could use to extend ink!'s BaseArithmetic trait.
72//
73// UniqueSaturatedInto<u8> +
74// UniqueSaturatedInto<u16> +
75// UniqueSaturatedInto<u32> +
76// UniqueSaturatedInto<u64> +
77// UniqueSaturatedInto<u128> +
78// UniqueSaturatedFrom<u64> +
79// UniqueSaturatedFrom<u128> +
80// Shl<u32, Output = Self> +
81// Shr<u32, Output = Self> +
82// CheckedAdd +
83// CheckedSub +
84// CheckedDiv +
85// CheckedShl +
86// CheckedShr +
87// IntegerSquareRoot +
88{
89}
90
91impl<T> BaseArithmetic for T where
92    T: Sized
93        + From<u8>
94        + Bounded
95        + Ord
96        + PartialOrd<Self>
97        + Zero
98        + One
99        + Add<Self, Output = Self>
100        + AddAssign<Self>
101        + Sub<Self, Output = Self>
102        + SubAssign<Self>
103        + Mul<Self, Output = Self>
104        + MulAssign<Self>
105        + Div<Self, Output = Self>
106        + DivAssign<Self>
107        + CheckedMul
108        + Saturating
109        + TryFrom<u16>
110        + TryFrom<u32>
111        + TryFrom<u64>
112        + TryFrom<u128>
113        + TryFrom<usize>
114        + TryInto<u16>
115        + TryInto<u32>
116        + TryInto<u64>
117        + TryInto<u128>
118        + TryInto<usize>
119{
120}
121
122/// A meta trait for arithmetic (copied from substrate).
123///
124/// Arithmetic types do all the usual stuff you'd expect numbers to do. They are
125/// guaranteed to be able to represent at least `u32` values without loss, hence the trait
126/// implies `From<u32>` and smaller integers. All other conversions are fallible.
127pub trait AtLeast32Bit: BaseArithmetic + From<u16> + From<u32> {}
128
129impl<T> AtLeast32Bit for T where T: BaseArithmetic + From<u16> + From<u32> {}
130
131/// A meta trait for arithmetic.  Same as [`AtLeast32Bit `], but also bounded to be
132/// unsigned.
133pub trait AtLeast32BitUnsigned: AtLeast32Bit + Unsigned {}
134
135impl<T> AtLeast32BitUnsigned for T where T: AtLeast32Bit + Unsigned {}
136
137/// Saturating arithmetic operations, returning maximum or minimum values instead of
138/// overflowing.
139#[allow(dead_code)]
140pub trait Saturating {
141    /// Saturating addition. Compute `self + rhs`, saturating at the numeric bounds
142    /// instead of overflowing.
143    fn saturating_add(self, rhs: Self) -> Self;
144
145    /// Saturating subtraction. Compute `self - rhs`, saturating at the numeric bounds
146    /// instead of overflowing.
147    fn saturating_sub(self, rhs: Self) -> Self;
148
149    /// Saturating multiply. Compute `self * rhs`, saturating at the numeric bounds
150    /// instead of overflowing.
151    fn saturating_mul(self, rhs: Self) -> Self;
152
153    /// Saturating exponentiation. Compute `self.pow(exp)`, saturating at the numeric
154    /// bounds instead of overflowing.
155    fn saturating_pow(self, exp: usize) -> Self;
156}
157
158impl<T> Saturating for T
159where
160    T: Clone + Zero + One + PartialOrd + CheckedMul + Bounded + num_traits::Saturating,
161{
162    fn saturating_add(self, o: Self) -> Self {
163        <Self as num_traits::Saturating>::saturating_add(self, o)
164    }
165
166    fn saturating_sub(self, o: Self) -> Self {
167        <Self as num_traits::Saturating>::saturating_sub(self, o)
168    }
169
170    fn saturating_mul(self, o: Self) -> Self {
171        self.checked_mul(&o).unwrap_or_else(|| {
172            if (self < T::zero()) != (o < T::zero()) {
173                Bounded::min_value()
174            } else {
175                Bounded::max_value()
176            }
177        })
178    }
179
180    fn saturating_pow(self, exp: usize) -> Self {
181        let neg = self < T::zero() && exp % 2 != 0;
182        checked_pow(self, exp).unwrap_or_else(|| {
183            if neg {
184                Bounded::min_value()
185            } else {
186                Bounded::max_value()
187            }
188        })
189    }
190}
191
192#[cfg(test)]
193mod tests {
194    use super::Saturating;
195
196    #[test]
197    fn saturating_add() {
198        assert_eq!(u64::MAX, Saturating::saturating_add(u64::MAX, 1))
199    }
200
201    #[test]
202    fn saturatiung_sub() {
203        assert_eq!(u64::MIN, Saturating::saturating_sub(u64::MIN, 1))
204    }
205
206    #[test]
207    fn saturating_mul() {
208        assert_eq!(u64::MAX, Saturating::saturating_mul(u64::MAX, 2));
209        assert_eq!(i64::MAX, Saturating::saturating_mul(i64::MAX, 2));
210        assert_eq!(i64::MIN, Saturating::saturating_mul(i64::MIN, 2));
211        assert_eq!(i64::MIN, Saturating::saturating_mul(2, i64::MIN));
212    }
213
214    #[test]
215    fn saturating_pow() {
216        assert_eq!(u64::MAX, Saturating::saturating_pow(u64::MAX, 2));
217        assert_eq!(i64::MAX, Saturating::saturating_pow(i64::MIN, 2));
218        assert_eq!(i64::MIN, Saturating::saturating_pow(i64::MIN, 3));
219    }
220}