Skip to main content

mz_ore/
overflowing.rs

1// Copyright 2019 The Rust Project Contributors
2// Copyright Materialize, Inc. and contributors. All rights reserved.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License in the LICENSE file at the
7// root of this repository, or online at
8//
9//     http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17//! Overflowing number types.
18
19#[cfg(feature = "proptest")]
20use proptest_derive::Arbitrary;
21use serde::{Deserialize, Serialize};
22use std::ops::{Add, AddAssign, Div, Mul, Neg, Rem, Sub, SubAssign};
23
24/// Overflowing number. Operations panic on overflow, even in release mode.
25///
26/// The `ore_overflowing_behavior` feature flag can be used to control the
27/// overflow behavior:
28/// * `panic`: panic on overflow (default when debug assertions are enabled).
29/// * `soft_panic`: log a warning on overflow, or panic, depending on whether
30///   soft assertions are enbaled.
31/// * `ignore`: ignore overflow (default when debug assertions are disabled).
32/// The default value is `panic` when `debug_assertions` are enabled, or `ignore` otherwise.
33///
34/// The non-aborting modes simply return the result of the operation, which can
35/// include overflows.
36#[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/// The behavior of the [`Overflowing`] type when an overflow occurs.
52#[derive(Debug)]
53pub enum OverflowingBehavior {
54    /// Panic on overflow. Corresponds to the `panic` string.
55    Panic,
56    /// Soft panic on overflow. Corresponds to the `soft_panic` string.
57    SoftPanic,
58    /// Ignore overflow. Corresponds to the `ignore` string.
59    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
75/// Set the overflowing behavior for the process.
76///
77/// This function is thread-safe and can be used to change the behavior at runtime.
78///
79/// The default behavior is to ignore overflows.
80pub fn set_behavior(behavior: OverflowingBehavior) {
81    overflowing_support::set_overflowing_mode(behavior);
82}
83
84impl<T> Overflowing<T> {
85    /// Returns the inner value.
86    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::bytes::indexed::DecodedStore;
102    use columnar::common::PushIndexAs;
103    use columnar::{
104        AsBytes, Borrow, Clear, Columnar, Container, FromBytes, Index, IndexAs, Len, Push,
105    };
106    use serde::{Deserialize, Serialize};
107    use std::ops::Range;
108
109    impl<T: Columnar<Container: PushIndexAs<T>> + Copy + Send> Columnar for Overflowing<T>
110    where
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, T::Container>;
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    /// Columnar container for [`Overflowing`], delegating to `T`'s own container `TC`, so
128    /// `Overflowing<i128>` uses columnar's byte-encoded `i128` store rather than requiring
129    /// `&[i128]` to be castable to bytes.
130    #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
131    pub struct Overflows<T, TC>(TC, std::marker::PhantomData<T>);
132
133    impl<T, TC: Default> Default for Overflows<T, TC> {
134        #[inline(always)]
135        fn default() -> Self {
136            Self(TC::default(), std::marker::PhantomData)
137        }
138    }
139
140    impl<T: Columnar + Copy + Send, TC: PushIndexAs<T>> Borrow for Overflows<T, TC>
141    where
142        Overflowing<T>: From<T>,
143    {
144        type Ref<'a> = Overflowing<T>;
145        type Borrowed<'a>
146            = Overflows<T, TC::Borrowed<'a>>
147        where
148            Self: 'a;
149        #[inline(always)]
150        fn borrow<'a>(&'a self) -> Self::Borrowed<'a> {
151            Overflows(self.0.borrow(), std::marker::PhantomData)
152        }
153        #[inline(always)]
154        fn reborrow<'b, 'a: 'b>(item: Self::Borrowed<'a>) -> Self::Borrowed<'b>
155        where
156            Self: 'a,
157        {
158            Overflows(TC::reborrow(item.0), std::marker::PhantomData)
159        }
160
161        #[inline(always)]
162        fn reborrow_ref<'b, 'a: 'b>(item: Self::Ref<'a>) -> Self::Ref<'b>
163        where
164            Self: 'a,
165        {
166            item
167        }
168    }
169
170    impl<T: Columnar + Copy + Send, TC: PushIndexAs<T>> Container for Overflows<T, TC>
171    where
172        Overflowing<T>: From<T>,
173    {
174        #[inline(always)]
175        fn extend_from_self(&mut self, other: Self::Borrowed<'_>, range: Range<usize>) {
176            self.0.extend_from_self(other.0, range);
177        }
178        #[inline(always)]
179        fn reserve_for<'a, I>(&mut self, selves: I)
180        where
181            Self: 'a,
182            I: Iterator<Item = Self::Borrowed<'a>> + Clone,
183        {
184            self.0.reserve_for(selves.map(|s| s.0));
185        }
186    }
187
188    impl<'a, T: Copy, TC: AsBytes<'a>> AsBytes<'a> for Overflows<T, TC> {
189        const SLICE_COUNT: usize = TC::SLICE_COUNT;
190        #[inline(always)]
191        fn get_byte_slice(&self, index: usize) -> (u64, &'a [u8]) {
192            self.0.get_byte_slice(index)
193        }
194        #[inline(always)]
195        fn as_bytes(&self) -> impl Iterator<Item = (u64, &'a [u8])> {
196            self.0.as_bytes()
197        }
198    }
199
200    impl<'a, T: Copy, TC: FromBytes<'a>> FromBytes<'a> for Overflows<T, TC> {
201        const SLICE_COUNT: usize = TC::SLICE_COUNT;
202        #[inline(always)]
203        fn from_bytes(bytes: &mut impl Iterator<Item = &'a [u8]>) -> Self {
204            Self(TC::from_bytes(bytes), std::marker::PhantomData)
205        }
206        #[inline(always)]
207        fn from_store(store: &DecodedStore<'a>, offset: &mut usize) -> Self {
208            Self(TC::from_store(store, offset), std::marker::PhantomData)
209        }
210        fn element_sizes(sizes: &mut Vec<usize>) -> Result<(), String> {
211            TC::element_sizes(sizes)
212        }
213    }
214
215    impl<T: Copy, TC: Len> Len for Overflows<T, TC> {
216        #[inline(always)]
217        fn len(&self) -> usize {
218            self.0.len()
219        }
220    }
221
222    impl<T: Copy, TC: Clear> Clear for Overflows<T, TC> {
223        #[inline(always)]
224        fn clear(&mut self) {
225            self.0.clear();
226        }
227    }
228
229    impl<T: Copy, TC: IndexAs<T>> Index for Overflows<T, TC>
230    where
231        Overflowing<T>: From<T>,
232    {
233        type Ref = Overflowing<T>;
234        #[inline(always)]
235        fn get(&self, index: usize) -> Self::Ref {
236            self.0.index_as(index).into()
237        }
238    }
239
240    impl<T: Copy, TC: for<'a> Push<&'a T>> Push<Overflowing<T>> for Overflows<T, TC> {
241        #[inline(always)]
242        fn push(&mut self, item: Overflowing<T>) {
243            self.0.push(&item.0);
244        }
245    }
246
247    impl<T: Copy, TC: for<'a> Push<&'a T>> Push<&Overflowing<T>> for Overflows<T, TC> {
248        #[inline(always)]
249        fn push(&mut self, item: &Overflowing<T>) {
250            self.0.push(&item.0);
251        }
252    }
253}
254
255macro_rules! impl_overflowing {
256    ($t:ty) => {
257        impl Overflowing<$t> {
258            /// The value zero.
259            pub const ZERO: Self = Self(0);
260            /// The value one.
261            pub const ONE: Self = Self(1);
262            /// The minimum value.
263            pub const MIN: Self = Self(<$t>::MIN);
264            /// The maximum value.
265            pub const MAX: Self = Self(<$t>::MAX);
266
267            /// Checked addition. Returns `None` if overflow occurred.
268            #[inline(always)]
269            pub fn checked_add(self, rhs: Self) -> Option<Self> {
270                self.0.checked_add(rhs.0).map(Self)
271            }
272
273            /// Wrapping addition.
274            #[inline(always)]
275            pub fn wrapping_add(self, rhs: Self) -> Self {
276                Self(self.0.wrapping_add(rhs.0))
277            }
278
279            /// Checked multiplication. Returns `None` if overflow occurred.
280            #[inline(always)]
281            pub fn checked_mul(self, rhs: Self) -> Option<Self> {
282                self.0.checked_mul(rhs.0).map(Self)
283            }
284
285            /// Wrapping multiplication.
286            #[inline(always)]
287            pub fn wrapping_mul(self, rhs: Self) -> Self {
288                Self(self.0.wrapping_mul(rhs.0))
289            }
290
291            /// Returns `true` if the number is zero.
292            pub fn is_zero(self) -> bool {
293                self == Self::ZERO
294            }
295        }
296
297        impl Add<Self> for Overflowing<$t> {
298            type Output = Self;
299
300            #[inline(always)]
301            fn add(self, rhs: 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<'a> Add<&'a Self> for Overflowing<$t> {
312            type Output = Self;
313
314            #[inline(always)]
315            fn add(self, rhs: &'a Self) -> Self::Output {
316                match self.0.overflowing_add(rhs.0) {
317                    (result, true) => {
318                        overflowing_support::handle_overflow(result, format_args!("{self} + {rhs}"))
319                    }
320                    (result, false) => Self(result),
321                }
322            }
323        }
324
325        impl AddAssign<Self> for Overflowing<$t> {
326            #[inline(always)]
327            fn add_assign(&mut self, rhs: Self) {
328                *self = *self + rhs;
329            }
330        }
331
332        impl AddAssign<&Self> for Overflowing<$t> {
333            #[inline(always)]
334            fn add_assign(&mut self, rhs: &Self) {
335                *self = *self + *rhs;
336            }
337        }
338
339        impl Div<Self> for Overflowing<$t> {
340            type Output = Overflowing<<$t as Div>::Output>;
341
342            #[inline(always)]
343            fn div(self, rhs: Self) -> Self::Output {
344                match self.0.overflowing_div(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 Rem<Self> for Overflowing<$t> {
354            type Output = Overflowing<<$t as Rem>::Output>;
355
356            #[inline(always)]
357            fn rem(self, rhs: Self) -> Self::Output {
358                match self.0.overflowing_rem(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 Sub<Self> for Overflowing<$t> {
368            type Output = Self;
369
370            #[inline(always)]
371            fn sub(self, rhs: 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<'a> Sub<&'a Self> for Overflowing<$t> {
382            type Output = Self;
383
384            #[inline(always)]
385            fn sub(self, rhs: &'a Self) -> Self::Output {
386                match self.0.overflowing_sub(rhs.0) {
387                    (result, true) => {
388                        overflowing_support::handle_overflow(result, format_args!("{self} - {rhs}"))
389                    }
390                    (result, false) => Self(result),
391                }
392            }
393        }
394
395        impl SubAssign<Self> for Overflowing<$t> {
396            #[inline(always)]
397            fn sub_assign(&mut self, rhs: Self) {
398                *self = *self - rhs;
399            }
400        }
401
402        impl SubAssign<&Self> for Overflowing<$t> {
403            #[inline(always)]
404            fn sub_assign(&mut self, rhs: &Self) {
405                *self = *self - *rhs;
406            }
407        }
408
409        impl std::iter::Sum<Overflowing<$t>> for Overflowing<$t> {
410            #[inline(always)]
411            fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
412                iter.fold(Self::ZERO, |a, b| a + b)
413            }
414        }
415
416        impl<'a> std::iter::Sum<&'a Overflowing<$t>> for Overflowing<$t> {
417            #[inline(always)]
418            fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
419                iter.fold(Self::ZERO, |a, b| a + b)
420            }
421        }
422
423        impl Mul for Overflowing<$t> {
424            type Output = Self;
425
426            #[inline(always)]
427            fn mul(self, rhs: Self) -> Self::Output {
428                match self.0.overflowing_mul(rhs.0) {
429                    (result, true) => {
430                        overflowing_support::handle_overflow(result, format_args!("{self} * {rhs}"))
431                    }
432                    (result, false) => Self(result),
433                }
434            }
435        }
436
437        #[cfg(feature = "differential-dataflow")]
438        impl differential_dataflow::difference::IsZero for Overflowing<$t> {
439            #[inline(always)]
440            fn is_zero(&self) -> bool {
441                self.0.is_zero()
442            }
443        }
444
445        #[cfg(feature = "differential-dataflow")]
446        impl differential_dataflow::difference::Semigroup for Overflowing<$t> {
447            #[inline(always)]
448            fn plus_equals(&mut self, rhs: &Self) {
449                *self += *rhs
450            }
451        }
452
453        #[cfg(feature = "differential-dataflow")]
454        impl differential_dataflow::difference::Monoid for Overflowing<$t> {
455            #[inline(always)]
456            fn zero() -> Self {
457                Self::ZERO
458            }
459        }
460
461        #[cfg(feature = "differential-dataflow")]
462        impl differential_dataflow::difference::Multiply<Self> for Overflowing<$t> {
463            type Output = Self;
464            #[inline(always)]
465            fn multiply(self, rhs: &Self) -> Self::Output {
466                self * *rhs
467            }
468        }
469
470        #[cfg(feature = "columnation")]
471        impl columnation::Columnation for Overflowing<$t> {
472            type InnerRegion = columnation::CopyRegion<Self>;
473        }
474
475        impl std::str::FromStr for Overflowing<$t> {
476            type Err = <$t as std::str::FromStr>::Err;
477
478            #[inline(always)]
479            fn from_str(s: &str) -> Result<Self, Self::Err> {
480                <$t>::from_str(s).map(Self)
481            }
482        }
483
484        impl std::hash::Hash for Overflowing<$t> {
485            #[inline(always)]
486            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
487                self.0.hash(state);
488            }
489        }
490
491        impl<T> crate::cast::CastFrom<T> for Overflowing<$t>
492        where
493            $t: crate::cast::CastFrom<T>,
494        {
495            #[inline(always)]
496            fn cast_from(value: T) -> Self {
497                Self(<$t>::cast_from(value))
498            }
499        }
500
501        #[cfg(feature = "num-traits")]
502        impl num_traits::identities::Zero for Overflowing<$t> {
503            #[inline(always)]
504            fn zero() -> Self {
505                Self::ZERO
506            }
507            #[inline(always)]
508            fn is_zero(&self) -> bool {
509                self.0.is_zero()
510            }
511        }
512
513        #[cfg(feature = "num-traits")]
514        impl num_traits::identities::One for Overflowing<$t> {
515            #[inline(always)]
516            fn one() -> Self {
517                Self::ONE
518            }
519        }
520
521        #[cfg(feature = "num-traits")]
522        impl num_traits::Num for Overflowing<$t> {
523            type FromStrRadixErr = <$t as num_traits::Num>::FromStrRadixErr;
524
525            #[inline(always)]
526            fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
527                <$t>::from_str_radix(str, radix).map(Self)
528            }
529        }
530    };
531}
532
533macro_rules! impl_overflowing_from {
534    ($t:ty, $($f:ty)+) => {
535        $(
536            impl From<$f> for Overflowing<$t> {
537                #[inline(always)]
538                fn from(value: $f) -> Self {
539                    Self(value.into())
540                }
541            }
542        )+
543    };
544}
545
546macro_rules! impl_overflowing_from_overflowing {
547    ($t:ty, $($f:ty)+) => {
548        $(
549            impl From<Overflowing<$f>> for Overflowing<$t> {
550                #[inline(always)]
551                fn from(value: Overflowing<$f>) -> Self {
552                    Self(value.0.into())
553                }
554            }
555        )+
556    };
557}
558
559macro_rules! impl_overflowing_try_from {
560    ($t:ty, $($f:ty)+) => {
561        $(
562            impl TryFrom<$f> for Overflowing<$t> {
563                type Error = <$t as TryFrom<$f>>::Error;
564                #[inline(always)]
565                fn try_from(value: $f) -> Result<Self, Self::Error> {
566                    <$t>::try_from(value).map(Self)
567                }
568            }
569
570            impl TryFrom<Overflowing<$f>> for Overflowing<$t> {
571                type Error = <$t as TryFrom<$f>>::Error;
572                #[inline(always)]
573                fn try_from(value: Overflowing<$f>) -> Result<Self, Self::Error> {
574                    <$t>::try_from(value.0).map(Self)
575                }
576            }
577        )+
578    };
579}
580
581// Implement Overflowing for signed types.
582macro_rules! impl_overflowing_signed {
583    ($t:ty, $u:ty) => {
584        impl Overflowing<$t> {
585            /// The value minus one.
586            pub const MINUS_ONE: Self = Self(-1);
587
588            /// Returns the absolute value of the number.
589            pub fn abs(self) -> Self {
590                Self(self.0.abs())
591            }
592
593            /// Returns the absolute value of the number as an unsigned integer.
594            #[inline(always)]
595            pub fn unsigned_abs(self) -> $u {
596                self.0.unsigned_abs()
597            }
598
599            /// Returns `true` if the number is positive and `false` if the number is zero
600            /// or negative.
601            ///
602            /// # Examples
603            ///
604            /// ```
605            /// # use mz_ore::Overflowing;
606            /// assert!(!Overflowing::<i64>::from(-10i32).is_positive());
607            /// assert!(Overflowing::<i64>::from(10i32).is_positive());
608            /// ```
609            pub fn is_positive(self) -> bool {
610                self > Self::ZERO
611            }
612
613            /// Returns `true` if the number is negative and `false` if the number is zero
614            /// or positive.
615            ///
616            /// # Examples
617            ///
618            /// ```
619            /// # use mz_ore::Overflowing;
620            /// assert!(Overflowing::<i64>::from(-10i32).is_negative());
621            /// assert!(!Overflowing::<i64>::from(10i32).is_negative());
622            /// ```
623            pub fn is_negative(self) -> bool {
624                self < Self::ZERO
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) => Self(result),
638                }
639            }
640        }
641
642        impl Neg for &Overflowing<$t> {
643            type Output = Overflowing<<$t as Neg>::Output>;
644
645            #[inline(always)]
646            fn neg(self) -> Self::Output {
647                match self.0.overflowing_neg() {
648                    (result, true) => {
649                        overflowing_support::handle_overflow(result, format_args!("-{self}"))
650                    }
651                    (result, false) => Overflowing(result),
652                }
653            }
654        }
655
656        #[cfg(feature = "differential-dataflow")]
657        impl differential_dataflow::difference::Abelian for Overflowing<$t> {
658            #[inline(always)]
659            fn negate(&mut self) {
660                *self = -*self
661            }
662        }
663
664        #[cfg(feature = "num-traits")]
665        impl num_traits::sign::Signed for Overflowing<$t> {
666            #[inline(always)]
667            fn abs(&self) -> Self {
668                Self(self.0.abs())
669            }
670            #[inline(always)]
671            fn abs_sub(&self, other: &Self) -> Self {
672                Self(self.0.abs_sub(&other.0))
673            }
674            #[inline(always)]
675            fn signum(&self) -> Self {
676                Self(self.0.signum())
677            }
678            #[inline(always)]
679            fn is_positive(&self) -> bool {
680                self.0.is_positive()
681            }
682            #[inline(always)]
683            fn is_negative(&self) -> bool {
684                self.0.is_negative()
685            }
686        }
687    };
688}
689
690macro_rules! overflowing {
691    ($t:ty, $($fit:ty)+, $($may_fit:ty)+ $(, $unsigned:ty)?) => {
692        impl_overflowing!($t);
693        impl_overflowing_from!($t, $($fit)+ $t);
694        impl_overflowing_from_overflowing!($t, $($fit)+);
695        impl_overflowing_try_from!($t, $($may_fit)+);
696        $( impl_overflowing_signed!($t, $unsigned); )?
697    };
698}
699
700// type, types that certainly fit, types that may fit, optional corresponding unsigned type
701overflowing!(u8, bool, u16 u32 u64 u128 i8 i16 i32 i64 i128 isize usize);
702overflowing!(u16, bool u8, u32 u64 u128 i8 i16 i32 i64 i128 isize usize);
703overflowing!(u32, bool u8 u16, u64 u128 i8 i16 i32 i64 i128 isize usize);
704overflowing!(u64, bool u8 u16 u32, u128 i8 i16 i32 i64 i128 isize usize);
705overflowing!(u128, bool u8 u16 u32 u64, i8 i16 i32 i64 i128 isize usize);
706
707overflowing!(i8, bool, u8 i16 u16 i32 u32 i64 u64 i128 u128 isize usize, u8);
708overflowing!(i16, bool i8 u8, u16 i32 u32 i64 u64 i128 u128 isize usize, u16);
709overflowing!(i32, bool i8 u8 i16 u16, u32 i64 u64 i128 u128 isize usize, u32);
710overflowing!(i64, bool i8 u8 i16 u16 i32 u32, u64 i128 u128 isize usize, u64);
711overflowing!(i128, bool i8 u8 i16 u16 i32 u32 i64 u64, u128 isize usize, u128);
712
713mod overflowing_support {
714    use std::sync::atomic::AtomicUsize;
715
716    use crate::overflowing::OverflowingBehavior;
717
718    /// Ignore overflow.
719    const MODE_IGNORE: usize = 0;
720    /// Soft assert on overflow.
721    const MODE_SOFT_PANIC: usize = 1;
722    /// Panic on overflow.
723    const MODE_PANIC: usize = 2;
724
725    static OVERFLOWING_MODE: AtomicUsize = AtomicUsize::new(MODE_IGNORE);
726
727    /// Handles overflow for [`Overflowing`](super::Overflowing) numbers.
728    #[track_caller]
729    #[cold]
730    pub(super) fn handle_overflow<T: Into<O>, O>(result: T, description: std::fmt::Arguments) -> O {
731        let mode = OVERFLOWING_MODE.load(std::sync::atomic::Ordering::Relaxed);
732        match mode {
733            #[cfg(not(target_arch = "wasm32"))]
734            MODE_SOFT_PANIC => crate::soft_panic_or_log!("Overflow: {description}"),
735            // We cannot use the logging `soft_panic_or_log` in wasm, so we panic instead (soft
736            // assertions are always enabled in wasm).
737            #[cfg(target_arch = "wasm32")]
738            MODE_SOFT_PANIC => panic!("Overflow: {description}"),
739            MODE_PANIC => panic!("Overflow: {description}"),
740            // MODE_IGNORE and all other (impossible) values
741            _ => {}
742        }
743        result.into()
744    }
745
746    /// Set the overflowing mode.
747    pub(crate) fn set_overflowing_mode(behavior: OverflowingBehavior) {
748        let value = match behavior {
749            OverflowingBehavior::Panic => MODE_PANIC,
750            OverflowingBehavior::SoftPanic => MODE_SOFT_PANIC,
751            OverflowingBehavior::Ignore => MODE_IGNORE,
752        };
753        OVERFLOWING_MODE.store(value, std::sync::atomic::Ordering::Relaxed);
754    }
755}
756
757#[cfg(test)]
758mod test {
759    use super::*;
760
761    #[cfg(debug_assertions)]
762    #[crate::test]
763    #[should_panic]
764    fn test_panicking_add() {
765        set_behavior(OverflowingBehavior::Panic);
766        let _ = Overflowing::<i8>::MAX + Overflowing::<i8>::ONE;
767    }
768
769    #[crate::test]
770    fn test_wrapping_add() {
771        let result = Overflowing::<i8>::MAX.wrapping_add(Overflowing::<i8>::ONE);
772        assert_eq!(result, Overflowing::<i8>::MIN);
773    }
774
775    #[crate::test]
776    fn test_checked_add() {
777        let result = Overflowing::<i8>::MAX.checked_add(Overflowing::<i8>::ONE);
778        assert_eq!(result, None);
779    }
780
781    #[cfg(feature = "columnar")]
782    #[crate::test]
783    fn test_columnar_i128_round_trip() {
784        use ::columnar::{AsBytes, Borrow, BorrowedOf, Columnar, FromBytes, Index, Len};
785
786        let values = [
787            Overflowing::<i128>::MIN,
788            Overflowing(-7),
789            Overflowing::<i128>::ZERO,
790            Overflowing::<i128>::ONE,
791            Overflowing::<i128>::MAX,
792        ];
793        let container = Overflowing::<i128>::as_columns(values.iter());
794        assert_eq!(container.len(), values.len());
795        let borrowed = container.borrow();
796        for (index, value) in values.iter().enumerate() {
797            assert_eq!(borrowed.get(index), *value);
798        }
799
800        let bytes: Vec<&[u8]> = borrowed.as_bytes().map(|(_align, bytes)| bytes).collect();
801        let decoded = BorrowedOf::<Overflowing<i128>>::from_bytes(&mut bytes.into_iter());
802        assert_eq!(decoded.len(), values.len());
803        for (index, value) in values.iter().enumerate() {
804            assert_eq!(decoded.get(index), *value);
805        }
806
807        // NOTE: columnar's `i128` store does not implement `element_sizes`, so the indexed
808        // store can be decoded but not `validate`d for this type.
809        let mut words = Vec::new();
810        ::columnar::bytes::indexed::encode(&mut words, &borrowed);
811        let store = ::columnar::bytes::indexed::DecodedStore::new(&words);
812        let decoded = BorrowedOf::<Overflowing<i128>>::from_store(&store, &mut 0);
813        assert_eq!(decoded.len(), values.len());
814        for (index, value) in values.iter().enumerate() {
815            assert_eq!(decoded.get(index), *value);
816        }
817    }
818}