1#[cfg(feature = "proptest")]
20use proptest_derive::Arbitrary;
21use serde::{Deserialize, Serialize};
22use std::ops::{Add, AddAssign, Div, Mul, Neg, Rem, Sub, SubAssign};
23
24#[derive(
37 Debug,
38 Default,
39 Ord,
40 PartialOrd,
41 Eq,
42 PartialEq,
43 Copy,
44 Clone,
45 Serialize,
46 Deserialize
47)]
48#[cfg_attr(feature = "proptest", derive(Arbitrary))]
49pub struct Overflowing<T>(T);
50
51#[derive(Debug)]
53pub enum OverflowingBehavior {
54 Panic,
56 SoftPanic,
58 Ignore,
60}
61
62impl std::str::FromStr for OverflowingBehavior {
63 type Err = String;
64
65 fn from_str(s: &str) -> Result<Self, Self::Err> {
66 match s {
67 _ if s.eq_ignore_ascii_case("panic") => Ok(OverflowingBehavior::Panic),
68 _ if s.eq_ignore_ascii_case("soft_panic") => Ok(OverflowingBehavior::SoftPanic),
69 _ if s.eq_ignore_ascii_case("ignore") => Ok(OverflowingBehavior::Ignore),
70 _ => Err(format!("Invalid OverflowingBehavior: {s}")),
71 }
72 }
73}
74
75pub fn set_behavior(behavior: OverflowingBehavior) {
81 overflowing_support::set_overflowing_mode(behavior);
82}
83
84impl<T> Overflowing<T> {
85 pub fn into_inner(self) -> T {
87 self.0
88 }
89}
90
91impl<T: std::fmt::Display> std::fmt::Display for Overflowing<T> {
92 #[inline(always)]
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 self.0.fmt(f)
95 }
96}
97
98#[cfg(feature = "columnar")]
99mod columnar {
100 use crate::overflowing::Overflowing;
101 use columnar::common::PushIndexAs;
102 use columnar::{
103 AsBytes, Borrow, Clear, Columnar, Container, FromBytes, Index, IndexAs, Len, Push,
104 };
105 use serde::{Deserialize, Serialize};
106 use std::ops::Range;
107
108 impl<T: Columnar + Copy + Send> Columnar for Overflowing<T>
109 where
110 for<'a> &'a [T]: AsBytes<'a> + FromBytes<'a>,
111 Overflowing<T>: From<T>,
112 {
113 #[inline(always)]
114 fn into_owned(other: columnar::Ref<'_, Self>) -> Self {
115 other
116 }
117 type Container = Overflows<T>;
118 #[inline(always)]
119 fn reborrow<'b, 'a: 'b>(thing: columnar::Ref<'a, Self>) -> columnar::Ref<'b, Self>
120 where
121 Self: 'a,
122 {
123 thing
124 }
125 }
126
127 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
129 pub struct Overflows<T, TC = Vec<T>>(TC, std::marker::PhantomData<T>);
130
131 impl<T, TC: Default> Default for Overflows<T, TC> {
132 #[inline(always)]
133 fn default() -> Self {
134 Self(TC::default(), std::marker::PhantomData)
135 }
136 }
137
138 impl<T: Columnar + Copy + Send, TC: PushIndexAs<T>> Borrow for Overflows<T, TC>
139 where
140 Overflowing<T>: From<T>,
141 {
142 type Ref<'a> = Overflowing<T>;
143 type Borrowed<'a>
144 = Overflows<T, TC::Borrowed<'a>>
145 where
146 Self: 'a;
147 #[inline(always)]
148 fn borrow<'a>(&'a self) -> Self::Borrowed<'a> {
149 Overflows(self.0.borrow(), std::marker::PhantomData)
150 }
151 #[inline(always)]
152 fn reborrow<'b, 'a: 'b>(item: Self::Borrowed<'a>) -> Self::Borrowed<'b>
153 where
154 Self: 'a,
155 {
156 Overflows(TC::reborrow(item.0), std::marker::PhantomData)
157 }
158
159 #[inline(always)]
160 fn reborrow_ref<'b, 'a: 'b>(item: Self::Ref<'a>) -> Self::Ref<'b>
161 where
162 Self: 'a,
163 {
164 item
165 }
166 }
167
168 impl<T: Columnar + Copy + Send, TC: PushIndexAs<T>> Container for Overflows<T, TC>
169 where
170 Overflowing<T>: From<T>,
171 {
172 #[inline(always)]
173 fn extend_from_self(&mut self, other: Self::Borrowed<'_>, range: Range<usize>) {
174 self.0.extend_from_self(other.0, range);
175 }
176 #[inline(always)]
177 fn reserve_for<'a, I>(&mut self, selves: I)
178 where
179 Self: 'a,
180 I: Iterator<Item = Self::Borrowed<'a>> + Clone,
181 {
182 self.0.reserve_for(selves.map(|s| s.0));
183 }
184 }
185
186 impl<'a, T: Copy, TC: AsBytes<'a>> AsBytes<'a> for Overflows<T, TC> {
187 const SLICE_COUNT: usize = TC::SLICE_COUNT;
188 #[inline(always)]
189 fn get_byte_slice(&self, index: usize) -> (u64, &'a [u8]) {
190 self.0.get_byte_slice(index)
191 }
192 #[inline(always)]
193 fn as_bytes(&self) -> impl Iterator<Item = (u64, &'a [u8])> {
194 self.0.as_bytes()
195 }
196 }
197
198 impl<'a, T: Copy, TC: FromBytes<'a>> FromBytes<'a> for Overflows<T, TC> {
199 const SLICE_COUNT: usize = TC::SLICE_COUNT;
200 #[inline(always)]
201 fn from_bytes(bytes: &mut impl Iterator<Item = &'a [u8]>) -> Self {
202 Self(TC::from_bytes(bytes), std::marker::PhantomData)
203 }
204 }
205
206 impl<T: Copy, TC: Len> Len for Overflows<T, TC> {
207 #[inline(always)]
208 fn len(&self) -> usize {
209 self.0.len()
210 }
211 }
212
213 impl<T: Copy, TC: Clear> Clear for Overflows<T, TC> {
214 #[inline(always)]
215 fn clear(&mut self) {
216 self.0.clear();
217 }
218 }
219
220 impl<T: Copy, TC: IndexAs<T>> Index for Overflows<T, TC>
221 where
222 Overflowing<T>: From<T>,
223 {
224 type Ref = Overflowing<T>;
225 #[inline(always)]
226 fn get(&self, index: usize) -> Self::Ref {
227 self.0.index_as(index).into()
228 }
229 }
230
231 impl<T: Copy, TC: for<'a> Push<&'a T>> Push<Overflowing<T>> for Overflows<T, TC> {
232 #[inline(always)]
233 fn push(&mut self, item: Overflowing<T>) {
234 self.0.push(&item.0);
235 }
236 }
237
238 impl<T: Copy, TC: Push<T>> Push<&Overflowing<T>> for Overflows<T, TC> {
239 #[inline(always)]
240 fn push(&mut self, item: &Overflowing<T>) {
241 self.0.push(item.0);
242 }
243 }
244}
245
246macro_rules! impl_overflowing {
247 ($t:ty) => {
248 impl Overflowing<$t> {
249 pub const ZERO: Self = Self(0);
251 pub const ONE: Self = Self(1);
253 pub const MIN: Self = Self(<$t>::MIN);
255 pub const MAX: Self = Self(<$t>::MAX);
257
258 #[inline(always)]
260 pub fn checked_add(self, rhs: Self) -> Option<Self> {
261 self.0.checked_add(rhs.0).map(Self)
262 }
263
264 #[inline(always)]
266 pub fn wrapping_add(self, rhs: Self) -> Self {
267 Self(self.0.wrapping_add(rhs.0))
268 }
269
270 #[inline(always)]
272 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
273 self.0.checked_mul(rhs.0).map(Self)
274 }
275
276 #[inline(always)]
278 pub fn wrapping_mul(self, rhs: Self) -> Self {
279 Self(self.0.wrapping_mul(rhs.0))
280 }
281
282 pub fn is_zero(self) -> bool {
284 self == Self::ZERO
285 }
286 }
287
288 impl Add<Self> for Overflowing<$t> {
289 type Output = Self;
290
291 #[inline(always)]
292 fn add(self, rhs: Self) -> Self::Output {
293 match self.0.overflowing_add(rhs.0) {
294 (result, true) => {
295 overflowing_support::handle_overflow(result, format_args!("{self} + {rhs}"))
296 }
297 (result, false) => Self(result),
298 }
299 }
300 }
301
302 impl<'a> Add<&'a Self> for Overflowing<$t> {
303 type Output = Self;
304
305 #[inline(always)]
306 fn add(self, rhs: &'a Self) -> Self::Output {
307 match self.0.overflowing_add(rhs.0) {
308 (result, true) => {
309 overflowing_support::handle_overflow(result, format_args!("{self} + {rhs}"))
310 }
311 (result, false) => Self(result),
312 }
313 }
314 }
315
316 impl AddAssign<Self> for Overflowing<$t> {
317 #[inline(always)]
318 fn add_assign(&mut self, rhs: Self) {
319 *self = *self + rhs;
320 }
321 }
322
323 impl AddAssign<&Self> for Overflowing<$t> {
324 #[inline(always)]
325 fn add_assign(&mut self, rhs: &Self) {
326 *self = *self + *rhs;
327 }
328 }
329
330 impl Div<Self> for Overflowing<$t> {
331 type Output = Overflowing<<$t as Div>::Output>;
332
333 #[inline(always)]
334 fn div(self, rhs: Self) -> Self::Output {
335 match self.0.overflowing_div(rhs.0) {
336 (result, true) => {
337 overflowing_support::handle_overflow(result, format_args!("{self} / {rhs}"))
338 }
339 (result, false) => Self(result),
340 }
341 }
342 }
343
344 impl Rem<Self> for Overflowing<$t> {
345 type Output = Overflowing<<$t as Rem>::Output>;
346
347 #[inline(always)]
348 fn rem(self, rhs: Self) -> Self::Output {
349 match self.0.overflowing_rem(rhs.0) {
350 (result, true) => {
351 overflowing_support::handle_overflow(result, format_args!("{self} % {rhs}"))
352 }
353 (result, false) => Self(result),
354 }
355 }
356 }
357
358 impl Sub<Self> for Overflowing<$t> {
359 type Output = Self;
360
361 #[inline(always)]
362 fn sub(self, rhs: Self) -> Self::Output {
363 match self.0.overflowing_sub(rhs.0) {
364 (result, true) => {
365 overflowing_support::handle_overflow(result, format_args!("{self} - {rhs}"))
366 }
367 (result, false) => Self(result),
368 }
369 }
370 }
371
372 impl<'a> Sub<&'a Self> for Overflowing<$t> {
373 type Output = Self;
374
375 #[inline(always)]
376 fn sub(self, rhs: &'a Self) -> Self::Output {
377 match self.0.overflowing_sub(rhs.0) {
378 (result, true) => {
379 overflowing_support::handle_overflow(result, format_args!("{self} - {rhs}"))
380 }
381 (result, false) => Self(result),
382 }
383 }
384 }
385
386 impl SubAssign<Self> for Overflowing<$t> {
387 #[inline(always)]
388 fn sub_assign(&mut self, rhs: Self) {
389 *self = *self - rhs;
390 }
391 }
392
393 impl SubAssign<&Self> for Overflowing<$t> {
394 #[inline(always)]
395 fn sub_assign(&mut self, rhs: &Self) {
396 *self = *self - *rhs;
397 }
398 }
399
400 impl std::iter::Sum<Overflowing<$t>> for Overflowing<$t> {
401 #[inline(always)]
402 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
403 iter.fold(Self::ZERO, |a, b| a + b)
404 }
405 }
406
407 impl<'a> std::iter::Sum<&'a Overflowing<$t>> for Overflowing<$t> {
408 #[inline(always)]
409 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
410 iter.fold(Self::ZERO, |a, b| a + b)
411 }
412 }
413
414 impl Mul for Overflowing<$t> {
415 type Output = Self;
416
417 #[inline(always)]
418 fn mul(self, rhs: Self) -> Self::Output {
419 match self.0.overflowing_mul(rhs.0) {
420 (result, true) => {
421 overflowing_support::handle_overflow(result, format_args!("{self} * {rhs}"))
422 }
423 (result, false) => Self(result),
424 }
425 }
426 }
427
428 #[cfg(feature = "differential-dataflow")]
429 impl differential_dataflow::difference::IsZero for Overflowing<$t> {
430 #[inline(always)]
431 fn is_zero(&self) -> bool {
432 self.0.is_zero()
433 }
434 }
435
436 #[cfg(feature = "differential-dataflow")]
437 impl differential_dataflow::difference::Semigroup for Overflowing<$t> {
438 #[inline(always)]
439 fn plus_equals(&mut self, rhs: &Self) {
440 *self += *rhs
441 }
442 }
443
444 #[cfg(feature = "differential-dataflow")]
445 impl differential_dataflow::difference::Monoid for Overflowing<$t> {
446 #[inline(always)]
447 fn zero() -> Self {
448 Self::ZERO
449 }
450 }
451
452 #[cfg(feature = "differential-dataflow")]
453 impl differential_dataflow::difference::Multiply<Self> for Overflowing<$t> {
454 type Output = Self;
455 #[inline(always)]
456 fn multiply(self, rhs: &Self) -> Self::Output {
457 self * *rhs
458 }
459 }
460
461 #[cfg(feature = "columnation")]
462 impl columnation::Columnation for Overflowing<$t> {
463 type InnerRegion = columnation::CopyRegion<Self>;
464 }
465
466 impl std::str::FromStr for Overflowing<$t> {
467 type Err = <$t as std::str::FromStr>::Err;
468
469 #[inline(always)]
470 fn from_str(s: &str) -> Result<Self, Self::Err> {
471 <$t>::from_str(s).map(Self)
472 }
473 }
474
475 impl std::hash::Hash for Overflowing<$t> {
476 #[inline(always)]
477 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
478 self.0.hash(state);
479 }
480 }
481
482 impl<T> crate::cast::CastFrom<T> for Overflowing<$t>
483 where
484 $t: crate::cast::CastFrom<T>,
485 {
486 #[inline(always)]
487 fn cast_from(value: T) -> Self {
488 Self(<$t>::cast_from(value))
489 }
490 }
491
492 #[cfg(feature = "num-traits")]
493 impl num_traits::identities::Zero for Overflowing<$t> {
494 #[inline(always)]
495 fn zero() -> Self {
496 Self::ZERO
497 }
498 #[inline(always)]
499 fn is_zero(&self) -> bool {
500 self.0.is_zero()
501 }
502 }
503
504 #[cfg(feature = "num-traits")]
505 impl num_traits::identities::One for Overflowing<$t> {
506 #[inline(always)]
507 fn one() -> Self {
508 Self::ONE
509 }
510 }
511
512 #[cfg(feature = "num-traits")]
513 impl num_traits::Num for Overflowing<$t> {
514 type FromStrRadixErr = <$t as num_traits::Num>::FromStrRadixErr;
515
516 #[inline(always)]
517 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
518 <$t>::from_str_radix(str, radix).map(Self)
519 }
520 }
521 };
522}
523
524macro_rules! impl_overflowing_from {
525 ($t:ty, $($f:ty)+) => {
526 $(
527 impl From<$f> for Overflowing<$t> {
528 #[inline(always)]
529 fn from(value: $f) -> Self {
530 Self(value.into())
531 }
532 }
533 )+
534 };
535}
536
537macro_rules! impl_overflowing_from_overflowing {
538 ($t:ty, $($f:ty)+) => {
539 $(
540 impl From<Overflowing<$f>> for Overflowing<$t> {
541 #[inline(always)]
542 fn from(value: Overflowing<$f>) -> Self {
543 Self(value.0.into())
544 }
545 }
546 )+
547 };
548}
549
550macro_rules! impl_overflowing_try_from {
551 ($t:ty, $($f:ty)+) => {
552 $(
553 impl TryFrom<$f> for Overflowing<$t> {
554 type Error = <$t as TryFrom<$f>>::Error;
555 #[inline(always)]
556 fn try_from(value: $f) -> Result<Self, Self::Error> {
557 <$t>::try_from(value).map(Self)
558 }
559 }
560
561 impl TryFrom<Overflowing<$f>> for Overflowing<$t> {
562 type Error = <$t as TryFrom<$f>>::Error;
563 #[inline(always)]
564 fn try_from(value: Overflowing<$f>) -> Result<Self, Self::Error> {
565 <$t>::try_from(value.0).map(Self)
566 }
567 }
568 )+
569 };
570}
571
572macro_rules! impl_overflowing_signed {
574 ($t:ty, $u:ty) => {
575 impl Overflowing<$t> {
576 pub const MINUS_ONE: Self = Self(-1);
578
579 pub fn abs(self) -> Self {
581 Self(self.0.abs())
582 }
583
584 #[inline(always)]
586 pub fn unsigned_abs(self) -> $u {
587 self.0.unsigned_abs()
588 }
589
590 pub fn is_positive(self) -> bool {
601 self > Self::ZERO
602 }
603
604 pub fn is_negative(self) -> bool {
615 self < Self::ZERO
616 }
617 }
618
619 impl Neg for Overflowing<$t> {
620 type Output = Overflowing<<$t as Neg>::Output>;
621
622 #[inline(always)]
623 fn neg(self) -> Self::Output {
624 match self.0.overflowing_neg() {
625 (result, true) => {
626 overflowing_support::handle_overflow(result, format_args!("-{self}"))
627 }
628 (result, false) => Self(result),
629 }
630 }
631 }
632
633 impl Neg for &Overflowing<$t> {
634 type Output = Overflowing<<$t as Neg>::Output>;
635
636 #[inline(always)]
637 fn neg(self) -> Self::Output {
638 match self.0.overflowing_neg() {
639 (result, true) => {
640 overflowing_support::handle_overflow(result, format_args!("-{self}"))
641 }
642 (result, false) => Overflowing(result),
643 }
644 }
645 }
646
647 #[cfg(feature = "differential-dataflow")]
648 impl differential_dataflow::difference::Abelian for Overflowing<$t> {
649 #[inline(always)]
650 fn negate(&mut self) {
651 *self = -*self
652 }
653 }
654
655 #[cfg(feature = "num-traits")]
656 impl num_traits::sign::Signed for Overflowing<$t> {
657 #[inline(always)]
658 fn abs(&self) -> Self {
659 Self(self.0.abs())
660 }
661 #[inline(always)]
662 fn abs_sub(&self, other: &Self) -> Self {
663 Self(self.0.abs_sub(&other.0))
664 }
665 #[inline(always)]
666 fn signum(&self) -> Self {
667 Self(self.0.signum())
668 }
669 #[inline(always)]
670 fn is_positive(&self) -> bool {
671 self.0.is_positive()
672 }
673 #[inline(always)]
674 fn is_negative(&self) -> bool {
675 self.0.is_negative()
676 }
677 }
678 };
679}
680
681macro_rules! overflowing {
682 ($t:ty, $($fit:ty)+, $($may_fit:ty)+ $(, $unsigned:ty)?) => {
683 impl_overflowing!($t);
684 impl_overflowing_from!($t, $($fit)+ $t);
685 impl_overflowing_from_overflowing!($t, $($fit)+);
686 impl_overflowing_try_from!($t, $($may_fit)+);
687 $( impl_overflowing_signed!($t, $unsigned); )?
688 };
689}
690
691overflowing!(u8, bool, u16 u32 u64 u128 i8 i16 i32 i64 i128 isize usize);
693overflowing!(u16, bool u8, u32 u64 u128 i8 i16 i32 i64 i128 isize usize);
694overflowing!(u32, bool u8 u16, u64 u128 i8 i16 i32 i64 i128 isize usize);
695overflowing!(u64, bool u8 u16 u32, u128 i8 i16 i32 i64 i128 isize usize);
696overflowing!(u128, bool u8 u16 u32 u64, i8 i16 i32 i64 i128 isize usize);
697
698overflowing!(i8, bool, u8 i16 u16 i32 u32 i64 u64 i128 u128 isize usize, u8);
699overflowing!(i16, bool i8 u8, u16 i32 u32 i64 u64 i128 u128 isize usize, u16);
700overflowing!(i32, bool i8 u8 i16 u16, u32 i64 u64 i128 u128 isize usize, u32);
701overflowing!(i64, bool i8 u8 i16 u16 i32 u32, u64 i128 u128 isize usize, u64);
702overflowing!(i128, bool i8 u8 i16 u16 i32 u32 i64 u64, u128 isize usize, u128);
703
704mod overflowing_support {
705 use std::sync::atomic::AtomicUsize;
706
707 use crate::overflowing::OverflowingBehavior;
708
709 const MODE_IGNORE: usize = 0;
711 const MODE_SOFT_PANIC: usize = 1;
713 const MODE_PANIC: usize = 2;
715
716 static OVERFLOWING_MODE: AtomicUsize = AtomicUsize::new(MODE_IGNORE);
717
718 #[track_caller]
720 #[cold]
721 pub(super) fn handle_overflow<T: Into<O>, O>(result: T, description: std::fmt::Arguments) -> O {
722 let mode = OVERFLOWING_MODE.load(std::sync::atomic::Ordering::Relaxed);
723 match mode {
724 #[cfg(not(target_arch = "wasm32"))]
725 MODE_SOFT_PANIC => crate::soft_panic_or_log!("Overflow: {description}"),
726 #[cfg(target_arch = "wasm32")]
729 MODE_SOFT_PANIC => panic!("Overflow: {description}"),
730 MODE_PANIC => panic!("Overflow: {description}"),
731 _ => {}
733 }
734 result.into()
735 }
736
737 pub(crate) fn set_overflowing_mode(behavior: OverflowingBehavior) {
739 let value = match behavior {
740 OverflowingBehavior::Panic => MODE_PANIC,
741 OverflowingBehavior::SoftPanic => MODE_SOFT_PANIC,
742 OverflowingBehavior::Ignore => MODE_IGNORE,
743 };
744 OVERFLOWING_MODE.store(value, std::sync::atomic::Ordering::Relaxed);
745 }
746}
747
748#[cfg(test)]
749mod test {
750 use super::*;
751
752 #[cfg(debug_assertions)]
753 #[crate::test]
754 #[should_panic]
755 fn test_panicking_add() {
756 set_behavior(OverflowingBehavior::Panic);
757 let _ = Overflowing::<i8>::MAX + Overflowing::<i8>::ONE;
758 }
759
760 #[crate::test]
761 fn test_wrapping_add() {
762 let result = Overflowing::<i8>::MAX.wrapping_add(Overflowing::<i8>::ONE);
763 assert_eq!(result, Overflowing::<i8>::MIN);
764 }
765
766 #[crate::test]
767 fn test_checked_add() {
768 let result = Overflowing::<i8>::MAX.checked_add(Overflowing::<i8>::ONE);
769 assert_eq!(result, None);
770 }
771}