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 #[inline(always)]
188 fn as_bytes(&self) -> impl Iterator<Item = (u64, &'a [u8])> {
189 self.0.as_bytes()
190 }
191 }
192
193 impl<'a, T: Copy, TC: FromBytes<'a>> FromBytes<'a> for Overflows<T, TC> {
194 const SLICE_COUNT: usize = TC::SLICE_COUNT;
195 #[inline(always)]
196 fn from_bytes(bytes: &mut impl Iterator<Item = &'a [u8]>) -> Self {
197 Self(TC::from_bytes(bytes), std::marker::PhantomData)
198 }
199 }
200
201 impl<T: Copy, TC: Len> Len for Overflows<T, TC> {
202 #[inline(always)]
203 fn len(&self) -> usize {
204 self.0.len()
205 }
206 }
207
208 impl<T: Copy, TC: Clear> Clear for Overflows<T, TC> {
209 #[inline(always)]
210 fn clear(&mut self) {
211 self.0.clear();
212 }
213 }
214
215 impl<T: Copy, TC: IndexAs<T>> Index for Overflows<T, TC>
216 where
217 Overflowing<T>: From<T>,
218 {
219 type Ref = Overflowing<T>;
220 #[inline(always)]
221 fn get(&self, index: usize) -> Self::Ref {
222 self.0.index_as(index).into()
223 }
224 }
225
226 impl<T: Copy, TC: for<'a> Push<&'a T>> Push<Overflowing<T>> for Overflows<T, TC> {
227 #[inline(always)]
228 fn push(&mut self, item: Overflowing<T>) {
229 self.0.push(&item.0);
230 }
231 }
232
233 impl<T: Copy, TC: Push<T>> Push<&Overflowing<T>> for Overflows<T, TC> {
234 #[inline(always)]
235 fn push(&mut self, item: &Overflowing<T>) {
236 self.0.push(item.0);
237 }
238 }
239}
240
241macro_rules! impl_overflowing {
242 ($t:ty) => {
243 impl Overflowing<$t> {
244 pub const ZERO: Self = Self(0);
246 pub const ONE: Self = Self(1);
248 pub const MIN: Self = Self(<$t>::MIN);
250 pub const MAX: Self = Self(<$t>::MAX);
252
253 #[inline(always)]
255 pub fn checked_add(self, rhs: Self) -> Option<Self> {
256 self.0.checked_add(rhs.0).map(Self)
257 }
258
259 #[inline(always)]
261 pub fn wrapping_add(self, rhs: Self) -> Self {
262 Self(self.0.wrapping_add(rhs.0))
263 }
264
265 #[inline(always)]
267 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
268 self.0.checked_mul(rhs.0).map(Self)
269 }
270
271 #[inline(always)]
273 pub fn wrapping_mul(self, rhs: Self) -> Self {
274 Self(self.0.wrapping_mul(rhs.0))
275 }
276
277 pub fn is_zero(self) -> bool {
279 self == Self::ZERO
280 }
281 }
282
283 impl Add<Self> for Overflowing<$t> {
284 type Output = Self;
285
286 #[inline(always)]
287 fn add(self, rhs: Self) -> Self::Output {
288 match self.0.overflowing_add(rhs.0) {
289 (result, true) => {
290 overflowing_support::handle_overflow(result, format_args!("{self} + {rhs}"))
291 }
292 (result, false) => Self(result),
293 }
294 }
295 }
296
297 impl<'a> Add<&'a Self> for Overflowing<$t> {
298 type Output = Self;
299
300 #[inline(always)]
301 fn add(self, rhs: &'a Self) -> Self::Output {
302 match self.0.overflowing_add(rhs.0) {
303 (result, true) => {
304 overflowing_support::handle_overflow(result, format_args!("{self} + {rhs}"))
305 }
306 (result, false) => Self(result),
307 }
308 }
309 }
310
311 impl AddAssign<Self> for Overflowing<$t> {
312 #[inline(always)]
313 fn add_assign(&mut self, rhs: Self) {
314 *self = *self + rhs;
315 }
316 }
317
318 impl AddAssign<&Self> for Overflowing<$t> {
319 #[inline(always)]
320 fn add_assign(&mut self, rhs: &Self) {
321 *self = *self + *rhs;
322 }
323 }
324
325 impl Div<Self> for Overflowing<$t> {
326 type Output = Overflowing<<$t as Div>::Output>;
327
328 #[inline(always)]
329 fn div(self, rhs: Self) -> Self::Output {
330 match self.0.overflowing_div(rhs.0) {
331 (result, true) => {
332 overflowing_support::handle_overflow(result, format_args!("{self} / {rhs}"))
333 }
334 (result, false) => Self(result),
335 }
336 }
337 }
338
339 impl Rem<Self> for Overflowing<$t> {
340 type Output = Overflowing<<$t as Rem>::Output>;
341
342 #[inline(always)]
343 fn rem(self, rhs: Self) -> Self::Output {
344 match self.0.overflowing_rem(rhs.0) {
345 (result, true) => {
346 overflowing_support::handle_overflow(result, format_args!("{self} % {rhs}"))
347 }
348 (result, false) => Self(result),
349 }
350 }
351 }
352
353 impl Sub<Self> for Overflowing<$t> {
354 type Output = Self;
355
356 #[inline(always)]
357 fn sub(self, rhs: Self) -> Self::Output {
358 match self.0.overflowing_sub(rhs.0) {
359 (result, true) => {
360 overflowing_support::handle_overflow(result, format_args!("{self} - {rhs}"))
361 }
362 (result, false) => Self(result),
363 }
364 }
365 }
366
367 impl<'a> Sub<&'a Self> for Overflowing<$t> {
368 type Output = Self;
369
370 #[inline(always)]
371 fn sub(self, rhs: &'a Self) -> Self::Output {
372 match self.0.overflowing_sub(rhs.0) {
373 (result, true) => {
374 overflowing_support::handle_overflow(result, format_args!("{self} - {rhs}"))
375 }
376 (result, false) => Self(result),
377 }
378 }
379 }
380
381 impl SubAssign<Self> for Overflowing<$t> {
382 #[inline(always)]
383 fn sub_assign(&mut self, rhs: Self) {
384 *self = *self - rhs;
385 }
386 }
387
388 impl SubAssign<&Self> for Overflowing<$t> {
389 #[inline(always)]
390 fn sub_assign(&mut self, rhs: &Self) {
391 *self = *self - *rhs;
392 }
393 }
394
395 impl std::iter::Sum<Overflowing<$t>> for Overflowing<$t> {
396 #[inline(always)]
397 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
398 iter.fold(Self::ZERO, |a, b| a + b)
399 }
400 }
401
402 impl<'a> std::iter::Sum<&'a Overflowing<$t>> for Overflowing<$t> {
403 #[inline(always)]
404 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
405 iter.fold(Self::ZERO, |a, b| a + b)
406 }
407 }
408
409 impl Mul for Overflowing<$t> {
410 type Output = Self;
411
412 #[inline(always)]
413 fn mul(self, rhs: Self) -> Self::Output {
414 match self.0.overflowing_mul(rhs.0) {
415 (result, true) => {
416 overflowing_support::handle_overflow(result, format_args!("{self} * {rhs}"))
417 }
418 (result, false) => Self(result),
419 }
420 }
421 }
422
423 #[cfg(feature = "differential-dataflow")]
424 impl differential_dataflow::difference::IsZero for Overflowing<$t> {
425 #[inline(always)]
426 fn is_zero(&self) -> bool {
427 self.0.is_zero()
428 }
429 }
430
431 #[cfg(feature = "differential-dataflow")]
432 impl differential_dataflow::difference::Semigroup for Overflowing<$t> {
433 #[inline(always)]
434 fn plus_equals(&mut self, rhs: &Self) {
435 *self += *rhs
436 }
437 }
438
439 #[cfg(feature = "differential-dataflow")]
440 impl differential_dataflow::difference::Monoid for Overflowing<$t> {
441 #[inline(always)]
442 fn zero() -> Self {
443 Self::ZERO
444 }
445 }
446
447 #[cfg(feature = "differential-dataflow")]
448 impl differential_dataflow::difference::Multiply<Self> for Overflowing<$t> {
449 type Output = Self;
450 #[inline(always)]
451 fn multiply(self, rhs: &Self) -> Self::Output {
452 self * *rhs
453 }
454 }
455
456 #[cfg(feature = "columnation")]
457 impl columnation::Columnation for Overflowing<$t> {
458 type InnerRegion = columnation::CopyRegion<Self>;
459 }
460
461 impl std::str::FromStr for Overflowing<$t> {
462 type Err = <$t as std::str::FromStr>::Err;
463
464 #[inline(always)]
465 fn from_str(s: &str) -> Result<Self, Self::Err> {
466 <$t>::from_str(s).map(Self)
467 }
468 }
469
470 impl std::hash::Hash for Overflowing<$t> {
471 #[inline(always)]
472 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
473 self.0.hash(state);
474 }
475 }
476
477 impl<T> crate::cast::CastFrom<T> for Overflowing<$t>
478 where
479 $t: crate::cast::CastFrom<T>,
480 {
481 #[inline(always)]
482 fn cast_from(value: T) -> Self {
483 Self(<$t>::cast_from(value))
484 }
485 }
486
487 #[cfg(feature = "num-traits")]
488 impl num_traits::identities::Zero for Overflowing<$t> {
489 #[inline(always)]
490 fn zero() -> Self {
491 Self::ZERO
492 }
493 #[inline(always)]
494 fn is_zero(&self) -> bool {
495 self.0.is_zero()
496 }
497 }
498
499 #[cfg(feature = "num-traits")]
500 impl num_traits::identities::One for Overflowing<$t> {
501 #[inline(always)]
502 fn one() -> Self {
503 Self::ONE
504 }
505 }
506
507 #[cfg(feature = "num-traits")]
508 impl num_traits::Num for Overflowing<$t> {
509 type FromStrRadixErr = <$t as num_traits::Num>::FromStrRadixErr;
510
511 #[inline(always)]
512 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
513 <$t>::from_str_radix(str, radix).map(Self)
514 }
515 }
516 };
517}
518
519macro_rules! impl_overflowing_from {
520 ($t:ty, $($f:ty)+) => {
521 $(
522 impl From<$f> for Overflowing<$t> {
523 #[inline(always)]
524 fn from(value: $f) -> Self {
525 Self(value.into())
526 }
527 }
528 )+
529 };
530}
531
532macro_rules! impl_overflowing_from_overflowing {
533 ($t:ty, $($f:ty)+) => {
534 $(
535 impl From<Overflowing<$f>> for Overflowing<$t> {
536 #[inline(always)]
537 fn from(value: Overflowing<$f>) -> Self {
538 Self(value.0.into())
539 }
540 }
541 )+
542 };
543}
544
545macro_rules! impl_overflowing_try_from {
546 ($t:ty, $($f:ty)+) => {
547 $(
548 impl TryFrom<$f> for Overflowing<$t> {
549 type Error = <$t as TryFrom<$f>>::Error;
550 #[inline(always)]
551 fn try_from(value: $f) -> Result<Self, Self::Error> {
552 <$t>::try_from(value).map(Self)
553 }
554 }
555
556 impl TryFrom<Overflowing<$f>> for Overflowing<$t> {
557 type Error = <$t as TryFrom<$f>>::Error;
558 #[inline(always)]
559 fn try_from(value: Overflowing<$f>) -> Result<Self, Self::Error> {
560 <$t>::try_from(value.0).map(Self)
561 }
562 }
563 )+
564 };
565}
566
567macro_rules! impl_overflowing_signed {
569 ($t:ty, $u:ty) => {
570 impl Overflowing<$t> {
571 pub const MINUS_ONE: Self = Self(-1);
573
574 pub fn abs(self) -> Self {
576 Self(self.0.abs())
577 }
578
579 #[inline(always)]
581 pub fn unsigned_abs(self) -> $u {
582 self.0.unsigned_abs()
583 }
584
585 pub fn is_positive(self) -> bool {
596 self > Self::ZERO
597 }
598
599 pub fn is_negative(self) -> bool {
610 self < Self::ZERO
611 }
612 }
613
614 impl Neg for Overflowing<$t> {
615 type Output = Overflowing<<$t as Neg>::Output>;
616
617 #[inline(always)]
618 fn neg(self) -> Self::Output {
619 match self.0.overflowing_neg() {
620 (result, true) => {
621 overflowing_support::handle_overflow(result, format_args!("-{self}"))
622 }
623 (result, false) => Self(result),
624 }
625 }
626 }
627
628 impl Neg for &Overflowing<$t> {
629 type Output = Overflowing<<$t as Neg>::Output>;
630
631 #[inline(always)]
632 fn neg(self) -> Self::Output {
633 match self.0.overflowing_neg() {
634 (result, true) => {
635 overflowing_support::handle_overflow(result, format_args!("-{self}"))
636 }
637 (result, false) => Overflowing(result),
638 }
639 }
640 }
641
642 #[cfg(feature = "differential-dataflow")]
643 impl differential_dataflow::difference::Abelian for Overflowing<$t> {
644 #[inline(always)]
645 fn negate(&mut self) {
646 *self = -*self
647 }
648 }
649
650 #[cfg(feature = "num-traits")]
651 impl num_traits::sign::Signed for Overflowing<$t> {
652 #[inline(always)]
653 fn abs(&self) -> Self {
654 Self(self.0.abs())
655 }
656 #[inline(always)]
657 fn abs_sub(&self, other: &Self) -> Self {
658 Self(self.0.abs_sub(&other.0))
659 }
660 #[inline(always)]
661 fn signum(&self) -> Self {
662 Self(self.0.signum())
663 }
664 #[inline(always)]
665 fn is_positive(&self) -> bool {
666 self.0.is_positive()
667 }
668 #[inline(always)]
669 fn is_negative(&self) -> bool {
670 self.0.is_negative()
671 }
672 }
673 };
674}
675
676macro_rules! overflowing {
677 ($t:ty, $($fit:ty)+, $($may_fit:ty)+ $(, $unsigned:ty)?) => {
678 impl_overflowing!($t);
679 impl_overflowing_from!($t, $($fit)+ $t);
680 impl_overflowing_from_overflowing!($t, $($fit)+);
681 impl_overflowing_try_from!($t, $($may_fit)+);
682 $( impl_overflowing_signed!($t, $unsigned); )?
683 };
684}
685
686overflowing!(u8, bool, u16 u32 u64 u128 i8 i16 i32 i64 i128 isize usize);
688overflowing!(u16, bool u8, u32 u64 u128 i8 i16 i32 i64 i128 isize usize);
689overflowing!(u32, bool u8 u16, u64 u128 i8 i16 i32 i64 i128 isize usize);
690overflowing!(u64, bool u8 u16 u32, u128 i8 i16 i32 i64 i128 isize usize);
691overflowing!(u128, bool u8 u16 u32 u64, i8 i16 i32 i64 i128 isize usize);
692
693overflowing!(i8, bool, u8 i16 u16 i32 u32 i64 u64 i128 u128 isize usize, u8);
694overflowing!(i16, bool i8 u8, u16 i32 u32 i64 u64 i128 u128 isize usize, u16);
695overflowing!(i32, bool i8 u8 i16 u16, u32 i64 u64 i128 u128 isize usize, u32);
696overflowing!(i64, bool i8 u8 i16 u16 i32 u32, u64 i128 u128 isize usize, u64);
697overflowing!(i128, bool i8 u8 i16 u16 i32 u32 i64 u64, u128 isize usize, u128);
698
699mod overflowing_support {
700 use std::sync::atomic::AtomicUsize;
701
702 use crate::overflowing::OverflowingBehavior;
703
704 const MODE_IGNORE: usize = 0;
706 const MODE_SOFT_PANIC: usize = 1;
708 const MODE_PANIC: usize = 2;
710
711 static OVERFLOWING_MODE: AtomicUsize = AtomicUsize::new(MODE_IGNORE);
712
713 #[track_caller]
715 #[cold]
716 pub(super) fn handle_overflow<T: Into<O>, O>(result: T, description: std::fmt::Arguments) -> O {
717 let mode = OVERFLOWING_MODE.load(std::sync::atomic::Ordering::Relaxed);
718 match mode {
719 #[cfg(not(target_arch = "wasm32"))]
720 MODE_SOFT_PANIC => crate::soft_panic_or_log!("Overflow: {description}"),
721 #[cfg(target_arch = "wasm32")]
724 MODE_SOFT_PANIC => panic!("Overflow: {description}"),
725 MODE_PANIC => panic!("Overflow: {description}"),
726 _ => {}
728 }
729 result.into()
730 }
731
732 pub(crate) fn set_overflowing_mode(behavior: OverflowingBehavior) {
734 let value = match behavior {
735 OverflowingBehavior::Panic => MODE_PANIC,
736 OverflowingBehavior::SoftPanic => MODE_SOFT_PANIC,
737 OverflowingBehavior::Ignore => MODE_IGNORE,
738 };
739 OVERFLOWING_MODE.store(value, std::sync::atomic::Ordering::Relaxed);
740 }
741}
742
743#[cfg(test)]
744mod test {
745 use super::*;
746
747 #[cfg(debug_assertions)]
748 #[crate::test]
749 #[should_panic]
750 fn test_panicking_add() {
751 set_behavior(OverflowingBehavior::Panic);
752 let _ = Overflowing::<i8>::MAX + Overflowing::<i8>::ONE;
753 }
754
755 #[crate::test]
756 fn test_wrapping_add() {
757 let result = Overflowing::<i8>::MAX.wrapping_add(Overflowing::<i8>::ONE);
758 assert_eq!(result, Overflowing::<i8>::MIN);
759 }
760
761 #[crate::test]
762 fn test_checked_add() {
763 let result = Overflowing::<i8>::MAX.checked_add(Overflowing::<i8>::ONE);
764 assert_eq!(result, None);
765 }
766}