use core::{
mem::{self, ManuallyDrop},
time::Duration,
};
use crate::inherent::AsReprInherent;
#[doc(hidden)]
#[non_exhaustive]
#[derive(Debug)]
pub enum SaturatingAddSubType {
U8,
U16,
U32,
U64,
U128,
I8,
I16,
I32,
I64,
I128,
Duration,
}
pub unsafe trait SaturatingAdd: Copy {
const TYPE: SaturatingAddSubType;
type ToRepr;
}
unsafe impl<T> SaturatingAdd for T
where
T: AsReprInherent,
T::InherentRepr: SaturatingAdd,
{
type ToRepr = <T::InherentRepr as SaturatingAdd>::ToRepr;
const TYPE: SaturatingAddSubType = <T::InherentRepr as SaturatingAdd>::TYPE;
}
pub unsafe trait SaturatingSub: Copy {
const TYPE: SaturatingAddSubType;
type ToRepr;
}
unsafe impl<T> SaturatingSub for T
where
T: AsReprInherent,
T::InherentRepr: SaturatingSub,
{
type ToRepr = <T::InherentRepr as SaturatingSub>::ToRepr;
const TYPE: SaturatingAddSubType = <T::InherentRepr as SaturatingSub>::TYPE;
}
macro_rules! saturating_add_sub {
($type:ty, $name:ident) => {
unsafe impl SaturatingAdd for $type {
type ToRepr = $type;
const TYPE: SaturatingAddSubType = SaturatingAddSubType::$name;
}
unsafe impl SaturatingSub for $type {
type ToRepr = $type;
const TYPE: SaturatingAddSubType = SaturatingAddSubType::$name;
}
};
}
saturating_add_sub!(i8, I8);
saturating_add_sub!(i16, I16);
saturating_add_sub!(i32, I32);
saturating_add_sub!(i64, I64);
saturating_add_sub!(i128, I128);
saturating_add_sub!(u8, U8);
saturating_add_sub!(u16, U16);
saturating_add_sub!(u32, U32);
saturating_add_sub!(u64, U64);
saturating_add_sub!(u128, U128);
saturating_add_sub!(Duration, Duration);
#[doc(hidden)]
#[non_exhaustive]
#[derive(Debug)]
pub enum SaturatingMulDivType {
U8,
U16,
U32,
U64,
U128,
I8,
I16,
I32,
I64,
I128,
}
pub unsafe trait SaturatingMul: Copy {
const TYPE: SaturatingMulDivType;
type ToRepr;
}
unsafe impl<T> SaturatingMul for T
where
T: AsReprInherent,
T::InherentRepr: SaturatingMul,
{
type ToRepr = <T::InherentRepr as SaturatingMul>::ToRepr;
const TYPE: SaturatingMulDivType = <T::InherentRepr as SaturatingMul>::TYPE;
}
pub unsafe trait SaturatingDiv: Copy {
const TYPE: SaturatingMulDivType;
type ToRepr;
}
unsafe impl<T> SaturatingDiv for T
where
T: AsReprInherent,
T::InherentRepr: SaturatingDiv,
{
type ToRepr = <T::InherentRepr as SaturatingDiv>::ToRepr;
const TYPE: SaturatingMulDivType = <T::InherentRepr as SaturatingDiv>::TYPE;
}
macro_rules! saturating_mul_div {
($type:ty, $name:ident) => {
unsafe impl SaturatingMul for $type {
type ToRepr = $type;
const TYPE: SaturatingMulDivType = SaturatingMulDivType::$name;
}
unsafe impl SaturatingDiv for $type {
type ToRepr = $type;
const TYPE: SaturatingMulDivType = SaturatingMulDivType::$name;
}
};
}
saturating_mul_div!(i8, I8);
saturating_mul_div!(i16, I16);
saturating_mul_div!(i32, I32);
saturating_mul_div!(i64, I64);
saturating_mul_div!(i128, I128);
saturating_mul_div!(u8, U8);
saturating_mul_div!(u16, U16);
saturating_mul_div!(u32, U32);
saturating_mul_div!(u64, U64);
saturating_mul_div!(u128, U128);
macro_rules! saturating_ops {
($type:ty, $op:ident, $a:ident, $b:ident) => {{
let (a, b) = unsafe { (*$a.cast::<$type>(), *$b.cast::<$type>()) };
let value = ManuallyDrop::new(a.$op(b));
unsafe { mem::transmute_copy(&value) }
}};
}
pub const fn saturating_add<T>(a: T, b: T) -> T::ToRepr
where
T: SaturatingAdd,
{
use SaturatingAddSubType as Type;
let a: *const T = &a;
let b: *const T = &b;
match T::TYPE {
Type::U8 => saturating_ops!(u8, saturating_add, a, b),
Type::U16 => saturating_ops!(u16, saturating_add, a, b),
Type::U32 => saturating_ops!(u32, saturating_add, a, b),
Type::U64 => saturating_ops!(u64, saturating_add, a, b),
Type::U128 => saturating_ops!(u128, saturating_add, a, b),
Type::I8 => saturating_ops!(i8, saturating_add, a, b),
Type::I16 => saturating_ops!(i16, saturating_add, a, b),
Type::I32 => saturating_ops!(i32, saturating_add, a, b),
Type::I64 => saturating_ops!(i64, saturating_add, a, b),
Type::I128 => saturating_ops!(i128, saturating_add, a, b),
Type::Duration => saturating_ops!(Duration, saturating_add, a, b),
}
}
pub const fn saturating_sub<T>(a: T, b: T) -> T::ToRepr
where
T: SaturatingSub,
{
use SaturatingAddSubType as Type;
let a: *const T = &a;
let b: *const T = &b;
match T::TYPE {
Type::U8 => saturating_ops!(u8, saturating_sub, a, b),
Type::U16 => saturating_ops!(u16, saturating_sub, a, b),
Type::U32 => saturating_ops!(u32, saturating_sub, a, b),
Type::U64 => saturating_ops!(u64, saturating_sub, a, b),
Type::U128 => saturating_ops!(u128, saturating_sub, a, b),
Type::I8 => saturating_ops!(i8, saturating_sub, a, b),
Type::I16 => saturating_ops!(i16, saturating_sub, a, b),
Type::I32 => saturating_ops!(i32, saturating_sub, a, b),
Type::I64 => saturating_ops!(i64, saturating_sub, a, b),
Type::I128 => saturating_ops!(i128, saturating_sub, a, b),
Type::Duration => saturating_ops!(Duration, saturating_sub, a, b),
}
}
pub const fn saturating_mul<T>(a: T, b: T) -> T::ToRepr
where
T: SaturatingMul,
{
use SaturatingMulDivType as Type;
let a: *const T = &a;
let b: *const T = &b;
match T::TYPE {
Type::U8 => saturating_ops!(u8, saturating_mul, a, b),
Type::U16 => saturating_ops!(u16, saturating_mul, a, b),
Type::U32 => saturating_ops!(u32, saturating_mul, a, b),
Type::U64 => saturating_ops!(u64, saturating_mul, a, b),
Type::U128 => saturating_ops!(u128, saturating_mul, a, b),
Type::I8 => saturating_ops!(i8, saturating_mul, a, b),
Type::I16 => saturating_ops!(i16, saturating_mul, a, b),
Type::I32 => saturating_ops!(i32, saturating_mul, a, b),
Type::I64 => saturating_ops!(i64, saturating_mul, a, b),
Type::I128 => saturating_ops!(i128, saturating_mul, a, b),
}
}
pub const fn saturating_div<T>(a: T, b: T) -> T::ToRepr
where
T: SaturatingDiv,
{
use SaturatingMulDivType as Type;
let a: *const T = &a;
let b: *const T = &b;
match T::TYPE {
Type::U8 => saturating_ops!(u8, saturating_div, a, b),
Type::U16 => saturating_ops!(u16, saturating_div, a, b),
Type::U32 => saturating_ops!(u32, saturating_div, a, b),
Type::U64 => saturating_ops!(u64, saturating_div, a, b),
Type::U128 => saturating_ops!(u128, saturating_div, a, b),
Type::I8 => saturating_ops!(i8, saturating_div, a, b),
Type::I16 => saturating_ops!(i16, saturating_div, a, b),
Type::I32 => saturating_ops!(i32, saturating_div, a, b),
Type::I64 => saturating_ops!(i64, saturating_div, a, b),
Type::I128 => saturating_ops!(i128, saturating_div, a, b),
}
}