cadd 0.1.1

Painless checked arithmetics and conversions
Documentation
#[cfg(feature = "std")]
use std::time::{Instant, SystemTime};
use {
    alloc::format,
    core::{num::NonZero, time::Duration},
};

macro_rules! impl_binary_op {
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, msg=$msg:literal for $t1:ty, $t2:ty, $out:ty) => {
        impl $crate::ops::$trait_<$t2> for $t1 {
            type Output = $out;
            type Error = $crate::Error;
            #[inline]
            fn $trait_fn(self, b: $t2) -> $crate::Result<$out> {
                self.$source_fn(b)
                    .ok_or_else(|| crate::Error::new(format!($msg, self, b)))
            }
        }
    };
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, err=$err:expr, for $t1:ty, $t2:ty, $out:ty) => {
        impl $crate::ops::$trait_<$t2> for $t1 {
            type Output = $out;
            type Error = $crate::Error;
            #[inline]
            fn $trait_fn(self, b: $t2) -> $crate::Result<$out> {
                self.$source_fn(b)
                    .ok_or_else(|| crate::Error::new(($err)(self, b)))
            }
        }
    };
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, msg=$msg:literal for $t1:ty) => {
        impl_binary_op!($trait_, $trait_fn, $source_fn, msg=$msg for $t1, $t1, $t1);
    };
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, err=$err:expr, for $t1:ty) => {
        impl_binary_op!($trait_, $trait_fn, $source_fn, err=$err, for $t1, $t1, $t1);
    };
}

macro_rules! impl_binary_ops {
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, msg=$msg:literal for $(($($t1:tt)*),)+) => {
        $(
            impl_binary_op!($trait_, $trait_fn, $source_fn, msg=$msg for $($t1)*);
        )*
    };
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, err=$err:expr, for $(($($t1:tt)*),)+) => {
        $(
            impl_binary_op!($trait_, $trait_fn, $source_fn, err=$err, for $($t1)*);
        )*
    };
}

macro_rules! impl_unary_op {
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, msg=$msg:literal for $t1:ty, $out:ty) => {
        impl $crate::ops::$trait_ for $t1 {
            type Output = $out;
            type Error = $crate::Error;
            #[inline]
            fn $trait_fn(self) -> $crate::Result<$out> {
                self.$source_fn()
                    .ok_or_else(|| crate::Error::new(format!($msg, self)))
            }
        }
    };
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, err=$err:expr, for $t1:ty, $out:ty) => {
        impl $crate::ops::$trait_ for $t1 {
            type Output = $out;
            type Error = $crate::Error;
            #[inline]
            fn $trait_fn(self) -> $crate::Result<$out> {
                self.$source_fn()
                    .ok_or_else(|| crate::Error::new(($err)(self)))
            }
        }
    };
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, msg=$msg:literal for $t1:ty) => {
        impl_unary_op!($trait_, $trait_fn, $source_fn, msg=$msg for $t1, $t1);
    };
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, err=$err:expr, for $t1:ty) => {
        impl_unary_op!($trait_, $trait_fn, $source_fn, err=$err, for $t1, $t1);
    };
}

macro_rules! impl_unary_ops {
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, msg=$msg:literal for $(($($t1:tt)*),)+) => {
        $(
            impl_unary_op!($trait_, $trait_fn, $source_fn, msg=$msg for $($t1)*);
        )*
    };
    ($trait_:ident, $trait_fn:ident, $source_fn:ident, err=$err:expr, for $(($($t1:tt)*),)+) => {
        $(
            impl_unary_op!($trait_, $trait_fn, $source_fn, err=$err, for $($t1)*);
        )*
    };
}

impl_binary_ops!(
    Cadd, cadd, checked_add, msg="overflow: {:?} + {:?}"
    for (u8), (i8), (u16), (i16), (u32), (i32), (u64), (i64), (u128), (i128), (usize), (isize),
    (Duration),
    (NonZero<u8>, u8, NonZero<u8>),
    (NonZero<u16>, u16, NonZero<u16>),
    (NonZero<u32>, u32, NonZero<u32>),
    (NonZero<u64>, u64, NonZero<u64>),
    (NonZero<u128>, u128, NonZero<u128>),
    (NonZero<usize>, usize, NonZero<usize>),
);
#[cfg(feature = "std")]
impl_binary_ops!(
    Cadd, cadd, checked_add, msg="overflow: {:?} + {:?}"
    for
    (Instant, Duration, Instant),
    (SystemTime, Duration, SystemTime),
);

