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