1use super::euclid::Euclid;
13
14c0nst::c0nst! {
15pub c0nst trait StrictAdd: Sized {
17 type Output;
19 fn strict_add(self, v: Self) -> Self::Output;
28}
29}
30
31c0nst::c0nst! {
32pub c0nst trait StrictSub: Sized {
34 type Output;
36 fn strict_sub(self, v: Self) -> Self::Output;
39}
40}
41
42c0nst::c0nst! {
43pub c0nst trait StrictMul: Sized {
45 type Output;
47 fn strict_mul(self, v: Self) -> Self::Output;
50}
51}
52
53macro_rules! strict_binary_impl {
54 ($trait_name:ident, $method:ident, $overflowing:ident, $msg:expr, $t:ty) => {
55 c0nst::c0nst! {
56 c0nst impl $trait_name for $t {
57 type Output = $t;
58 #[inline]
59 #[track_caller]
60 fn $method(self, v: Self) -> Self {
61 let (val, overflowed) = <$t>::$overflowing(self, v);
62 if overflowed {
63 panic!($msg)
64 }
65 val
66 }
67 }
68 }
69 };
70}
71
72macro_rules! strict_binary_impl_all {
73 ($trait_name:ident, $method:ident, $overflowing:ident, $msg:expr) => {
74 strict_binary_impl!($trait_name, $method, $overflowing, $msg, u8);
75 strict_binary_impl!($trait_name, $method, $overflowing, $msg, u16);
76 strict_binary_impl!($trait_name, $method, $overflowing, $msg, u32);
77 strict_binary_impl!($trait_name, $method, $overflowing, $msg, u64);
78 strict_binary_impl!($trait_name, $method, $overflowing, $msg, usize);
79 strict_binary_impl!($trait_name, $method, $overflowing, $msg, u128);
80 strict_binary_impl!($trait_name, $method, $overflowing, $msg, i8);
81 strict_binary_impl!($trait_name, $method, $overflowing, $msg, i16);
82 strict_binary_impl!($trait_name, $method, $overflowing, $msg, i32);
83 strict_binary_impl!($trait_name, $method, $overflowing, $msg, i64);
84 strict_binary_impl!($trait_name, $method, $overflowing, $msg, isize);
85 strict_binary_impl!($trait_name, $method, $overflowing, $msg, i128);
86 };
87}
88
89strict_binary_impl_all!(
90 StrictAdd,
91 strict_add,
92 overflowing_add,
93 "attempt to add with overflow"
94);
95strict_binary_impl_all!(
96 StrictSub,
97 strict_sub,
98 overflowing_sub,
99 "attempt to subtract with overflow"
100);
101strict_binary_impl_all!(
102 StrictMul,
103 strict_mul,
104 overflowing_mul,
105 "attempt to multiply with overflow"
106);
107
108c0nst::c0nst! {
109pub c0nst trait StrictDiv: Sized {
111 type Output;
113 fn strict_div(self, v: Self) -> Self::Output;
116}
117}
118
119c0nst::c0nst! {
120pub c0nst trait StrictRem: Sized {
122 type Output;
124 fn strict_rem(self, v: Self) -> Self::Output;
127}
128}
129
130strict_binary_impl_all!(
131 StrictDiv,
132 strict_div,
133 overflowing_div,
134 "attempt to divide with overflow"
135);
136strict_binary_impl_all!(
137 StrictRem,
138 strict_rem,
139 overflowing_rem,
140 "attempt to calculate the remainder with overflow"
141);
142
143c0nst::c0nst! {
144pub c0nst trait StrictNeg: Sized {
146 type Output;
149 fn strict_neg(self) -> Self::Output;
150}
151}
152
153macro_rules! strict_neg_impl {
154 ($($t:ty)*) => {$(
155 c0nst::c0nst! {
156 c0nst impl StrictNeg for $t {
157 type Output = $t;
158 #[inline]
159 #[track_caller]
160 fn strict_neg(self) -> Self {
161 let (val, overflowed) = <$t>::overflowing_neg(self);
162 if overflowed {
163 panic!("attempt to negate with overflow")
164 }
165 val
166 }
167 }
168 }
169 )*}
170}
171
172strict_neg_impl!(usize u8 u16 u32 u64 u128);
173strict_neg_impl!(isize i8 i16 i32 i64 i128);
174
175c0nst::c0nst! {
176pub c0nst trait StrictAbs: Sized {
178 type Output;
180 fn strict_abs(self) -> Self::Output;
183}
184}
185
186macro_rules! strict_abs_impl {
187 ($($t:ty)*) => {$(
188 c0nst::c0nst! {
189 c0nst impl StrictAbs for $t {
190 type Output = $t;
191 #[inline]
192 #[track_caller]
193 fn strict_abs(self) -> Self {
194 match <$t>::checked_abs(self) {
196 Some(val) => val,
197 None => panic!("attempt to negate with overflow"),
198 }
199 }
200 }
201 }
202 )*}
203}
204
205strict_abs_impl!(isize i8 i16 i32 i64 i128);
206
207c0nst::c0nst! {
208pub c0nst trait StrictShl: Sized {
210 type Output;
212 fn strict_shl(self, rhs: u32) -> Self::Output;
215}
216}
217
218c0nst::c0nst! {
219pub c0nst trait StrictShr: Sized {
221 type Output;
223 fn strict_shr(self, rhs: u32) -> Self::Output;
226}
227}
228
229macro_rules! strict_shift_impl {
230 ($trait_name:ident, $method:ident, $checked:ident, $msg:expr, $($t:ty)*) => {$(
231 c0nst::c0nst! {
232 c0nst impl $trait_name for $t {
233 type Output = $t;
234 #[inline]
235 #[track_caller]
236 fn $method(self, rhs: u32) -> Self {
237 match <$t>::$checked(self, rhs) {
238 Some(val) => val,
239 None => panic!($msg),
240 }
241 }
242 }
243 }
244 )*}
245}
246
247strict_shift_impl!(
248 StrictShl,
249 strict_shl,
250 checked_shl,
251 "attempt to shift left with overflow",
252 usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128
253);
254strict_shift_impl!(
255 StrictShr,
256 strict_shr,
257 checked_shr,
258 "attempt to shift right with overflow",
259 usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128
260);
261
262c0nst::c0nst! {
263pub c0nst trait StrictPow: Sized {
265 type Output;
267 fn strict_pow(self, exp: u32) -> Self::Output;
270}
271}
272
273strict_shift_impl!(
274 StrictPow,
275 strict_pow,
276 checked_pow,
277 "attempt to exponentiate with overflow",
278 usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128
279);
280
281c0nst::c0nst! {
282pub c0nst trait StrictEuclid: [c0nst] Euclid {
284 fn strict_div_euclid(self, v: Self) -> <Self as Euclid>::Output;
288
289 fn strict_rem_euclid(self, v: Self) -> <Self as Euclid>::Output;
293}
294}
295
296macro_rules! strict_euclid_impl {
297 ($($t:ty)*) => {$(
298 c0nst::c0nst! {
299 c0nst impl StrictEuclid for $t {
300 #[inline]
301 #[track_caller]
302 fn strict_div_euclid(self, v: $t) -> Self {
303 let (val, overflowed) = <$t>::overflowing_div_euclid(self, v);
304 if overflowed {
305 panic!("attempt to divide with overflow")
306 }
307 val
308 }
309
310 #[inline]
311 #[track_caller]
312 fn strict_rem_euclid(self, v: $t) -> Self {
313 let (val, overflowed) = <$t>::overflowing_rem_euclid(self, v);
314 if overflowed {
315 panic!("attempt to calculate the remainder with overflow")
316 }
317 val
318 }
319 }
320 }
321 )*}
322}
323
324strict_euclid_impl!(usize u8 u16 u32 u64 u128);
325strict_euclid_impl!(isize i8 i16 i32 i64 i128);
326
327#[cfg(test)]
328mod tests {
329 use super::*;
330
331 #[test]
332 fn strict_ok_paths() {
333 assert_eq!(StrictAdd::strict_add(250u8, 5), 255);
334 assert_eq!(StrictSub::strict_sub(5i8, 10), -5);
335 assert_eq!(StrictMul::strict_mul(16u8, 15), 240);
336 assert_eq!(StrictDiv::strict_div(100i32, -3), -33);
337 assert_eq!(StrictRem::strict_rem(100i32, -3), 1);
338 assert_eq!(StrictNeg::strict_neg(-100i8), 100);
339 assert_eq!(StrictNeg::strict_neg(0u8), 0);
340 assert_eq!(StrictAbs::strict_abs(-100i8), 100);
341 assert_eq!(StrictShl::strict_shl(1u8, 7), 0x80);
342 assert_eq!(StrictShr::strict_shr(0x80u8, 7), 1);
343 assert_eq!(StrictPow::strict_pow(3u8, 5), 243);
344 assert_eq!(StrictEuclid::strict_div_euclid(-7i32, 4), -2);
345 assert_eq!(StrictEuclid::strict_rem_euclid(-7i32, 4), 1);
346 }
347
348 #[test]
349 #[should_panic(expected = "attempt to add with overflow")]
350 fn strict_add_panics() {
351 let _ = StrictAdd::strict_add(u8::MAX, 1);
352 }
353
354 #[test]
355 #[should_panic(expected = "attempt to negate with overflow")]
356 fn strict_neg_unsigned_panics() {
357 let _ = StrictNeg::strict_neg(1u8);
358 }
359
360 #[test]
361 #[should_panic(expected = "attempt to negate with overflow")]
362 fn strict_abs_panics() {
363 let _ = StrictAbs::strict_abs(i8::MIN);
364 }
365
366 #[test]
367 #[should_panic(expected = "attempt to shift left with overflow")]
368 fn strict_shl_panics() {
369 let _ = StrictShl::strict_shl(1u8, 8);
370 }
371
372 #[test]
373 #[should_panic(expected = "attempt to exponentiate with overflow")]
374 fn strict_pow_panics() {
375 let _ = StrictPow::strict_pow(2u8, 8);
376 }
377
378 #[test]
379 #[should_panic(expected = "attempt to divide with overflow")]
380 fn strict_div_euclid_panics() {
381 let _ = StrictEuclid::strict_div_euclid(i8::MIN, -1);
382 }
383}