1macro_rules! declare_mixed_trait {
24 (
25 $(#[$tdoc:meta])*
26 trait $name:ident, type $assoc:ident;
27 $(#[$mdoc:meta])*
28 fn $method:ident -> $ret:ty;
29 ) => {
30 c0nst::c0nst! {
31 $(#[$tdoc])*
32 pub c0nst trait $name: Sized {
33 type $assoc;
35
36 type Output;
38
39 $(#[$mdoc])*
40 fn $method(self, rhs: Self::$assoc) -> $ret;
41 }
42 }
43 };
44}
45
46declare_mixed_trait! {
49 trait CheckedAddSigned, type Signed;
51 fn checked_add_signed -> Option<Self::Output>;
60}
61
62declare_mixed_trait! {
63 trait WrappingAddSigned, type Signed;
65 fn wrapping_add_signed -> Self::Output;
67}
68
69declare_mixed_trait! {
70 trait OverflowingAddSigned, type Signed;
72 fn overflowing_add_signed -> (Self::Output, bool);
75}
76
77declare_mixed_trait! {
78 trait SaturatingAddSigned, type Signed;
80 fn saturating_add_signed -> Self::Output;
82}
83
84declare_mixed_trait! {
85 trait StrictAddSigned, type Signed;
87 fn strict_add_signed -> Self::Output;
89}
90
91declare_mixed_trait! {
92 trait CheckedSubSigned, type Signed;
94 fn checked_sub_signed -> Option<Self::Output>;
103}
104
105declare_mixed_trait! {
106 trait WrappingSubSigned, type Signed;
108 fn wrapping_sub_signed -> Self::Output;
110}
111
112declare_mixed_trait! {
113 trait OverflowingSubSigned, type Signed;
115 fn overflowing_sub_signed -> (Self::Output, bool);
118}
119
120declare_mixed_trait! {
121 trait SaturatingSubSigned, type Signed;
123 fn saturating_sub_signed -> Self::Output;
125}
126
127declare_mixed_trait! {
128 trait StrictSubSigned, type Signed;
130 fn strict_sub_signed -> Self::Output;
132}
133
134declare_mixed_trait! {
137 trait CheckedAddUnsigned, type Unsigned;
139 fn checked_add_unsigned -> Option<Self::Output>;
148}
149
150declare_mixed_trait! {
151 trait WrappingAddUnsigned, type Unsigned;
153 fn wrapping_add_unsigned -> Self::Output;
155}
156
157declare_mixed_trait! {
158 trait OverflowingAddUnsigned, type Unsigned;
160 fn overflowing_add_unsigned -> (Self::Output, bool);
163}
164
165declare_mixed_trait! {
166 trait SaturatingAddUnsigned, type Unsigned;
168 fn saturating_add_unsigned -> Self::Output;
170}
171
172declare_mixed_trait! {
173 trait StrictAddUnsigned, type Unsigned;
175 fn strict_add_unsigned -> Self::Output;
177}
178
179declare_mixed_trait! {
180 trait CheckedSubUnsigned, type Unsigned;
182 fn checked_sub_unsigned -> Option<Self::Output>;
191}
192
193declare_mixed_trait! {
194 trait WrappingSubUnsigned, type Unsigned;
196 fn wrapping_sub_unsigned -> Self::Output;
198}
199
200declare_mixed_trait! {
201 trait OverflowingSubUnsigned, type Unsigned;
203 fn overflowing_sub_unsigned -> (Self::Output, bool);
206}
207
208declare_mixed_trait! {
209 trait SaturatingSubUnsigned, type Unsigned;
211 fn saturating_sub_unsigned -> Self::Output;
213}
214
215declare_mixed_trait! {
216 trait StrictSubUnsigned, type Unsigned;
218 fn strict_sub_unsigned -> Self::Output;
220}
221
222macro_rules! mixed_signed_impl {
225 ($($t:ty => $s:ty;)*) => {$(
226 c0nst::c0nst! {
227 c0nst impl CheckedAddSigned for $t {
228 type Signed = $s;
229 type Output = $t;
230
231 #[inline]
232 fn checked_add_signed(self, rhs: $s) -> Option<$t> {
233 <$t>::checked_add_signed(self, rhs)
234 }
235 }
236 }
237
238 c0nst::c0nst! {
239 c0nst impl WrappingAddSigned for $t {
240 type Signed = $s;
241 type Output = $t;
242
243 #[inline]
244 fn wrapping_add_signed(self, rhs: $s) -> $t {
245 <$t>::wrapping_add_signed(self, rhs)
246 }
247 }
248 }
249
250 c0nst::c0nst! {
251 c0nst impl OverflowingAddSigned for $t {
252 type Signed = $s;
253 type Output = $t;
254
255 #[inline]
256 fn overflowing_add_signed(self, rhs: $s) -> ($t, bool) {
257 <$t>::overflowing_add_signed(self, rhs)
258 }
259 }
260 }
261
262 c0nst::c0nst! {
263 c0nst impl SaturatingAddSigned for $t {
264 type Signed = $s;
265 type Output = $t;
266
267 #[inline]
268 fn saturating_add_signed(self, rhs: $s) -> $t {
269 <$t>::saturating_add_signed(self, rhs)
270 }
271 }
272 }
273
274 c0nst::c0nst! {
275 c0nst impl StrictAddSigned for $t {
276 type Signed = $s;
277 type Output = $t;
278
279 #[inline]
281 #[track_caller]
282 fn strict_add_signed(self, rhs: $s) -> $t {
283 let (val, overflowed) = <$t>::overflowing_add_signed(self, rhs);
284 if overflowed {
285 panic!("attempt to add with overflow")
286 }
287 val
288 }
289 }
290 }
291
292 c0nst::c0nst! {
295 c0nst impl OverflowingSubSigned for $t {
296 type Signed = $s;
297 type Output = $t;
298
299 #[inline]
300 fn overflowing_sub_signed(self, rhs: $s) -> ($t, bool) {
301 let (res, overflow) = <$t>::overflowing_sub(self, rhs as $t);
304 (res, overflow != (rhs < 0))
305 }
306 }
307 }
308
309 c0nst::c0nst! {
310 c0nst impl CheckedSubSigned for $t {
311 type Signed = $s;
312 type Output = $t;
313
314 #[inline]
315 fn checked_sub_signed(self, rhs: $s) -> Option<$t> {
316 let (val, overflowed) =
317 OverflowingSubSigned::overflowing_sub_signed(self, rhs);
318 if overflowed {
319 None
320 } else {
321 Some(val)
322 }
323 }
324 }
325 }
326
327 c0nst::c0nst! {
328 c0nst impl WrappingSubSigned for $t {
329 type Signed = $s;
330 type Output = $t;
331
332 #[inline]
333 fn wrapping_sub_signed(self, rhs: $s) -> $t {
334 <$t>::wrapping_sub(self, rhs as $t)
335 }
336 }
337 }
338
339 c0nst::c0nst! {
340 c0nst impl SaturatingSubSigned for $t {
341 type Signed = $s;
342 type Output = $t;
343
344 #[inline]
345 fn saturating_sub_signed(self, rhs: $s) -> $t {
346 let (val, overflowed) =
347 OverflowingSubSigned::overflowing_sub_signed(self, rhs);
348 if !overflowed {
349 val
350 } else if rhs < 0 {
351 <$t>::MAX
352 } else {
353 0
354 }
355 }
356 }
357 }
358
359 c0nst::c0nst! {
360 c0nst impl StrictSubSigned for $t {
361 type Signed = $s;
362 type Output = $t;
363
364 #[inline]
365 #[track_caller]
366 fn strict_sub_signed(self, rhs: $s) -> $t {
367 let (val, overflowed) =
368 OverflowingSubSigned::overflowing_sub_signed(self, rhs);
369 if overflowed {
370 panic!("attempt to subtract with overflow")
371 }
372 val
373 }
374 }
375 }
376 )*};
377}
378
379mixed_signed_impl! {
380 u8 => i8;
381 u16 => i16;
382 u32 => i32;
383 u64 => i64;
384 usize => isize;
385 u128 => i128;
386}
387
388macro_rules! mixed_unsigned_impl {
389 ($($t:ty => $u:ty;)*) => {$(
390 c0nst::c0nst! {
391 c0nst impl CheckedAddUnsigned for $t {
392 type Unsigned = $u;
393 type Output = $t;
394
395 #[inline]
396 fn checked_add_unsigned(self, rhs: $u) -> Option<$t> {
397 <$t>::checked_add_unsigned(self, rhs)
398 }
399 }
400 }
401
402 c0nst::c0nst! {
403 c0nst impl WrappingAddUnsigned for $t {
404 type Unsigned = $u;
405 type Output = $t;
406
407 #[inline]
408 fn wrapping_add_unsigned(self, rhs: $u) -> $t {
409 <$t>::wrapping_add_unsigned(self, rhs)
410 }
411 }
412 }
413
414 c0nst::c0nst! {
415 c0nst impl OverflowingAddUnsigned for $t {
416 type Unsigned = $u;
417 type Output = $t;
418
419 #[inline]
420 fn overflowing_add_unsigned(self, rhs: $u) -> ($t, bool) {
421 <$t>::overflowing_add_unsigned(self, rhs)
422 }
423 }
424 }
425
426 c0nst::c0nst! {
427 c0nst impl SaturatingAddUnsigned for $t {
428 type Unsigned = $u;
429 type Output = $t;
430
431 #[inline]
432 fn saturating_add_unsigned(self, rhs: $u) -> $t {
433 <$t>::saturating_add_unsigned(self, rhs)
434 }
435 }
436 }
437
438 c0nst::c0nst! {
439 c0nst impl StrictAddUnsigned for $t {
440 type Unsigned = $u;
441 type Output = $t;
442
443 #[inline]
444 #[track_caller]
445 fn strict_add_unsigned(self, rhs: $u) -> $t {
446 let (val, overflowed) = <$t>::overflowing_add_unsigned(self, rhs);
447 if overflowed {
448 panic!("attempt to add with overflow")
449 }
450 val
451 }
452 }
453 }
454
455 c0nst::c0nst! {
456 c0nst impl CheckedSubUnsigned for $t {
457 type Unsigned = $u;
458 type Output = $t;
459
460 #[inline]
461 fn checked_sub_unsigned(self, rhs: $u) -> Option<$t> {
462 <$t>::checked_sub_unsigned(self, rhs)
463 }
464 }
465 }
466
467 c0nst::c0nst! {
468 c0nst impl WrappingSubUnsigned for $t {
469 type Unsigned = $u;
470 type Output = $t;
471
472 #[inline]
473 fn wrapping_sub_unsigned(self, rhs: $u) -> $t {
474 <$t>::wrapping_sub_unsigned(self, rhs)
475 }
476 }
477 }
478
479 c0nst::c0nst! {
480 c0nst impl OverflowingSubUnsigned for $t {
481 type Unsigned = $u;
482 type Output = $t;
483
484 #[inline]
485 fn overflowing_sub_unsigned(self, rhs: $u) -> ($t, bool) {
486 <$t>::overflowing_sub_unsigned(self, rhs)
487 }
488 }
489 }
490
491 c0nst::c0nst! {
492 c0nst impl SaturatingSubUnsigned for $t {
493 type Unsigned = $u;
494 type Output = $t;
495
496 #[inline]
497 fn saturating_sub_unsigned(self, rhs: $u) -> $t {
498 <$t>::saturating_sub_unsigned(self, rhs)
499 }
500 }
501 }
502
503 c0nst::c0nst! {
504 c0nst impl StrictSubUnsigned for $t {
505 type Unsigned = $u;
506 type Output = $t;
507
508 #[inline]
509 #[track_caller]
510 fn strict_sub_unsigned(self, rhs: $u) -> $t {
511 let (val, overflowed) = <$t>::overflowing_sub_unsigned(self, rhs);
512 if overflowed {
513 panic!("attempt to subtract with overflow")
514 }
515 val
516 }
517 }
518 }
519 )*};
520}
521
522mixed_unsigned_impl! {
523 i8 => u8;
524 i16 => u16;
525 i32 => u32;
526 i64 => u64;
527 isize => usize;
528 i128 => u128;
529}
530
531c0nst::c0nst! {
532pub c0nst trait CheckedSignedDiff: Sized {
534 type Signed;
536
537 fn checked_signed_diff(self, rhs: Self) -> Option<Self::Signed>;
547}
548}
549
550macro_rules! checked_signed_diff_impl {
551 ($($t:ty => $s:ty;)*) => {$(
552 c0nst::c0nst! {
553 c0nst impl CheckedSignedDiff for $t {
554 type Signed = $s;
555
556 #[inline]
558 fn checked_signed_diff(self, rhs: Self) -> Option<$s> {
559 let res = <$t>::wrapping_sub(self, rhs) as $s;
560 let overflow = (self >= rhs) == (res < 0);
561 if !overflow {
562 Some(res)
563 } else {
564 None
565 }
566 }
567 }
568 }
569 )*};
570}
571
572checked_signed_diff_impl! {
573 u8 => i8;
574 u16 => i16;
575 u32 => i32;
576 u64 => i64;
577 usize => isize;
578 u128 => i128;
579}
580
581#[cfg(test)]
582mod tests {
583 use super::*;
584
585 #[test]
586 fn add_signed() {
587 assert_eq!(CheckedAddSigned::checked_add_signed(1u8, -2), None);
588 assert_eq!(CheckedAddSigned::checked_add_signed(254u8, 1), Some(255));
589 assert_eq!(WrappingAddSigned::wrapping_add_signed(1u8, -2), 255);
590 assert_eq!(
591 OverflowingAddSigned::overflowing_add_signed(255u8, 1),
592 (0, true)
593 );
594 assert_eq!(SaturatingAddSigned::saturating_add_signed(1u8, -2), 0);
595 assert_eq!(SaturatingAddSigned::saturating_add_signed(250u8, 100), 255);
596 assert_eq!(StrictAddSigned::strict_add_signed(250u8, 5), 255);
597 }
598
599 #[test]
600 fn sub_signed() {
601 assert_eq!(CheckedSubSigned::checked_sub_signed(1u8, 2), None);
602 assert_eq!(CheckedSubSigned::checked_sub_signed(1u8, -2), Some(3));
603 assert_eq!(CheckedSubSigned::checked_sub_signed(u8::MAX, -1), None);
604 assert_eq!(WrappingSubSigned::wrapping_sub_signed(0u8, 1), 255);
605 assert_eq!(
606 OverflowingSubSigned::overflowing_sub_signed(0u8, 1),
607 (255, true)
608 );
609 assert_eq!(
610 OverflowingSubSigned::overflowing_sub_signed(255u8, -1),
611 (0, true)
612 );
613 assert_eq!(
614 OverflowingSubSigned::overflowing_sub_signed(10u8, -5),
615 (15, false)
616 );
617 assert_eq!(SaturatingSubSigned::saturating_sub_signed(0u8, 1), 0);
618 assert_eq!(SaturatingSubSigned::saturating_sub_signed(255u8, -1), 255);
619 assert_eq!(StrictSubSigned::strict_sub_signed(10u8, -5), 15);
620 }
621
622 #[test]
623 #[should_panic(expected = "attempt to subtract with overflow")]
624 fn strict_sub_signed_panics() {
625 let _ = StrictSubSigned::strict_sub_signed(0u8, 1);
626 }
627
628 #[test]
629 fn add_sub_unsigned() {
630 assert_eq!(CheckedAddUnsigned::checked_add_unsigned(i8::MAX, 1), None);
631 assert_eq!(
632 WrappingAddUnsigned::wrapping_add_unsigned(i8::MAX, 1),
633 i8::MIN
634 );
635 assert_eq!(
636 OverflowingAddUnsigned::overflowing_add_unsigned(-1i8, 2),
637 (1, false)
638 );
639 assert_eq!(
640 SaturatingAddUnsigned::saturating_add_unsigned(100i8, 100),
641 i8::MAX
642 );
643 assert_eq!(StrictAddUnsigned::strict_add_unsigned(-1i8, 128), 127);
644 assert_eq!(CheckedSubUnsigned::checked_sub_unsigned(i8::MIN, 1), None);
645 assert_eq!(
646 WrappingSubUnsigned::wrapping_sub_unsigned(i8::MIN, 1),
647 i8::MAX
648 );
649 assert_eq!(
650 OverflowingSubUnsigned::overflowing_sub_unsigned(1i8, 2),
651 (-1, false)
652 );
653 assert_eq!(
654 SaturatingSubUnsigned::saturating_sub_unsigned(-100i8, 100),
655 i8::MIN
656 );
657 assert_eq!(StrictSubUnsigned::strict_sub_unsigned(0i8, 128), i8::MIN);
658 }
659
660 #[test]
661 fn signed_diff() {
662 assert_eq!(CheckedSignedDiff::checked_signed_diff(10u8, 14), Some(-4));
663 assert_eq!(CheckedSignedDiff::checked_signed_diff(14u8, 10), Some(4));
664 assert_eq!(CheckedSignedDiff::checked_signed_diff(u8::MAX, 0), None);
665 assert_eq!(CheckedSignedDiff::checked_signed_diff(0u8, u8::MAX), None);
666 assert_eq!(
667 CheckedSignedDiff::checked_signed_diff(0u8, 128),
668 Some(i8::MIN)
669 );
670 assert_eq!(
671 CheckedSignedDiff::checked_signed_diff(127u8, 0),
672 Some(i8::MAX)
673 );
674 }
675}