Skip to main content

reifydb_value/value/number/safe/
add.rs

1// SPDX-License-Identifier: Apache-2.0
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;
31
32impl SafeAdd for Decimal {
33	fn checked_add(&self, r: &Self) -> Option<Self> {
34		Decimal::checked_add(self, r)
35	}
36
37	fn saturating_add(&self, r: &Self) -> Self {
38		Decimal::saturating_add(self, r)
39	}
40
41	fn wrapping_add(&self, r: &Self) -> Self {
42		Decimal::saturating_add(self, r)
43	}
44}
45
46impl SafeAdd for f32 {
47	fn checked_add(&self, r: &Self) -> Option<Self> {
48		let result = *self + *r;
49		if result.is_infinite() && self.is_finite() && r.is_finite() {
50			None
51		} else {
52			Some(result)
53		}
54	}
55
56	fn saturating_add(&self, r: &Self) -> Self {
57		let result = *self + *r;
58		if result.is_infinite() {
59			if result.is_sign_positive() {
60				f32::MAX
61			} else {
62				f32::MIN
63			}
64		} else {
65			result
66		}
67	}
68
69	fn wrapping_add(&self, r: &Self) -> Self {
70		*self + *r
71	}
72}
73
74impl SafeAdd for f64 {
75	fn checked_add(&self, r: &Self) -> Option<Self> {
76		let result = *self + *r;
77		if result.is_infinite() && self.is_finite() && r.is_finite() {
78			None
79		} else {
80			Some(result)
81		}
82	}
83
84	fn saturating_add(&self, r: &Self) -> Self {
85		let result = *self + *r;
86		if result.is_infinite() {
87			if result.is_sign_positive() {
88				f64::MAX
89			} else {
90				f64::MIN
91			}
92		} else {
93			result
94		}
95	}
96
97	fn wrapping_add(&self, r: &Self) -> Self {
98		*self + *r
99	}
100}
101
102#[cfg(test)]
103pub mod tests {
104
105	macro_rules! define_tests {
106        ($($t:ty => $mod:ident),*) => {
107            $(
108                mod $mod {
109                    use super::super::SafeAdd;
110
111                    #[test]
112                    fn checked_add_happy() {
113                        let x: $t = 10;
114                        let y: $t = 20;
115                        assert_eq!(SafeAdd::checked_add(&x, &y), Some(30));
116                    }
117
118                    #[test]
119                    fn checked_add_unhappy() {
120                        let x: $t = <$t>::MAX;
121                        let y: $t = 1;
122                        assert_eq!(SafeAdd::checked_add(&x, &y), None);
123                    }
124
125                    #[test]
126                    fn saturating_add_happy() {
127                        let x: $t = 10;
128                        let y: $t = 20;
129                        assert_eq!(SafeAdd::saturating_add(&x, &y), 30);
130                    }
131
132                    #[test]
133                    fn saturating_add_unhappy() {
134                        let x: $t = <$t>::MAX;
135                        let y: $t = 1;
136                        assert_eq!(SafeAdd::saturating_add(&x, &y), <$t>::MAX);
137                    }
138
139                    #[test]
140                    fn wrapping_add_happy() {
141                        let x: $t = 10;
142                        let y: $t = 20;
143                        assert_eq!(SafeAdd::wrapping_add(&x, &y), 30);
144                    }
145
146                    #[test]
147                    fn wrapping_add_unhappy() {
148                        let x: $t = <$t>::MAX;
149                        let y: $t = 1;
150                        assert_eq!(SafeAdd::wrapping_add(&x, &y), <$t>::MIN);
151                    }
152                }
153            )*
154        };
155    }
156
157	define_tests!(
158	    i8 => i8_tests,
159	    i16 => i16_tests,
160	    i32 => i32_tests,
161	    i64 => i64_tests,
162	    i128 => i128_tests,
163	    u8 => u8_tests,
164	    u16 => u16_tests,
165	    u32 => u32_tests,
166	    u64 => u64_tests,
167	    u128 => u128_tests
168	);
169}