reifydb_value/value/number/safe/
sub.rs1pub trait SafeSub: Sized {
5 fn checked_sub(&self, r: &Self) -> Option<Self>;
6 fn saturating_sub(&self, r: &Self) -> Self;
7 fn wrapping_sub(&self, r: &Self) -> Self;
8}
9
10macro_rules! impl_safe_sub {
11 ($($t:ty),*) => {
12 $(
13 impl SafeSub for $t {
14 fn checked_sub(&self, r: &Self) -> Option<Self> {
15 <$t>::checked_sub(*self, *r)
16 }
17 fn saturating_sub(&self, r: &Self) -> Self {
18 <$t>::saturating_sub(*self, *r)
19 }
20 fn wrapping_sub(&self, r: &Self) -> Self {
21 <$t>::wrapping_sub(*self, *r)
22 }
23 }
24 )*
25 };
26}
27
28impl_safe_sub!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
29
30use crate::value::decimal::Decimal;
31
32impl SafeSub for Decimal {
33 fn checked_sub(&self, r: &Self) -> Option<Self> {
34 Decimal::checked_sub(self, r)
35 }
36
37 fn saturating_sub(&self, r: &Self) -> Self {
38 Decimal::saturating_sub(self, r)
39 }
40
41 fn wrapping_sub(&self, r: &Self) -> Self {
42 Decimal::saturating_sub(self, r)
43 }
44}
45
46impl SafeSub for f32 {
47 fn checked_sub(&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_sub(&self, r: &Self) -> Self {
57 let result = *self - *r;
58 if result.is_infinite() {
59 if result.is_sign_negative() {
60 f32::MIN
61 } else {
62 f32::MAX
63 }
64 } else {
65 result
66 }
67 }
68
69 fn wrapping_sub(&self, r: &Self) -> Self {
70 *self - *r
71 }
72}
73
74impl SafeSub for f64 {
75 fn checked_sub(&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_sub(&self, r: &Self) -> Self {
85 let result = *self - *r;
86 if result.is_infinite() {
87 if result.is_sign_negative() {
88 f64::MIN
89 } else {
90 f64::MAX
91 }
92 } else {
93 result
94 }
95 }
96
97 fn wrapping_sub(&self, r: &Self) -> Self {
98 *self - *r
99 }
100}
101
102#[cfg(test)]
103pub mod tests {
104 macro_rules! define_tests {
105 ($($t:ty => $mod:ident),*) => {
106 $(
107 mod $mod {
108 use super::super::SafeSub;
109
110 #[test]
111 fn checked_sub_happy() {
112 let x: $t = 20;
113 let y: $t = 10;
114 assert_eq!(SafeSub::checked_sub(&x, &y), Some(10));
115 }
116
117 #[test]
118 fn checked_sub_unhappy() {
119 let x: $t = <$t>::MIN;
120 let y: $t = 1;
121 assert_eq!(SafeSub::checked_sub(&x, &y), None);
122 }
123
124 #[test]
125 fn saturating_sub_happy() {
126 let x: $t = 20;
127 let y: $t = 10;
128 assert_eq!(SafeSub::saturating_sub(&x, &y), 10);
129 }
130
131 #[test]
132 fn saturating_sub_unhappy() {
133 let x: $t = <$t>::MIN;
134 let y: $t = 1;
135 assert_eq!(SafeSub::saturating_sub(&x, &y), <$t>::MIN);
136 }
137
138 #[test]
139 fn wrapping_sub_happy() {
140 let x: $t = 20;
141 let y: $t = 10;
142 assert_eq!(SafeSub::wrapping_sub(&x, &y), 10);
143 }
144
145 #[test]
146 fn wrapping_sub_unhappy() {
147 let x: $t = <$t>::MIN;
148 let y: $t = 1;
149 assert_eq!(SafeSub::wrapping_sub(&x, &y), <$t>::MAX);
150 }
151 }
152 )*
153 };
154 }
155
156 define_tests!(
157 i8 => i8_tests,
158 i16 => i16_tests,
159 i32 => i32_tests,
160 i64 => i64_tests,
161 i128 => i128_tests,
162 u8 => u8_tests,
163 u16 => u16_tests,
164 u32 => u32_tests,
165 u64 => u64_tests,
166 u128 => u128_tests
167 );
168}