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