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