use std::{
fmt,
iter::Sum,
ops::{Add, AddAssign, Neg, Sub, SubAssign},
};
use crate::IntVal;
pub(crate) type DoubleIntVal = i128;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct OverflowImpossible;
pub trait OverflowMode: private::Sealed + Clone + fmt::Debug + 'static {
const HANDLE_OVERFLOW: bool;
type Accumulator: Add<Output = Self::Accumulator>
+ AddAssign
+ Copy
+ Clone
+ fmt::Debug
+ fmt::Display
+ From<IntVal>
+ Into<DoubleIntVal>
+ Neg<Output = Self::Accumulator>
+ Ord
+ Sub<Output = Self::Accumulator>
+ SubAssign
+ Sum
+ TryInto<IntVal>;
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct OverflowPossible;
impl OverflowMode for OverflowImpossible {
const HANDLE_OVERFLOW: bool = false;
type Accumulator = IntVal;
}
impl private::Sealed for OverflowImpossible {}
impl OverflowMode for OverflowPossible {
const HANDLE_OVERFLOW: bool = true;
type Accumulator = DoubleIntVal;
}
impl private::Sealed for OverflowPossible {}
mod private {
pub trait Sealed {}
}
#[cfg(test)]
mod tests {
use crate::{
IntVal,
helpers::overflow::{DoubleIntVal, OverflowImpossible, OverflowMode, OverflowPossible},
};
#[test]
fn double_intval_size() {
assert_eq!(size_of::<DoubleIntVal>(), size_of::<IntVal>() * 2);
}
#[test]
fn test_overflow_impossible() {
const { assert!(!OverflowImpossible::HANDLE_OVERFLOW) };
assert!(
<OverflowImpossible as OverflowMode>::Accumulator::from(IntVal::MAX)
.checked_add(1)
.is_none()
);
}
#[test]
fn test_overflow_possible() {
const { assert!(OverflowPossible::HANDLE_OVERFLOW) };
assert!(
<OverflowPossible as OverflowMode>::Accumulator::from(IntVal::MAX)
.checked_add(1)
.is_some()
);
}
}