impl_binary_ops!(
    Cadd, cadd, checked_add_signed, msg="overflow: {} + {}"
    for
    (u8, i8, u8),
    (u16, i16, u16),
    (u32, i32, u32),
    (u64, i64, u64),
    (u128, i128, u128),
    (usize, isize, usize),
);

impl_binary_ops!(
    Cadd, cadd, checked_add_unsigned, msg="overflow: {} + {}"
    for
    (i8, u8, i8),
    (i16, u16, i16),
    (i32, u32, i32),
    (i64, u64, i64),
    (i128, u128, i128),
    (isize, usize, isize),
);

impl_binary_ops!(
    Csub, csub, checked_sub, msg="overflow: {:?} - {:?}"
    for (u8), (i8), (u16), (i16), (u32), (i32), (u64), (i64), (u128), (i128), (usize), (isize),
    (Duration),
);
#[cfg(feature = "std")]
impl_binary_ops!(
    Csub, csub, checked_sub, msg="overflow: {:?} - {:?}"
    for
    (Instant, Duration, Instant),
    (SystemTime, Duration, SystemTime),
);

impl_binary_ops!(
    Csub, csub, checked_sub_unsigned, msg="overflow: {} + {}"
    for
    (i8, u8, i8),
    (i16, u16, i16),
    (i32, u32, i32),
    (i64, u64, i64),
    (i128, u128, i128),
    (isize, usize, isize),
);

impl_binary_ops!(
    Cmul, cmul, checked_mul, msg="overflow: {:?} * {:?}"
    for (u8), (i8), (u16), (i16), (u32), (i32), (u64), (i64), (u128), (i128), (usize), (isize),
    (NonZero<u8>), (NonZero<u16>), (NonZero<u32>), (NonZero<u64>), (NonZero<u128>), (NonZero<usize>),
    (NonZero<i8>), (NonZero<i16>), (NonZero<i32>), (NonZero<i64>), (NonZero<i128>), (NonZero<isize>),
    (Duration, u32, Duration),
);

impl_unary_ops!(
    Cneg, cneg, checked_neg, msg="overflow: -{}"
    for (u8), (i8), (u16), (i16), (u32), (i32), (u64), (i64), (u128), (i128), (usize), (isize),
    (NonZero<i8>), (NonZero<i16>), (NonZero<i32>), (NonZero<i64>), (NonZero<i128>), (NonZero<isize>),
);

impl_binary_ops!(
    Cdiv, cdiv, checked_div, err=|a, b| {
        if b == 0 {
            format!("division by zero: {a:?} / {b:?}")
        } else {
            format!("overflow: {a:?} / {b:?}")
        }
    },
    for (u8), (i8), (u16), (i16), (u32), (i32), (u64), (i64), (u128), (i128), (usize), (isize),
    (Duration, u32, Duration),
);

impl_binary_ops!(
    CdivEuclid, cdiv_euclid, checked_div_euclid, err=|a, b| {
        if b == 0 {
            format!("division by zero: div_euclid({a:?}, {b:?})")
        } else {
            format!("overflow: div_euclid({a:?}, {b:?})")
        }
    },
    for (u8), (i8), (u16), (i16), (u32), (i32), (u64), (i64), (u128), (i128), (usize), (isize),
);

impl_binary_ops!(
    Crem, crem, checked_rem, err=|a, b| {
        if b == 0 {
            format!("division by zero: {a:?} % {b:?}")
        } else {
            format!("overflow: {a:?} % {b:?}")
        }
    },
    for (u8), (i8), (u16), (i16), (u32), (i32), (u64), (i64), (u128), (i128), (usize), (isize),
);

impl_binary_ops!(
    CremEuclid, crem_euclid, checked_rem_euclid, err=|a, b| {
        if b == 0 {
            format!("division by zero: rem_euclid({a:?}, {b:?})")
        } else {
            format!("overflow: rem_euclid({a:?}, {b:?})")
        }
    },
    for (u8), (i8), (u16), (i16), (u32), (i32), (u64), (i64), (u128), (i128), (usize), (isize),
);

