Skip to main content

reifydb_value/value/number/safe/
add.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 ReifyDB
3
4pub trait SafeAdd: Sized {
5	fn checked_add(&self, r: &Self) -> Option<Self>;
6	fn saturating_add(&self, r: &Self) -> Self;
7	fn wrapping_add(&self, r: &Self) -> Self;
8}
9
10macro_rules! impl_safe_add {
11    ($($t:ty),*) => {
12        $(
13            impl SafeAdd for $t {
14                fn checked_add(&self, r: &Self) -> Option<Self> {
15                    <$t>::checked_add(*self, *r)
16                }
17                fn saturating_add(&self, r: &Self) -> Self {
18                    <$t>::saturating_add(*self, *r)
19                }
20                fn wrapping_add(&self, r: &Self) -> Self {
21                    <$t>::wrapping_add(*self, *r)
22                }
23            }
24        )*
25    };
26}
27
28impl_safe_add!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
29
30use crate::value::{decimal::Decimal, int::Int, uint::Uint};
31
32impl SafeAdd for Int {
33	fn checked_add(&self, r: &Self) -> Option<Self> {
34		Some(Int::from(&self.0 + &r.0))
35	}
36
37	fn saturating_add(&self, r: &Self) -> Self {
38		Int::from(&self.0 + &r.0)
39	}
40
41	fn wrapping_add(&self, r: &Self) -> Self {
42		Int::from(&self.0 + &r.0)
43	}
44}
45
46impl SafeAdd for Uint {
47	fn checked_add(&self, r: &Self) -> Option<Self> {
48		Some(Uint::from(&self.0 + &r.0))
49	}
50
51	fn saturating_add(&self, r: &Self) -> Self {
52		Uint::from(&self.0 + &r.0)
53	}
54
55	fn wrapping_add(&self, r: &Self) -> Self {
56		Uint::from(&self.0 + &r.0)
57	}
58}
59
60impl SafeAdd for Decimal {
61	fn checked_add(&self, r: &Self) -> Option<Self> {
62		let result = self.inner() + r.inner();
63		Some(Decimal::from(result))
64	}
65
66	fn saturating_add(&self, r: &Self) -> Self {
67		let result = self.inner() + r.inner();
68		Decimal::from(result)
69	}
70
71	fn wrapping_add(&self, r: &Self) -> Self {
72		let result = self.inner() + r.inner();
73		Decimal::from(result)
74	}
75}
76
77impl SafeAdd for f32 {
78	fn checked_add(&self, r: &Self) -> Option<Self> {
79		let result = *self + *r;
80		if result.is_finite() {
81			Some(result)
82		} else {
83			None
84		}
85	}
86
87	fn saturating_add(&self, r: &Self) -> Self {
88		let result = *self + *r;
89		if result.is_infinite() {
90			if result.is_sign_positive() {
91				f32::MAX
92			} else {
93				f32::MIN
94			}
95		} else {
96			result
97		}
98	}
99
100	fn wrapping_add(&self, r: &Self) -> Self {
101		*self + *r
102	}
103}
104
105impl SafeAdd for f64 {
106	fn checked_add(&self, r: &Self) -> Option<Self> {
107		let result = *self + *r;
108		if result.is_finite() {
109			Some(result)
110		} else {
111			None
112		}
113	}
114
115	fn saturating_add(&self, r: &Self) -> Self {
116		let result = *self + *r;
117		if result.is_infinite() {
118			if result.is_sign_positive() {
119				f64::MAX
120			} else {
121				f64::MIN
122			}
123		} else {
124			result
125		}
126	}
127
128	fn wrapping_add(&self, r: &Self) -> Self {
129		*self + *r
130	}
131}
132
133#[cfg(test)]
134pub mod tests {
135
136	macro_rules! define_tests {
137        ($($t:ty => $mod:ident),*) => {
138            $(
139                mod $mod {
140                    use super::super::SafeAdd;
141
142                    #[test]
143                    fn checked_add_happy() {
144                        let x: $t = 10;
145                        let y: $t = 20;
146                        assert_eq!(SafeAdd::checked_add(&x, &y), Some(30));
147                    }
148
149                    #[test]
150                    fn checked_add_unhappy() {
151                        let x: $t = <$t>::MAX;
152                        let y: $t = 1;
153                        assert_eq!(SafeAdd::checked_add(&x, &y), None);
154                    }
155
156                    #[test]
157                    fn saturating_add_happy() {
158                        let x: $t = 10;
159                        let y: $t = 20;
160                        assert_eq!(SafeAdd::saturating_add(&x, &y), 30);
161                    }
162
163                    #[test]
164                    fn saturating_add_unhappy() {
165                        let x: $t = <$t>::MAX;
166                        let y: $t = 1;
167                        assert_eq!(SafeAdd::saturating_add(&x, &y), <$t>::MAX);
168                    }
169
170                    #[test]
171                    fn wrapping_add_happy() {
172                        let x: $t = 10;
173                        let y: $t = 20;
174                        assert_eq!(SafeAdd::wrapping_add(&x, &y), 30);
175                    }
176
177                    #[test]
178                    fn wrapping_add_unhappy() {
179                        let x: $t = <$t>::MAX;
180                        let y: $t = 1;
181                        assert_eq!(SafeAdd::wrapping_add(&x, &y), <$t>::MIN);
182                    }
183                }
184            )*
185        };
186    }
187
188	define_tests!(
189	    i8 => i8_tests,
190	    i16 => i16_tests,
191	    i32 => i32_tests,
192	    i64 => i64_tests,
193	    i128 => i128_tests,
194	    u8 => u8_tests,
195	    u16 => u16_tests,
196	    u32 => u32_tests,
197	    u64 => u64_tests,
198	    u128 => u128_tests
199	);
200}