use core::num::Saturating;
use crate::{
common::{
Inner, SaturatingFrom, generate_from_primitive_to_wrapper,
generate_from_wrapper_to_primitive, generate_from_wrapper_to_wrapper,
generate_saturating_from_float_to_wrapper,
generate_saturating_from_signed_primitive_to_unsigned_wrapper,
generate_saturating_from_unsigned_primitive_to_unsigned_wrapper,
generate_saturating_from_unsigned_wrapper_to_signed_primitive,
generate_saturating_from_wrapper_to_primitive, generate_saturating_from_wrapper_to_wrapper,
generate_saturating_wrapper,
},
si::{Si8, Si16, Si32, Si64, Si128},
};
generate_saturating_wrapper!(Su8; su8; u8);
generate_saturating_wrapper!(Su16; su16; u16);
generate_saturating_wrapper!(Su32; su32; u32);
generate_saturating_wrapper!(Su64; su64; u64);
generate_saturating_wrapper!(Su128; su128; u128);
macro_rules! generate_unsigned_functions {
($($name:ident; $inner:ty; $signed_name:ident; $signed_inner:ty)+) => {
$(
impl $name {
#[doc = concat!(
"Computes the absolute difference between `self` and `rhs`.\n\n",
"# Examples\n\n",
"```rust\n",
"use satint::", stringify!($name), ";\n\n",
"assert_eq!(", stringify!($name), "::new(10).abs_diff(", stringify!($name), "::new(25)), ", stringify!($name), "::new(15));\n",
"```"
)]
#[inline]
#[must_use]
pub const fn abs_diff(self, rhs: Self) -> Self {
Self::new(self.into_inner().abs_diff(rhs.into_inner()))
}
#[doc = concat!(
"Returns `true` if `self` is a power of two.\n\n",
"# Examples\n\n",
"```rust\n",
"use satint::", stringify!($name), ";\n\n",
"assert!(", stringify!($name), "::new(16).is_power_of_two());\n",
"assert!(!", stringify!($name), "::new(10).is_power_of_two());\n",
"```"
)]
#[inline]
#[must_use]
pub const fn is_power_of_two(self) -> bool {
self.into_inner().is_power_of_two()
}
#[doc = concat!(
"Returns the smallest power of two greater than or equal to `self`, ",
"saturating at [`", stringify!($name), "::MAX`] if the primitive operation would overflow.\n\n",
"# Examples\n\n",
"```rust\n",
"use satint::", stringify!($name), ";\n\n",
"assert_eq!(", stringify!($name), "::new(15).next_power_of_two(), ", stringify!($name), "::new(16));\n",
"assert_eq!(", stringify!($name), "::MAX.next_power_of_two(), ", stringify!($name), "::MAX);\n",
"```"
)]
#[inline]
#[must_use]
pub const fn next_power_of_two(self) -> Self {
match self.checked_next_power_of_two() {
Some(v) => v,
None => Self::MAX,
}
}
#[doc = concat!(
"Returns the smallest power of two greater than or equal to `self`, ",
"or `None` if the primitive operation would overflow.\n\n",
"# Examples\n\n",
"```rust\n",
"use satint::", stringify!($name), ";\n\n",
"assert_eq!(", stringify!($name), "::new(15).checked_next_power_of_two(), Some(", stringify!($name), "::new(16)));\n",
"assert_eq!(", stringify!($name), "::MAX.checked_next_power_of_two(), None);\n",
"```"
)]
#[inline]
#[must_use]
pub const fn checked_next_power_of_two(self) -> Option<Self> {
match self.into_inner().checked_next_power_of_two() {
Some(v) => Some(Self::new(v)),
None => None,
}
}
#[doc = concat!(
"Returns the integer square root.\n\n",
"# Examples\n\n",
"```rust\n",
"use satint::", stringify!($name), ";\n\n",
"assert_eq!(", stringify!($name), "::new(16).isqrt(), ", stringify!($name), "::new(4));\n",
"assert_eq!(", stringify!($name), "::new(15).isqrt(), ", stringify!($name), "::new(3));\n",
"```"
)]
#[inline]
#[must_use]
pub const fn isqrt(self) -> Self {
Self::new(self.into_inner().isqrt())
}
#[doc = concat!(
"Converts to the same-width signed wrapper, saturating values above the signed range to [`", stringify!($signed_name), "::MAX`].\n\n",
"# Examples\n\n",
"```rust\n",
"use satint::{", stringify!($name), ", ", stringify!($signed_name), "};\n\n",
"assert_eq!(", stringify!($name), "::new(42).to_signed(), ", stringify!($signed_name), "::new(42));\n",
"assert_eq!(", stringify!($name), "::MAX.to_signed(), ", stringify!($signed_name), "::MAX);\n",
"```"
)]
#[inline]
#[must_use]
pub const fn to_signed(self) -> $signed_name {
let value = self.0.0;
let cap = <$signed_inner>::MAX as $inner;
if value > cap {
$signed_name::MAX
} else {
$signed_name::new(value as $signed_inner)
}
}
}
generate_saturating_from_unsigned_primitive_to_unsigned_wrapper!($name; u8, u16, u32, u64, u128, usize);
generate_saturating_from_signed_primitive_to_unsigned_wrapper!($name; i8, i16, i32, i64, i128, isize);
generate_saturating_from_wrapper_to_primitive!($name; u128; u8, u16, u32, u64, usize);
generate_saturating_from_unsigned_wrapper_to_signed_primitive!($name; i8, i16, i32, i64, i128, isize);
generate_saturating_from_float_to_wrapper!($name; f32, f64);
)+
};
}
generate_unsigned_functions!(Su8; u8; Si8; i8);
generate_unsigned_functions!(Su16; u16; Si16; i16);
generate_unsigned_functions!(Su32; u32; Si32; i32);
generate_unsigned_functions!(Su64; u64; Si64; i64);
generate_unsigned_functions!(Su128; u128; Si128; i128);
generate_from_primitive_to_wrapper!(Su16; u8);
generate_from_primitive_to_wrapper!(Su32; u8, u16);
generate_from_primitive_to_wrapper!(Su64; u8, u16, u32);
generate_from_primitive_to_wrapper!(Su128; u8, u16, u32, u64);
generate_from_wrapper_to_primitive!(Su8; u16, u32, u64, u128, usize, isize, f32, f64);
generate_from_wrapper_to_primitive!(Su16; u32, u64, u128, usize, f32, f64);
generate_from_wrapper_to_primitive!(Su32; u64, u128, f64);
generate_from_wrapper_to_primitive!(Su64; u128);
generate_from_wrapper_to_wrapper!(Su16; Su8);
generate_from_wrapper_to_wrapper!(Su32; Su8, Su16);
generate_from_wrapper_to_wrapper!(Su64; Su8, Su16, Su32);
generate_from_wrapper_to_wrapper!(Su128; Su8, Su16, Su32, Su64);
generate_saturating_from_wrapper_to_wrapper!(Su8; u128; Su16, Su32, Su64, Su128);
generate_saturating_from_wrapper_to_wrapper!(Su16; u128; Su8, Su32, Su64, Su128);
generate_saturating_from_wrapper_to_wrapper!(Su32; u128; Su8, Su16, Su64, Su128);
generate_saturating_from_wrapper_to_wrapper!(Su64; u128; Su8, Su16, Su32, Su128);
generate_saturating_from_wrapper_to_wrapper!(Su128; u128; Su8, Su16, Su32, Su64);
#[cfg(test)]
mod tests {
use crate::{
common::{Inner, SaturatingFrom},
si::{Si8, Si16, Si32, Si64, Si128},
su::{Su8, Su16, Su32, Su64, Su128},
};
macro_rules! test_unsigned_suite {
($($mod_name:ident; $name:ident; $signed:ident)+) => {
$(
mod $mod_name {
use super::*;
type T = <$name as Inner>::Inner;
#[test]
fn test_basics() {
assert_eq!($name::ZERO.into_inner(), 0);
assert_eq!($name::ONE.into_inner(), 1);
assert_eq!($name::MIN.into_inner(), T::MIN);
assert_eq!($name::MAX.into_inner(), T::MAX);
}
#[test]
fn test_methods() {
let a = $name::new(10);
let b = $name::new(25);
assert_eq!(a.abs_diff(b), $name::new(15));
assert_eq!(b.abs_diff(a), $name::new(15));
assert!($name::new(16).is_power_of_two());
assert!(!$name::new(10).is_power_of_two());
assert_eq!($name::new(15).next_power_of_two(), $name::new(16));
assert_eq!($name::new(16).next_power_of_two(), $name::new(16));
assert_eq!($name::MAX.next_power_of_two(), $name::MAX);
assert_eq!($name::new(16).isqrt(), $name::new(4));
assert_eq!($name::new(15).isqrt(), $name::new(3));
}
#[test]
fn test_to_signed() {
type S = <$signed as Inner>::Inner;
assert_eq!($name::new(10).to_signed(), $signed::new(10));
assert_eq!($name::MAX.to_signed(), $signed::MAX);
let cap = S::MAX as T;
assert_eq!($name::new(cap).to_signed(), $signed::new(S::MAX));
if cap < T::MAX {
assert_eq!($name::new(cap + 1).to_signed(), $signed::MAX);
}
}
#[test]
fn test_saturating_conversions() {
assert_eq!($name::saturating_from(-1_i8), $name::ZERO);
assert_eq!($name::saturating_from(-128_i8), $name::ZERO);
}
}
)+
};
}
test_unsigned_suite!(
su8_tests; Su8; Si8
su16_tests; Su16; Si16
su32_tests; Su32; Si32
su64_tests; Su64; Si64
su128_tests; Su128; Si128
);
}