impl_binary_ops!(
    CILog, cilog, checked_ilog, err=|a, b| {
        if b < 2 {
            format!("base is less than 2: ilog({a}, {b})")
        } else {
            format!("number is not positive: ilog({a}, {b})")
        }
    },
    for
    (u8, u8, u32),
    (u16, u16, u32),
    (u32, u32, u32),
    (u64, u64, u32),
    (u128, u128, u32),
    (usize, usize, u32),
    (i8, i8, u32),
    (i16, i16, u32),
    (i32, i32, u32),
    (i64, i64, u32),
    (i128, i128, u32),
    (isize, isize, u32),
);

impl_unary_ops!(
    CILog2, cilog2, checked_ilog2, msg="number is not positive: ilog2({})"
    for
    (u8, u32),
    (u16, u32),
    (u32, u32),
    (u64, u32),
    (u128, u32),
    (usize, u32),
    (i8, u32),
    (i16, u32),
    (i32, u32),
    (i64, u32),
    (i128, u32),
    (isize, u32),
);

impl_unary_ops!(
    CILog10, cilog10, checked_ilog10, msg="number is not positive: ilog10({})"
    for
    (u8, u32),
    (u16, u32),
    (u32, u32),
    (u64, u32),
    (u128, u32),
    (usize, u32),
    (i8, u32),
    (i16, u32),
    (i32, u32),
    (i64, u32),
    (i128, u32),
    (isize, u32),
);

impl_binary_ops!(
    Cshl, cshl, checked_shl, msg="shift amount is too large: {} << {}"
    for
    (u8, u32, u8),
    (u16, u32, u16),
    (u32, u32, u32),
    (u64, u32, u64),
    (u128, u32, u128),
    (usize, u32, usize),
    (i8, u32, i8),
    (i16, u32, i16),
    (i32, u32, i32),
    (i64, u32, i64),
    (i128, u32, i128),
    (isize, u32, isize),
);

impl_binary_ops!(
    Cshr, cshr, checked_shr, msg="shift amount is too large: {} >> {}"
    for
    (u8, u32, u8),
    (u16, u32, u16),
    (u32, u32, u32),
    (u64, u32, u64),
    (u128, u32, u128),
    (usize, u32, usize),
    (i8, u32, i8),
    (i16, u32, i16),
    (i32, u32, i32),
    (i64, u32, i64),
    (i128, u32, i128),
    (isize, u32, isize),
);

impl_binary_ops!(
    Cpow, cpow, checked_pow, msg="overflow: pow({}, {})"
    for
    (u8, u32, u8),
    (u16, u32, u16),
    (u32, u32, u32),
    (u64, u32, u64),
    (u128, u32, u128),
    (usize, u32, usize),
    (i8, u32, i8),
    (i16, u32, i16),
    (i32, u32, i32),
    (i64, u32, i64),
    (i128, u32, i128),
    (isize, u32, isize),
);

impl_unary_ops!(
    Cabs, cabs, checked_abs, msg="overflow: abs({})"
    for
    (i8), (i16), (i32), (i64), (i128), (isize),
    (NonZero<i8>), (NonZero<i16>), (NonZero<i32>), (NonZero<i64>), (NonZero<i128>), (NonZero<isize>),
);

impl_binary_ops!(
    CnextMultipleOf, cnext_multiple_of, checked_next_multiple_of, err=|a, b| {
        if b == 0 {
            format!("multiplier is zero: next_multiple_of({a}, {b})")
        } else {
            format!("overflow: next_multiple_of({a}, {b})")
        }
    },
    for (u8), (u16), (u32), (u64), (u128), (usize),
);

impl_unary_ops!(
    CnextPowerOfTwo, cnext_power_of_two, checked_next_power_of_two, msg="overflow: next_power_of_two({})"
    for (u8), (u16), (u32), (u64), (u128), (usize),
    (NonZero<u8>), (NonZero<u16>), (NonZero<u32>), (NonZero<u64>), (NonZero<u128>), (NonZero<usize>),
);