diff --git a/CHANGELOG.txt b/CHANGELOG similarity index 73% rename from CHANGELOG.txt rename to CHANGELOG index 7b317ba..313bc00 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG @@ -1,4 +1,10 @@ +# 0.1.4 + +Split items in `extend` module into their own modules inside `extend`. +Added `Signed::abs_unsigned` method. +Improved `sign` module's tests. + # 0.1.3 Added insight on implementations on references for most traits. diff --git a/Cargo.toml b/Cargo.toml index 091c7e7..5c7084a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ description = "Explicit integer conversions" readme = "README.md" license = "MIT" license_file = "LICENSE" -version = "0.1.3" +version = "0.1.4" authors = ["Filipe Rodrigues "] edition = "2018" repository = "https://github.com/Zenithsiz/int-conv" diff --git a/src/extend.rs b/src/extend.rs index a657d35..832a815 100644 --- a/src/extend.rs +++ b/src/extend.rs @@ -3,446 +3,12 @@ //! This module contains several traits that dictate behavior for extending //! an integer past it's range. -// Imports -use crate::Signed; -use core::mem; +// Modules +pub mod default; +pub mod sign; +pub mod zero; -/// Zero extend -/// -/// This trait serves to extend integers with `0`s, -/// including signed ones. -pub trait ZeroExtend: Sized { - /// Zero extends this type - fn zero_extend(self) -> T; -} - -/// Sign extends -/// -/// This trait serves to extend integers with their -/// sign signal. -pub trait SignExtend: Sized { - /// Sign extends this type - fn sign_extend(self) -> T; -} - -/// Generic extension -/// -/// This type performs either a zero extend or -/// a sign extend, depending if the type is signed. -pub trait Extend: Sized { - /// Extends this type - fn extend(self) -> T; -} - -/// Zero extending to the same type simply returns it -impl ZeroExtend for T { - #[inline] - fn zero_extend(self) -> Self { - self - } -} - -/// Sign extending to the same type simply returns it -impl SignExtend for T { - #[inline] - fn sign_extend(self) -> Self { - self - } -} - -/// Extending to the same type simply returns it -impl Extend for T { - #[inline] - fn extend(self) -> Self { - self - } -} - -/// Macro to help implement [`ZeroExtend`] -/// -/// Note: Regardless if `GAT`s are available, a `impl ZeroExtend<&'b U> for &'a T` isn't -/// possible, as it would require memory available for `U` at `T`, which we don't -/// know from just receiving a reference to `T`. -macro_rules! impl_zero_extend { - ($T:ty => $( $U:ty ),+ $(,)?) => { - $( - // Make sure `U` is bigger or equal to `T` so we don't truncate the integer - // Note: It is guaranteed that signed and unsigned variants have the same size - ::static_assertions::const_assert!(mem::size_of::<$U>() >= mem::size_of::<$T>()); - - impl ZeroExtend<$U> for $T - { - #[inline] - #[allow(clippy::as_conversions)] - fn zero_extend(self) -> $U { - // Casting between signedness is a no-op. - // Casting from a smaller to larger unsigned integer will zero-extend. - self - as <$T as Signed>::Unsigned - as <$U as Signed>::Unsigned - as $U - } - } - - // TODO: Replace with generic version once specialization is stable - impl<'a> ZeroExtend<$U> for &'a $T - where - $T: ZeroExtend<$U> - { - #[inline] - fn zero_extend(self) -> $U { - <$T as ZeroExtend<$U>>::zero_extend(*self) - } - } - )+ - }; -} - -// Unsigned -impl_zero_extend! { u8 => u16, u32, u64, u128 } -impl_zero_extend! { u16 => u32, u64, u128 } -impl_zero_extend! { u32 => u64, u128 } -impl_zero_extend! { u64 => u128 } - -// Signed -impl_zero_extend! { i8 => i16, i32, i64, i128 } -impl_zero_extend! { i16 => i32, i64, i128 } -impl_zero_extend! { i32 => i64, i128 } -impl_zero_extend! { i64 => i128 } - -/// Macro to help implement [`SignExtend`] -/// -/// Note: Regardless if `GAT`s are available, a `impl SignExtend<&'b U> for &'a T` isn't -/// possible, as it would require memory available for `U` at `T`, which we don't -/// know from just receiving a reference to `T`. -macro_rules! impl_sign_extend { - ($T:ty => $( $U:ty ),+ $(,)?) => { - $( - // Make sure `U` is bigger or equal to `T` so we don't truncate the integer - // Note: It is guaranteed that signed and unsigned variants have the same size - ::static_assertions::const_assert!(mem::size_of::<$U>() >= mem::size_of::<$T>()); - - impl SignExtend<$U> for $T - { - #[inline] - #[allow(clippy::as_conversions)] - fn sign_extend(self) -> $U { - // Casting between signedness is a no-op. - // Casting from a smaller to larger signed integer will sign-extend. - self - as <$T as Signed>::Signed - as <$U as Signed>::Signed - as $U - } - } - - // TODO: Replace with generic version once specialization is stable - impl<'a> SignExtend<$U> for &'a $T - where - $T: SignExtend<$U> - { - #[inline] - fn sign_extend(self) -> $U { - <$T as SignExtend<$U>>::sign_extend(*self) - } - } - )+ - }; -} - -// Signed -impl_sign_extend! { i8 => i16, i32, i64, i128 } -impl_sign_extend! { i16 => i32, i64, i128 } -impl_sign_extend! { i32 => i64, i128 } -impl_sign_extend! { i64 => i128 } - -/// Macro to help implement [`Extend`] -/// -/// Note: Regardless if `GAT`s are available, a `impl Extend<&'b U> for &'a T` isn't -/// possible, as it would require memory available for `U` at `T`, which we don't -/// know from just receiving a reference to `T`. -macro_rules! impl_extend { - ($T:ty => $( $U:ty ),+ $(,)? => $method:ident) => { - $( - impl Extend<$U> for $T - { - #[inline] - fn extend(self) -> $U { - self.$method() - } - } - - // TODO: Replace with generic version once specialization is stable - impl<'a> Extend<$U> for &'a $T - where - $T: Extend<$U> - { - #[inline] - fn extend(self) -> $U { - <$T as Extend<$U>>::extend(*self) - } - } - )+ - }; -} - -// Unsigned -impl_extend! { u8 => u16, u32, u64, u128 => zero_extend } -impl_extend! { u16 => u32, u64, u128 => zero_extend } -impl_extend! { u32 => u64, u128 => zero_extend } -impl_extend! { u64 => u128 => zero_extend } - -// Signed -impl_extend! { i8 => i16, i32, i64, i128 => sign_extend } -impl_extend! { i16 => i32, i64, i128 => sign_extend } -impl_extend! { i32 => i64, i128 => sign_extend } -impl_extend! { i64 => i128 => sign_extend } - -/// Helper trait for [`ZeroExtend`] to be used with turbofish syntax -pub trait ZeroExtended: Sized { - /// Zero extends this type - #[inline] - fn zero_extended(self) -> T - where - Self: ZeroExtend, - { - self.zero_extend() - } -} -impl ZeroExtended for T {} - -/// Helper trait for [`SignExtend`] to be used with turbofish syntax -pub trait SignExtended { - /// Sign extends this type - #[inline] - fn sign_extended(self) -> T - where - Self: SignExtend, - { - self.sign_extend() - } -} -impl SignExtended for T {} - -/// Helper trait for [`Extend`] to be used with turbofish syntax -pub trait Extended { - /// Extends this type - #[inline] - fn extended(self) -> T - where - Self: Extend, - { - self.extend() - } -} -impl Extended for T {} - -// Check that all `ZeroExtend` / `SignExtend` / `Extend` impls exist -static_assertions::assert_impl_all! { i8 : ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend } -static_assertions::assert_impl_all! { i16 : ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend } -static_assertions::assert_impl_all! { i32 : ZeroExtend, ZeroExtend, ZeroExtend } -static_assertions::assert_impl_all! { i64 : ZeroExtend, ZeroExtend } -static_assertions::assert_impl_all! { i128 : ZeroExtend } -static_assertions::assert_impl_all! { u8 : ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend } -static_assertions::assert_impl_all! { u16 : ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend } -static_assertions::assert_impl_all! { u32 : ZeroExtend, ZeroExtend, ZeroExtend } -static_assertions::assert_impl_all! { u64 : ZeroExtend, ZeroExtend } -static_assertions::assert_impl_all! { u128 : ZeroExtend } -static_assertions::assert_impl_all! { i8 : SignExtend, SignExtend, SignExtend, SignExtend, SignExtend } -static_assertions::assert_impl_all! { i16 : SignExtend, SignExtend, SignExtend, SignExtend } -static_assertions::assert_impl_all! { i32 : SignExtend, SignExtend, SignExtend } -static_assertions::assert_impl_all! { i64 : SignExtend, SignExtend } -static_assertions::assert_impl_all! { i128 : SignExtend } -static_assertions::assert_impl_all! { i8 : Extend, Extend, Extend, Extend, Extend } -static_assertions::assert_impl_all! { i16 : Extend, Extend, Extend, Extend } -static_assertions::assert_impl_all! { i32 : Extend, Extend, Extend } -static_assertions::assert_impl_all! { i64 : Extend, Extend } -static_assertions::assert_impl_all! { i128 : Extend } -static_assertions::assert_impl_all! { u8 : Extend, Extend, Extend, Extend, Extend } -static_assertions::assert_impl_all! { u16 : Extend, Extend, Extend, Extend } -static_assertions::assert_impl_all! { u32 : Extend, Extend, Extend } -static_assertions::assert_impl_all! { u64 : Extend, Extend } -static_assertions::assert_impl_all! { u128 : Extend } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[rustfmt::skip] - fn zero_extend_unsigned() { - assert_eq!( u8::zero_extended::< u8>(1), 1); - assert_eq!( u8::zero_extended::< u16>(1), 1); - assert_eq!( u8::zero_extended::< u32>(1), 1); - assert_eq!( u8::zero_extended::< u64>(1), 1); - assert_eq!( u8::zero_extended::(1), 1); - assert_eq!( u16::zero_extended::< u16>(1), 1); - assert_eq!( u16::zero_extended::< u32>(1), 1); - assert_eq!( u16::zero_extended::< u64>(1), 1); - assert_eq!( u16::zero_extended::(1), 1); - assert_eq!( u32::zero_extended::< u32>(1), 1); - assert_eq!( u32::zero_extended::< u64>(1), 1); - assert_eq!( u32::zero_extended::(1), 1); - assert_eq!( u64::zero_extended::< u64>(1), 1); - assert_eq!( u64::zero_extended::(1), 1); - assert_eq!(u128::zero_extended::(1), 1); - } - - #[test] - #[rustfmt::skip] - fn zero_extend_unsigned_big() { - - assert_eq!( u8::zero_extended::< u16>( u8::MAX), u16::from( u8::MAX)); - assert_eq!( u8::zero_extended::< u32>( u8::MAX), u32::from( u8::MAX)); - assert_eq!( u8::zero_extended::< u64>( u8::MAX), u64::from( u8::MAX)); - assert_eq!( u8::zero_extended::( u8::MAX), u128::from( u8::MAX)); - assert_eq!(u16::zero_extended::< u32>(u16::MAX), u32::from(u16::MAX)); - assert_eq!(u16::zero_extended::< u64>(u16::MAX), u64::from(u16::MAX)); - assert_eq!(u16::zero_extended::(u16::MAX), u128::from(u16::MAX)); - assert_eq!(u32::zero_extended::< u64>(u32::MAX), u64::from(u32::MAX)); - assert_eq!(u32::zero_extended::(u32::MAX), u128::from(u32::MAX)); - assert_eq!(u64::zero_extended::(u64::MAX), u128::from(u64::MAX)); - - assert_eq!( u8::zero_extended::< u8>( u8::MAX), u8::MAX); - assert_eq!( u16::zero_extended::< u16>( u16::MAX), u16::MAX); - assert_eq!( u32::zero_extended::< u32>( u32::MAX), u32::MAX); - assert_eq!( u64::zero_extended::< u64>( u64::MAX), u64::MAX); - assert_eq!(u128::zero_extended::(u128::MAX), u128::MAX); - } - - #[test] - #[rustfmt::skip] - fn zero_extend_signed_positive() { - assert_eq!( i8::zero_extended::< i8>(1), 1); - assert_eq!( i8::zero_extended::< i16>(1), 1); - assert_eq!( i8::zero_extended::< i32>(1), 1); - assert_eq!( i8::zero_extended::< i64>(1), 1); - assert_eq!( i8::zero_extended::(1), 1); - assert_eq!( i16::zero_extended::< i16>(1), 1); - assert_eq!( i16::zero_extended::< i32>(1), 1); - assert_eq!( i16::zero_extended::< i64>(1), 1); - assert_eq!( i16::zero_extended::(1), 1); - assert_eq!( i32::zero_extended::< i32>(1), 1); - assert_eq!( i32::zero_extended::< i64>(1), 1); - assert_eq!( i32::zero_extended::(1), 1); - assert_eq!( i64::zero_extended::< i64>(1), 1); - assert_eq!( i64::zero_extended::(1), 1); - assert_eq!(i128::zero_extended::(1), 1); - } - - #[test] - #[rustfmt::skip] - fn zero_extend_signed_negative() { - assert_eq!( i8::zero_extended::< i16>(-1), i16::from(u8 ::MAX)); - assert_eq!( i8::zero_extended::< i32>(-1), i32::from(u8 ::MAX)); - assert_eq!( i8::zero_extended::< i64>(-1), i64::from(u8 ::MAX)); - assert_eq!( i8::zero_extended::(-1), i128::from(u8 ::MAX)); - assert_eq!(i16::zero_extended::< i32>(-1), i32::from(u16 ::MAX)); - assert_eq!(i16::zero_extended::< i64>(-1), i64::from(u16 ::MAX)); - assert_eq!(i16::zero_extended::(-1), i128::from(u16 ::MAX)); - assert_eq!(i32::zero_extended::< i64>(-1), i64::from(u32 ::MAX)); - assert_eq!(i32::zero_extended::(-1), i128::from(u32 ::MAX)); - assert_eq!(i64::zero_extended::(-1), i128::from(u64 ::MAX)); - - assert_eq!( i8::zero_extended::< i8>(-1), -1); - assert_eq!( i16::zero_extended::< i16>(-1), -1); - assert_eq!( i32::zero_extended::< i32>(-1), -1); - assert_eq!( i64::zero_extended::< i64>(-1), -1); - assert_eq!(i128::zero_extended::(-1), -1); - } - - #[test] - #[rustfmt::skip] - fn sign_extend_positive() { - assert_eq!(i8 ::sign_extended::< i16>(1), 1); - assert_eq!(i8 ::sign_extended::< i32>(1), 1); - assert_eq!(i8 ::sign_extended::< i64>(1), 1); - assert_eq!(i8 ::sign_extended::(1), 1); - assert_eq!(i16::sign_extended::< i32>(1), 1); - assert_eq!(i16::sign_extended::< i64>(1), 1); - assert_eq!(i16::sign_extended::(1), 1); - assert_eq!(i32::sign_extended::< i64>(1), 1); - assert_eq!(i32::sign_extended::(1), 1); - assert_eq!(i64::sign_extended::(1), 1); - } - - #[test] - #[rustfmt::skip] - fn sign_extend_negative() { - assert_eq!( i8::sign_extended::< i16>(-1), -1); - assert_eq!( i8::sign_extended::< i32>(-1), -1); - assert_eq!( i8::sign_extended::< i64>(-1), -1); - assert_eq!( i8::sign_extended::(-1), -1); - assert_eq!(i16::sign_extended::< i32>(-1), -1); - assert_eq!(i16::sign_extended::< i64>(-1), -1); - assert_eq!(i16::sign_extended::(-1), -1); - assert_eq!(i32::sign_extended::< i64>(-1), -1); - assert_eq!(i32::sign_extended::(-1), -1); - assert_eq!(i64::sign_extended::(-1), -1); - } - - #[test] - #[rustfmt::skip] - fn extend_unsigned() { - assert_eq!( u8::extended::< u16>(1), u8::zero_extended::< u16>(1)); - assert_eq!( u8::extended::< u32>(1), u8::zero_extended::< u32>(1)); - assert_eq!( u8::extended::< u64>(1), u8::zero_extended::< u64>(1)); - assert_eq!( u8::extended::(1), u8::zero_extended::(1)); - assert_eq!(u16::extended::< u32>(1), u16::zero_extended::< u32>(1)); - assert_eq!(u16::extended::< u64>(1), u16::zero_extended::< u64>(1)); - assert_eq!(u16::extended::(1), u16::zero_extended::(1)); - assert_eq!(u32::extended::< u64>(1), u32::zero_extended::< u64>(1)); - assert_eq!(u32::extended::(1), u32::zero_extended::(1)); - assert_eq!(u64::extended::(1), u64::zero_extended::(1)); - } - - #[test] - #[rustfmt::skip] - fn extend_unsigned_big() { - assert_eq!( u8::extended::< u8>( u8::MAX), u8::zero_extended::< u8>( u8::MAX)); - assert_eq!( u8::extended::< u16>( u8::MAX), u8::zero_extended::< u16>( u8::MAX)); - assert_eq!( u8::extended::< u32>( u8::MAX), u8::zero_extended::< u32>( u8::MAX)); - assert_eq!( u8::extended::< u64>( u8::MAX), u8::zero_extended::< u64>( u8::MAX)); - assert_eq!( u8::extended::( u8::MAX), u8::zero_extended::( u8::MAX)); - assert_eq!( u16::extended::< u16>( u16::MAX), u16::zero_extended::< u16>( u16::MAX)); - assert_eq!( u16::extended::< u32>( u16::MAX), u16::zero_extended::< u32>( u16::MAX)); - assert_eq!( u16::extended::< u64>( u16::MAX), u16::zero_extended::< u64>( u16::MAX)); - assert_eq!( u16::extended::( u16::MAX), u16::zero_extended::( u16::MAX)); - assert_eq!( u32::extended::< u32>( u32::MAX), u32::zero_extended::< u32>( u32::MAX)); - assert_eq!( u32::extended::< u64>( u32::MAX), u32::zero_extended::< u64>( u32::MAX)); - assert_eq!( u32::extended::( u32::MAX), u32::zero_extended::( u32::MAX)); - assert_eq!( u64::extended::< u64>( u64::MAX), u64::zero_extended::< u64>( u64::MAX)); - assert_eq!( u64::extended::( u64::MAX), u64::zero_extended::( u64::MAX)); - assert_eq!(u128::extended::(u128::MAX), u128::zero_extended::(u128::MAX)); - } - - #[test] - #[rustfmt::skip] - fn extend_signed_positive() { - assert_eq!( i8::extended::< i16>(1), i8::sign_extended::< i16>(1)); - assert_eq!( i8::extended::< i32>(1), i8::sign_extended::< i32>(1)); - assert_eq!( i8::extended::< i64>(1), i8::sign_extended::< i64>(1)); - assert_eq!( i8::extended::(1), i8::sign_extended::(1)); - assert_eq!(i16::extended::< i32>(1), i16::sign_extended::< i32>(1)); - assert_eq!(i16::extended::< i64>(1), i16::sign_extended::< i64>(1)); - assert_eq!(i16::extended::(1), i16::sign_extended::(1)); - assert_eq!(i32::extended::< i64>(1), i32::sign_extended::< i64>(1)); - assert_eq!(i32::extended::(1), i32::sign_extended::(1)); - assert_eq!(i64::extended::(1), i64::sign_extended::(1)); - } - - #[test] - #[rustfmt::skip] - fn extend_signed_negative() { - assert_eq!( i8::extended::< i16>(-1), i8::sign_extended::< i16>(-1)); - assert_eq!( i8::extended::< i32>(-1), i8::sign_extended::< i32>(-1)); - assert_eq!( i8::extended::< i64>(-1), i8::sign_extended::< i64>(-1)); - assert_eq!( i8::extended::(-1), i8::sign_extended::(-1)); - assert_eq!(i16::extended::< i32>(-1), i16::sign_extended::< i32>(-1)); - assert_eq!(i16::extended::< i64>(-1), i16::sign_extended::< i64>(-1)); - assert_eq!(i16::extended::(-1), i16::sign_extended::(-1)); - assert_eq!(i32::extended::< i64>(-1), i32::sign_extended::< i64>(-1)); - assert_eq!(i32::extended::(-1), i32::sign_extended::(-1)); - assert_eq!(i64::extended::(-1), i64::sign_extended::(-1)); - } -} +// Exports +pub use default::{Extend, Extended}; +pub use sign::{SignExtend, SignExtended}; +pub use zero::{ZeroExtend, ZeroExtended}; diff --git a/src/extend/default.rs b/src/extend/default.rs new file mode 100644 index 0000000..8ba1fd0 --- /dev/null +++ b/src/extend/default.rs @@ -0,0 +1,160 @@ +//! Default extension + +// Imports +use crate::{SignExtend, ZeroExtend}; + +/// Generic extension +/// +/// This type performs either a zero extend or +/// a sign extend, depending if the type is signed. +pub trait Extend: Sized { + /// Extends this type + fn extend(self) -> T; +} + +/// Extending to the same type simply returns it +impl Extend for T { + #[inline] + fn extend(self) -> Self { + self + } +} + +/// Macro to help implement [`Extend`] +/// +/// Note: Regardless if `GAT`s are available, a `impl Extend<&'b U> for &'a T` isn't +/// possible, as it would require memory available for `U` at `T`, which we don't +/// know from just receiving a reference to `T`. +macro_rules! impl_extend { + ($T:ty => $( $U:ty ),+ $(,)? => $method:ident) => { + $( + impl Extend<$U> for $T + { + #[inline] + fn extend(self) -> $U { + self.$method() + } + } + + // TODO: Replace with generic version once specialization is stable + impl<'a> Extend<$U> for &'a $T + where + $T: Extend<$U> + { + #[inline] + fn extend(self) -> $U { + <$T as Extend<$U>>::extend(*self) + } + } + )+ + }; +} + +// Unsigned +impl_extend! { u8 => u16, u32, u64, u128 => zero_extend } +impl_extend! { u16 => u32, u64, u128 => zero_extend } +impl_extend! { u32 => u64, u128 => zero_extend } +impl_extend! { u64 => u128 => zero_extend } + +// Signed +impl_extend! { i8 => i16, i32, i64, i128 => sign_extend } +impl_extend! { i16 => i32, i64, i128 => sign_extend } +impl_extend! { i32 => i64, i128 => sign_extend } +impl_extend! { i64 => i128 => sign_extend } + +/// Helper trait for [`Extend`] to be used with turbofish syntax +pub trait Extended { + /// Extends this type + #[inline] + fn extended(self) -> T + where + Self: Extend, + { + self.extend() + } +} +impl Extended for T {} + +// Check that all `Extend` impls exist +static_assertions::assert_impl_all! { i8 : Extend, Extend, Extend, Extend, Extend } +static_assertions::assert_impl_all! { i16 : Extend, Extend, Extend, Extend } +static_assertions::assert_impl_all! { i32 : Extend, Extend, Extend } +static_assertions::assert_impl_all! { i64 : Extend, Extend } +static_assertions::assert_impl_all! { i128 : Extend } +static_assertions::assert_impl_all! { u8 : Extend, Extend, Extend, Extend, Extend } +static_assertions::assert_impl_all! { u16 : Extend, Extend, Extend, Extend } +static_assertions::assert_impl_all! { u32 : Extend, Extend, Extend } +static_assertions::assert_impl_all! { u64 : Extend, Extend } +static_assertions::assert_impl_all! { u128 : Extend } + +#[cfg(test)] +mod tests { + // Imports + use super::*; + use crate::{SignExtended, ZeroExtended}; + + #[test] + #[rustfmt::skip] + fn extend_unsigned() { + assert_eq!( u8::extended::< u16>(1), u8::zero_extended::< u16>(1)); + assert_eq!( u8::extended::< u32>(1), u8::zero_extended::< u32>(1)); + assert_eq!( u8::extended::< u64>(1), u8::zero_extended::< u64>(1)); + assert_eq!( u8::extended::(1), u8::zero_extended::(1)); + assert_eq!(u16::extended::< u32>(1), u16::zero_extended::< u32>(1)); + assert_eq!(u16::extended::< u64>(1), u16::zero_extended::< u64>(1)); + assert_eq!(u16::extended::(1), u16::zero_extended::(1)); + assert_eq!(u32::extended::< u64>(1), u32::zero_extended::< u64>(1)); + assert_eq!(u32::extended::(1), u32::zero_extended::(1)); + assert_eq!(u64::extended::(1), u64::zero_extended::(1)); + } + + #[test] + #[rustfmt::skip] + fn extend_unsigned_big() { + assert_eq!( u8::extended::< u8>( u8::MAX), u8::zero_extended::< u8>( u8::MAX)); + assert_eq!( u8::extended::< u16>( u8::MAX), u8::zero_extended::< u16>( u8::MAX)); + assert_eq!( u8::extended::< u32>( u8::MAX), u8::zero_extended::< u32>( u8::MAX)); + assert_eq!( u8::extended::< u64>( u8::MAX), u8::zero_extended::< u64>( u8::MAX)); + assert_eq!( u8::extended::( u8::MAX), u8::zero_extended::( u8::MAX)); + assert_eq!( u16::extended::< u16>( u16::MAX), u16::zero_extended::< u16>( u16::MAX)); + assert_eq!( u16::extended::< u32>( u16::MAX), u16::zero_extended::< u32>( u16::MAX)); + assert_eq!( u16::extended::< u64>( u16::MAX), u16::zero_extended::< u64>( u16::MAX)); + assert_eq!( u16::extended::( u16::MAX), u16::zero_extended::( u16::MAX)); + assert_eq!( u32::extended::< u32>( u32::MAX), u32::zero_extended::< u32>( u32::MAX)); + assert_eq!( u32::extended::< u64>( u32::MAX), u32::zero_extended::< u64>( u32::MAX)); + assert_eq!( u32::extended::( u32::MAX), u32::zero_extended::( u32::MAX)); + assert_eq!( u64::extended::< u64>( u64::MAX), u64::zero_extended::< u64>( u64::MAX)); + assert_eq!( u64::extended::( u64::MAX), u64::zero_extended::( u64::MAX)); + assert_eq!(u128::extended::(u128::MAX), u128::zero_extended::(u128::MAX)); + } + + #[test] + #[rustfmt::skip] + fn extend_signed_positive() { + assert_eq!( i8::extended::< i16>(1), i8::sign_extended::< i16>(1)); + assert_eq!( i8::extended::< i32>(1), i8::sign_extended::< i32>(1)); + assert_eq!( i8::extended::< i64>(1), i8::sign_extended::< i64>(1)); + assert_eq!( i8::extended::(1), i8::sign_extended::(1)); + assert_eq!(i16::extended::< i32>(1), i16::sign_extended::< i32>(1)); + assert_eq!(i16::extended::< i64>(1), i16::sign_extended::< i64>(1)); + assert_eq!(i16::extended::(1), i16::sign_extended::(1)); + assert_eq!(i32::extended::< i64>(1), i32::sign_extended::< i64>(1)); + assert_eq!(i32::extended::(1), i32::sign_extended::(1)); + assert_eq!(i64::extended::(1), i64::sign_extended::(1)); + } + + #[test] + #[rustfmt::skip] + fn extend_signed_negative() { + assert_eq!( i8::extended::< i16>(-1), i8::sign_extended::< i16>(-1)); + assert_eq!( i8::extended::< i32>(-1), i8::sign_extended::< i32>(-1)); + assert_eq!( i8::extended::< i64>(-1), i8::sign_extended::< i64>(-1)); + assert_eq!( i8::extended::(-1), i8::sign_extended::(-1)); + assert_eq!(i16::extended::< i32>(-1), i16::sign_extended::< i32>(-1)); + assert_eq!(i16::extended::< i64>(-1), i16::sign_extended::< i64>(-1)); + assert_eq!(i16::extended::(-1), i16::sign_extended::(-1)); + assert_eq!(i32::extended::< i64>(-1), i32::sign_extended::< i64>(-1)); + assert_eq!(i32::extended::(-1), i32::sign_extended::(-1)); + assert_eq!(i64::extended::(-1), i64::sign_extended::(-1)); + } +} diff --git a/src/extend/sign.rs b/src/extend/sign.rs new file mode 100644 index 0000000..4af306f --- /dev/null +++ b/src/extend/sign.rs @@ -0,0 +1,124 @@ +//! Sign extension + +// Imports +use crate::Signed; +use core::mem; + +/// Sign extends +/// +/// This trait serves to extend integers with their +/// sign signal. +pub trait SignExtend: Sized { + /// Sign extends this type + fn sign_extend(self) -> T; +} + +/// Sign extending to the same type simply returns it +impl SignExtend for T { + #[inline] + fn sign_extend(self) -> Self { + self + } +} + +/// Macro to help implement [`SignExtend`] +/// +/// Note: Regardless if `GAT`s are available, a `impl SignExtend<&'b U> for &'a T` isn't +/// possible, as it would require memory available for `U` at `T`, which we don't +/// know from just receiving a reference to `T`. +macro_rules! impl_sign_extend { + ($T:ty => $( $U:ty ),+ $(,)?) => { + $( + // Make sure `U` is bigger or equal to `T` so we don't truncate the integer + // Note: It is guaranteed that signed and unsigned variants have the same size + ::static_assertions::const_assert!(mem::size_of::<$U>() >= mem::size_of::<$T>()); + + impl SignExtend<$U> for $T + { + #[inline] + #[allow(clippy::as_conversions)] + fn sign_extend(self) -> $U { + // Casting between signedness is a no-op. + // Casting from a smaller to larger signed integer will sign-extend. + self + as <$T as Signed>::Signed + as <$U as Signed>::Signed + as $U + } + } + + // TODO: Replace with generic version once specialization is stable + impl<'a> SignExtend<$U> for &'a $T + where + $T: SignExtend<$U> + { + #[inline] + fn sign_extend(self) -> $U { + <$T as SignExtend<$U>>::sign_extend(*self) + } + } + )+ + }; +} + +// Signed +impl_sign_extend! { i8 => i16, i32, i64, i128 } +impl_sign_extend! { i16 => i32, i64, i128 } +impl_sign_extend! { i32 => i64, i128 } +impl_sign_extend! { i64 => i128 } + +/// Helper trait for [`SignExtend`] to be used with turbofish syntax +pub trait SignExtended { + /// Sign extends this type + #[inline] + fn sign_extended(self) -> T + where + Self: SignExtend, + { + self.sign_extend() + } +} +impl SignExtended for T {} + +// Check that all `SignExtend` / `Extend` impls exist +static_assertions::assert_impl_all! { i8 : SignExtend, SignExtend, SignExtend, SignExtend, SignExtend } +static_assertions::assert_impl_all! { i16 : SignExtend, SignExtend, SignExtend, SignExtend } +static_assertions::assert_impl_all! { i32 : SignExtend, SignExtend, SignExtend } +static_assertions::assert_impl_all! { i64 : SignExtend, SignExtend } +static_assertions::assert_impl_all! { i128 : SignExtend } + +#[cfg(test)] +mod tests { + // Imports + use super::*; + + #[test] + #[rustfmt::skip] + fn sign_extend_positive() { + assert_eq!(i8 ::sign_extended::< i16>(1), 1); + assert_eq!(i8 ::sign_extended::< i32>(1), 1); + assert_eq!(i8 ::sign_extended::< i64>(1), 1); + assert_eq!(i8 ::sign_extended::(1), 1); + assert_eq!(i16::sign_extended::< i32>(1), 1); + assert_eq!(i16::sign_extended::< i64>(1), 1); + assert_eq!(i16::sign_extended::(1), 1); + assert_eq!(i32::sign_extended::< i64>(1), 1); + assert_eq!(i32::sign_extended::(1), 1); + assert_eq!(i64::sign_extended::(1), 1); + } + + #[test] + #[rustfmt::skip] + fn sign_extend_negative() { + assert_eq!( i8::sign_extended::< i16>(-1), -1); + assert_eq!( i8::sign_extended::< i32>(-1), -1); + assert_eq!( i8::sign_extended::< i64>(-1), -1); + assert_eq!( i8::sign_extended::(-1), -1); + assert_eq!(i16::sign_extended::< i32>(-1), -1); + assert_eq!(i16::sign_extended::< i64>(-1), -1); + assert_eq!(i16::sign_extended::(-1), -1); + assert_eq!(i32::sign_extended::< i64>(-1), -1); + assert_eq!(i32::sign_extended::(-1), -1); + assert_eq!(i64::sign_extended::(-1), -1); + } +} diff --git a/src/extend/zero.rs b/src/extend/zero.rs new file mode 100644 index 0000000..51a5a25 --- /dev/null +++ b/src/extend/zero.rs @@ -0,0 +1,188 @@ +//! Zero extension + +// Imports +use crate::Signed; +use core::mem; + +/// Zero extend +/// +/// This trait serves to extend integers with `0`s, +/// including signed ones. +pub trait ZeroExtend: Sized { + /// Zero extends this type + fn zero_extend(self) -> T; +} + +/// Zero extending to the same type simply returns it +impl ZeroExtend for T { + #[inline] + fn zero_extend(self) -> Self { + self + } +} + +/// Macro to help implement [`ZeroExtend`] +/// +/// Note: Regardless if `GAT`s are available, a `impl ZeroExtend<&'b U> for &'a T` isn't +/// possible, as it would require memory available for `U` at `T`, which we don't +/// know from just receiving a reference to `T`. +macro_rules! impl_zero_extend { + ($T:ty => $( $U:ty ),+ $(,)?) => { + $( + // Make sure `U` is bigger or equal to `T` so we don't truncate the integer + // Note: It is guaranteed that signed and unsigned variants have the same size + ::static_assertions::const_assert!(mem::size_of::<$U>() >= mem::size_of::<$T>()); + + impl ZeroExtend<$U> for $T + { + #[inline] + #[allow(clippy::as_conversions)] + fn zero_extend(self) -> $U { + // Casting between signedness is a no-op. + // Casting from a smaller to larger unsigned integer will zero-extend. + self + as <$T as Signed>::Unsigned + as <$U as Signed>::Unsigned + as $U + } + } + + // TODO: Replace with generic version once specialization is stable + impl<'a> ZeroExtend<$U> for &'a $T + where + $T: ZeroExtend<$U> + { + #[inline] + fn zero_extend(self) -> $U { + <$T as ZeroExtend<$U>>::zero_extend(*self) + } + } + )+ + }; +} + +// Unsigned +impl_zero_extend! { u8 => u16, u32, u64, u128 } +impl_zero_extend! { u16 => u32, u64, u128 } +impl_zero_extend! { u32 => u64, u128 } +impl_zero_extend! { u64 => u128 } + +// Signed +impl_zero_extend! { i8 => i16, i32, i64, i128 } +impl_zero_extend! { i16 => i32, i64, i128 } +impl_zero_extend! { i32 => i64, i128 } +impl_zero_extend! { i64 => i128 } + +/// Helper trait for [`ZeroExtend`] to be used with turbofish syntax +pub trait ZeroExtended: Sized { + /// Zero extends this type + #[inline] + fn zero_extended(self) -> T + where + Self: ZeroExtend, + { + self.zero_extend() + } +} +impl ZeroExtended for T {} + +// Check that all `ZeroExtend` impls exist +static_assertions::assert_impl_all! { i8 : ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend } +static_assertions::assert_impl_all! { i16 : ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend } +static_assertions::assert_impl_all! { i32 : ZeroExtend, ZeroExtend, ZeroExtend } +static_assertions::assert_impl_all! { i64 : ZeroExtend, ZeroExtend } +static_assertions::assert_impl_all! { i128 : ZeroExtend } +static_assertions::assert_impl_all! { u8 : ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend } +static_assertions::assert_impl_all! { u16 : ZeroExtend, ZeroExtend, ZeroExtend, ZeroExtend } +static_assertions::assert_impl_all! { u32 : ZeroExtend, ZeroExtend, ZeroExtend } +static_assertions::assert_impl_all! { u64 : ZeroExtend, ZeroExtend } +static_assertions::assert_impl_all! { u128 : ZeroExtend } + +#[cfg(test)] +mod tests { + // Imports + use super::*; + + #[test] + #[rustfmt::skip] + fn zero_extend_unsigned() { + assert_eq!( u8::zero_extended::< u8>(1), 1); + assert_eq!( u8::zero_extended::< u16>(1), 1); + assert_eq!( u8::zero_extended::< u32>(1), 1); + assert_eq!( u8::zero_extended::< u64>(1), 1); + assert_eq!( u8::zero_extended::(1), 1); + assert_eq!( u16::zero_extended::< u16>(1), 1); + assert_eq!( u16::zero_extended::< u32>(1), 1); + assert_eq!( u16::zero_extended::< u64>(1), 1); + assert_eq!( u16::zero_extended::(1), 1); + assert_eq!( u32::zero_extended::< u32>(1), 1); + assert_eq!( u32::zero_extended::< u64>(1), 1); + assert_eq!( u32::zero_extended::(1), 1); + assert_eq!( u64::zero_extended::< u64>(1), 1); + assert_eq!( u64::zero_extended::(1), 1); + assert_eq!(u128::zero_extended::(1), 1); + } + + #[test] + #[rustfmt::skip] + fn zero_extend_unsigned_big() { + + assert_eq!( u8::zero_extended::< u16>( u8::MAX), u16::from( u8::MAX)); + assert_eq!( u8::zero_extended::< u32>( u8::MAX), u32::from( u8::MAX)); + assert_eq!( u8::zero_extended::< u64>( u8::MAX), u64::from( u8::MAX)); + assert_eq!( u8::zero_extended::( u8::MAX), u128::from( u8::MAX)); + assert_eq!(u16::zero_extended::< u32>(u16::MAX), u32::from(u16::MAX)); + assert_eq!(u16::zero_extended::< u64>(u16::MAX), u64::from(u16::MAX)); + assert_eq!(u16::zero_extended::(u16::MAX), u128::from(u16::MAX)); + assert_eq!(u32::zero_extended::< u64>(u32::MAX), u64::from(u32::MAX)); + assert_eq!(u32::zero_extended::(u32::MAX), u128::from(u32::MAX)); + assert_eq!(u64::zero_extended::(u64::MAX), u128::from(u64::MAX)); + + assert_eq!( u8::zero_extended::< u8>( u8::MAX), u8::MAX); + assert_eq!( u16::zero_extended::< u16>( u16::MAX), u16::MAX); + assert_eq!( u32::zero_extended::< u32>( u32::MAX), u32::MAX); + assert_eq!( u64::zero_extended::< u64>( u64::MAX), u64::MAX); + assert_eq!(u128::zero_extended::(u128::MAX), u128::MAX); + } + + #[test] + #[rustfmt::skip] + fn zero_extend_signed_positive() { + assert_eq!( i8::zero_extended::< i8>(1), 1); + assert_eq!( i8::zero_extended::< i16>(1), 1); + assert_eq!( i8::zero_extended::< i32>(1), 1); + assert_eq!( i8::zero_extended::< i64>(1), 1); + assert_eq!( i8::zero_extended::(1), 1); + assert_eq!( i16::zero_extended::< i16>(1), 1); + assert_eq!( i16::zero_extended::< i32>(1), 1); + assert_eq!( i16::zero_extended::< i64>(1), 1); + assert_eq!( i16::zero_extended::(1), 1); + assert_eq!( i32::zero_extended::< i32>(1), 1); + assert_eq!( i32::zero_extended::< i64>(1), 1); + assert_eq!( i32::zero_extended::(1), 1); + assert_eq!( i64::zero_extended::< i64>(1), 1); + assert_eq!( i64::zero_extended::(1), 1); + assert_eq!(i128::zero_extended::(1), 1); + } + + #[test] + #[rustfmt::skip] + fn zero_extend_signed_negative() { + assert_eq!( i8::zero_extended::< i16>(-1), i16::from(u8 ::MAX)); + assert_eq!( i8::zero_extended::< i32>(-1), i32::from(u8 ::MAX)); + assert_eq!( i8::zero_extended::< i64>(-1), i64::from(u8 ::MAX)); + assert_eq!( i8::zero_extended::(-1), i128::from(u8 ::MAX)); + assert_eq!(i16::zero_extended::< i32>(-1), i32::from(u16 ::MAX)); + assert_eq!(i16::zero_extended::< i64>(-1), i64::from(u16 ::MAX)); + assert_eq!(i16::zero_extended::(-1), i128::from(u16 ::MAX)); + assert_eq!(i32::zero_extended::< i64>(-1), i64::from(u32 ::MAX)); + assert_eq!(i32::zero_extended::(-1), i128::from(u32 ::MAX)); + assert_eq!(i64::zero_extended::(-1), i128::from(u64 ::MAX)); + + assert_eq!( i8::zero_extended::< i8>(-1), -1); + assert_eq!( i16::zero_extended::< i16>(-1), -1); + assert_eq!( i32::zero_extended::< i32>(-1), -1); + assert_eq!( i64::zero_extended::< i64>(-1), -1); + assert_eq!(i128::zero_extended::(-1), -1); + } +} diff --git a/src/lib.rs b/src/lib.rs index 5b74ca8..ce080e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,8 @@ #![allow(clippy::integer_arithmetic)] // We want to explicitly use the type we're converting to in implementations #![allow(clippy::use_self)] +// We use integer division when we want to discard any decimal parts +#![allow(clippy::integer_division)] // In tests, we make sure `as` conversions are correct. #![cfg_attr(test, allow(clippy::as_conversions))] // Tests sometimes contain a lot of cases, but they're all simple diff --git a/src/sign.rs b/src/sign.rs index 36f412b..8c415ad 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -15,12 +15,15 @@ pub trait Signed { /// Unsigned variant of this type type Unsigned; - /// Reinterprets this type as unsigned + /// Reinterprets this value as unsigned fn as_unsigned(self) -> Self::Unsigned; - /// Reinterprets this type as signed + /// Reinterprets this value as signed fn as_signed(self) -> Self::Signed; + /// Returns the absolute value of `self` as unsigned. + fn abs_unsigned(self) -> Self::Unsigned; + // TODO: Maybe add a `fn signal() -> Signal` method? Or maybe two `is_positive` / `is_negative` methods. } @@ -53,6 +56,17 @@ macro_rules! impl_signed { fn as_signed(self) -> Self::Signed { self } + + #[inline] + fn abs_unsigned(self) -> Self::Unsigned { + // Note: Branch is optimized by compiler in release mode. + if self < 0 { + // Note: We don't use `-self.as_unsigned()` because it can panic + (!self.as_unsigned()).wrapping_add(1) + } else { + self.as_unsigned() + } + } } impl Signed for $TUnsigned { @@ -70,6 +84,12 @@ macro_rules! impl_signed { // Casting between integers of the same size is a no-op self as $TSigned } + + #[inline] + fn abs_unsigned(self) -> Self::Unsigned { + // Note: We're already unsigned + self + } } }; } @@ -115,38 +135,122 @@ mod tests { #[test] #[rustfmt::skip] - fn as_unsigned() { - assert_eq!( u8::as_unsigned(1), 1); - assert_eq!( u16::as_unsigned(1), 1); - assert_eq!( u32::as_unsigned(1), 1); - assert_eq!( u64::as_unsigned(1), 1); - assert_eq!( u128::as_unsigned(1), 1); + fn as_unsigned_positive() { + assert_eq!(u8 ::as_unsigned(1), 1); + assert_eq!(u16 ::as_unsigned(1), 1); + assert_eq!(u32 ::as_unsigned(1), 1); + assert_eq!(u64 ::as_unsigned(1), 1); + assert_eq!(u128 ::as_unsigned(1), 1); assert_eq!(usize::as_unsigned(1), 1); - - assert_eq!( i8::as_unsigned(-1), u8 ::MAX); - assert_eq!( i16::as_unsigned(-1), u16 ::MAX); - assert_eq!( i32::as_unsigned(-1), u32 ::MAX); - assert_eq!( i64::as_unsigned(-1), u64 ::MAX); - assert_eq!( i128::as_unsigned(-1), u128 ::MAX); + } + + #[test] + #[rustfmt::skip] + fn as_unsigned_negative() { + assert_eq!(i8 ::as_unsigned(-1), u8 ::MAX); + assert_eq!(i16 ::as_unsigned(-1), u16 ::MAX); + assert_eq!(i32 ::as_unsigned(-1), u32 ::MAX); + assert_eq!(i64 ::as_unsigned(-1), u64 ::MAX); + assert_eq!(i128 ::as_unsigned(-1), u128 ::MAX); assert_eq!(isize::as_unsigned(-1), usize::MAX); } #[test] - #[allow(clippy::cast_possible_wrap)] // We want to wrap around in this test #[rustfmt::skip] - fn as_signed() { - assert_eq!( u8::as_signed(1), 1); - assert_eq!( u16::as_signed(1), 1); - assert_eq!( u32::as_signed(1), 1); - assert_eq!( u64::as_signed(1), 1); - assert_eq!( u128::as_signed(1), 1); + fn as_unsigned_negative_big() { + assert_eq!(i8 ::as_unsigned(i8 ::MIN), u8 ::MAX / 2 + 1); + assert_eq!(i16 ::as_unsigned(i16 ::MIN), u16 ::MAX / 2 + 1); + assert_eq!(i32 ::as_unsigned(i32 ::MIN), u32 ::MAX / 2 + 1); + assert_eq!(i64 ::as_unsigned(i64 ::MIN), u64 ::MAX / 2 + 1); + assert_eq!(i128 ::as_unsigned(i128 ::MIN), u128 ::MAX / 2 + 1); + assert_eq!(isize::as_unsigned(isize::MIN), usize::MAX / 2 + 1); + } + + #[test] + #[rustfmt::skip] + fn as_signed_positive() { + assert_eq!(u8 ::as_signed(1), 1); + assert_eq!(u16 ::as_signed(1), 1); + assert_eq!(u32 ::as_signed(1), 1); + assert_eq!(u64 ::as_signed(1), 1); + assert_eq!(u128 ::as_signed(1), 1); assert_eq!(usize::as_signed(1), 1); - - assert_eq!( i8::as_signed(u8 ::MAX as i8), -1); - assert_eq!( i16::as_signed(u16 ::MAX as i16), -1); - assert_eq!( i32::as_signed(u32 ::MAX as i32), -1); - assert_eq!( i64::as_signed(u64 ::MAX as i64), -1); - assert_eq!( i128::as_signed(u128 ::MAX as i128), -1); - assert_eq!(isize::as_signed(usize::MAX as isize), -1); + } + + #[test] + #[rustfmt::skip] + fn as_signed_negative() { + assert_eq!(i8 ::as_signed(u8 ::MAX.as_signed()), -1); + assert_eq!(i16 ::as_signed(u16 ::MAX.as_signed()), -1); + assert_eq!(i32 ::as_signed(u32 ::MAX.as_signed()), -1); + assert_eq!(i64 ::as_signed(u64 ::MAX.as_signed()), -1); + assert_eq!(i128 ::as_signed(u128 ::MAX.as_signed()), -1); + assert_eq!(isize::as_signed(usize::MAX.as_signed()), -1); + } + + #[test] + #[rustfmt::skip] + fn abs_unsigned_unsigned() { + assert_eq!(u8 ::abs_unsigned(1), 1); + assert_eq!(u16 ::abs_unsigned(1), 1); + assert_eq!(u32 ::abs_unsigned(1), 1); + assert_eq!(u64 ::abs_unsigned(1), 1); + assert_eq!(u128 ::abs_unsigned(1), 1); + assert_eq!(usize::abs_unsigned(1), 1); + } + + #[test] + #[rustfmt::skip] + fn abs_unsigned_unsigned_big() { + assert_eq!(u8 ::abs_unsigned(u8 ::MAX), u8 ::MAX); + assert_eq!(u16 ::abs_unsigned(u16 ::MAX), u16 ::MAX); + assert_eq!(u32 ::abs_unsigned(u32 ::MAX), u32 ::MAX); + assert_eq!(u64 ::abs_unsigned(u64 ::MAX), u64 ::MAX); + assert_eq!(u128 ::abs_unsigned(u128 ::MAX), u128 ::MAX); + assert_eq!(usize::abs_unsigned(usize::MAX), usize::MAX); + } + + #[test] + #[rustfmt::skip] + fn abs_unsigned_signed_positive() { + assert_eq!(i8 ::abs_unsigned(1), 1); + assert_eq!(i16 ::abs_unsigned(1), 1); + assert_eq!(i32 ::abs_unsigned(1), 1); + assert_eq!(i64 ::abs_unsigned(1), 1); + assert_eq!(i128 ::abs_unsigned(1), 1); + assert_eq!(isize::abs_unsigned(1), 1); + } + + #[test] + #[rustfmt::skip] + fn abs_unsigned_signed_positive_big() { + assert_eq!(i8 ::abs_unsigned(i8 ::MAX), u8 ::MAX / 2); + assert_eq!(i16 ::abs_unsigned(i16 ::MAX), u16 ::MAX / 2); + assert_eq!(i32 ::abs_unsigned(i32 ::MAX), u32 ::MAX / 2); + assert_eq!(i64 ::abs_unsigned(i64 ::MAX), u64 ::MAX / 2); + assert_eq!(i128 ::abs_unsigned(i128 ::MAX), u128 ::MAX / 2); + assert_eq!(isize::abs_unsigned(isize::MAX), usize::MAX / 2); + } + + #[test] + #[rustfmt::skip] + fn abs_unsigned_signed_negative() { + assert_eq!(i8 ::abs_unsigned(-1), 1); + assert_eq!(i16 ::abs_unsigned(-1), 1); + assert_eq!(i32 ::abs_unsigned(-1), 1); + assert_eq!(i64 ::abs_unsigned(-1), 1); + assert_eq!(i128 ::abs_unsigned(-1), 1); + assert_eq!(isize::abs_unsigned(-1), 1); + } + + #[test] + #[rustfmt::skip] + fn abs_unsigned_signed_negative_big() { + assert_eq!(i8 ::abs_unsigned(i8 ::MIN), u8 ::MAX / 2 + 1); + assert_eq!(i16 ::abs_unsigned(i16 ::MIN), u16 ::MAX / 2 + 1); + assert_eq!(i32 ::abs_unsigned(i32 ::MIN), u32 ::MAX / 2 + 1); + assert_eq!(i64 ::abs_unsigned(i64 ::MIN), u64 ::MAX / 2 + 1); + assert_eq!(i128 ::abs_unsigned(i128 ::MIN), u128 ::MAX / 2 + 1); + assert_eq!(isize::abs_unsigned(isize::MIN), usize::MAX / 2 + 1); } }