use_arithmetic/
checked.rs1#![allow(clippy::module_name_repetitions)]
2
3mod sealed {
4 pub trait Sealed {}
5
6 macro_rules! impl_sealed {
7 ($($ty:ty),* $(,)?) => {
8 $(impl Sealed for $ty {})*
9 };
10 }
11
12 impl_sealed!(
13 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
14 );
15}
16
17pub trait CheckedArithmetic: sealed::Sealed + Sized {
19 fn checked_add(self, rhs: Self) -> Option<Self>;
21
22 fn checked_sub(self, rhs: Self) -> Option<Self>;
24
25 fn checked_mul(self, rhs: Self) -> Option<Self>;
27}
28
29macro_rules! impl_checked_arithmetic {
30 ($($ty:ty),* $(,)?) => {
31 $(impl CheckedArithmetic for $ty {
32 fn checked_add(self, rhs: Self) -> Option<Self> {
33 <$ty>::checked_add(self, rhs)
34 }
35
36 fn checked_sub(self, rhs: Self) -> Option<Self> {
37 <$ty>::checked_sub(self, rhs)
38 }
39
40 fn checked_mul(self, rhs: Self) -> Option<Self> {
41 <$ty>::checked_mul(self, rhs)
42 }
43 })*
44 };
45}
46
47impl_checked_arithmetic!(
48 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
49);
50
51#[must_use]
53pub fn checked_add<T: CheckedArithmetic>(left: T, right: T) -> Option<T> {
54 <T as CheckedArithmetic>::checked_add(left, right)
55}
56
57#[must_use]
59pub fn checked_sub<T: CheckedArithmetic>(left: T, right: T) -> Option<T> {
60 <T as CheckedArithmetic>::checked_sub(left, right)
61}
62
63#[must_use]
65pub fn checked_mul<T: CheckedArithmetic>(left: T, right: T) -> Option<T> {
66 <T as CheckedArithmetic>::checked_mul(left, right)
67}
68
69#[cfg(test)]
70mod tests {
71 use super::{checked_add, checked_mul, checked_sub};
72
73 #[test]
74 fn reports_overflow_for_unsigned_values() {
75 assert_eq!(checked_add(u8::MAX, 1), None);
76 assert_eq!(checked_sub(0_u8, 1), None);
77 assert_eq!(checked_mul(200_u8, 2), None);
78 }
79
80 #[test]
81 fn reports_overflow_for_signed_values() {
82 assert_eq!(checked_add(i8::MAX, 1), None);
83 assert_eq!(checked_sub(i8::MIN, 1), None);
84 assert_eq!(checked_mul(i8::MAX, 2), None);
85 }
86}