//! Extension traits for integers and types used in the traits. //! //! //! use std_::{cmp, hash::Hash, fmt, ops}; use std_::time::Duration; /// Extension trait for built-in integers. pub trait IntegerExt: 'static + cmp::Eq + cmp::Ord + Copy + Default + fmt::Binary + fmt::Debug + fmt::Display + fmt::LowerHex + fmt::Octal + fmt::UpperHex + Hash + ops::Add + ops::AddAssign + ops::BitAnd + ops::BitAndAssign + ops::BitOr + ops::BitOrAssign + ops::BitXor + ops::BitXorAssign + ops::Div + ops::DivAssign + ops::Mul + ops::MulAssign + ops::Not + ops::Rem + ops::RemAssign + ops::Shl + ops::ShlAssign + ops::Shr + ops::ShrAssign + ops::Sub + ops::SubAssign + Send + Sync { /// The unsigned version of this integer type. type Unsigned: IntegerExt; /// The minimum value of this integer type. const MIN: Self; /// The maximum value of this integer type. const MAX: Self; /// `0` of this integer type. const ZERO: Self; /// `1` of this integer type. const ONE: Self; /// Converts from a `u8` to `Self`. /// /// if `Self` is an `i8` this method returns `127` for `n > 127`. /// /// # Example /// /// ``` /// use core_extensions::IntegerExt; /// /// assert_eq!(u8::from_u8(0 ), 0); /// assert_eq!(u8::from_u8(255), 255); /// /// assert_eq!(i8::from_u8(0 ), 0); /// assert_eq!(i8::from_u8(255), 127); /// /// assert_eq!(u16::from_u8(0 ), 0); /// assert_eq!(u16::from_u8(255), 255); /// /// assert_eq!(i16::from_u8(0 ), 0); /// assert_eq!(i16::from_u8(255), 255); /// /// ``` fn from_u8(n: u8) -> Self; /// Converts from an `i8` to `Self`. /// /// if `Self` is an unsigned integer type, /// this method returns `0` for `n < 0`. /// /// # Example /// /// ``` /// use core_extensions::IntegerExt; /// /// assert_eq!(u8::from_i8(-128), 0); /// assert_eq!(u8::from_i8(0 ), 0); /// assert_eq!(u8::from_i8(1 ), 1); /// assert_eq!(u8::from_i8(127 ), 127); /// /// assert_eq!(i8::from_i8(-128), -128); /// assert_eq!(i8::from_i8(0 ), 0 ); /// assert_eq!(i8::from_i8(127 ), 127 ); /// /// assert_eq!(u16::from_i8(-128), 0); /// assert_eq!(u16::from_i8(0 ), 0); /// assert_eq!(u16::from_i8(1 ), 1); /// assert_eq!(u16::from_i8(127 ), 127); /// /// assert_eq!(i16::from_i8(-128), -128); /// assert_eq!(i16::from_i8(0 ), 0 ); /// assert_eq!(i16::from_i8(127 ), 127 ); /// /// /// ``` fn from_i8(n: i8) -> Self; /// Raises `self` to the `n`th power. /// /// This delegates to the inherent [`pow`] method. /// /// [`pow`]: https://doc.rust-lang.org/std/primitive.u32.html#method.pow fn power(self, n: u32) -> Self; /// Returns the absolute value of this integer as the equivalent unsigned integer type. /// /// This method allows getting the absolute value for the minimum signed integer value. /// /// # Example /// /// ``` /// use core_extensions::IntegerExt; /// /// assert_eq!(0u8.abs_unsigned(), 0u8); /// assert_eq!(0i8.abs_unsigned(), 0u8); /// assert_eq!(127i8.abs_unsigned(), 127u8); /// assert_eq!((-1i8).abs_unsigned(), 1u8); /// assert_eq!((-16i8).abs_unsigned(), 16u8); /// assert_eq!((-128i8).abs_unsigned(), 128u8); /// /// ``` /// fn abs_unsigned(self) -> Self::Unsigned; /// Gets the sign of this integer. /// /// # Example /// /// ``` /// use core_extensions::integers::{IntegerExt, Sign}; /// /// assert_eq!(0u8.get_sign(), Sign::Positive); /// assert_eq!(0i8.get_sign(), Sign::Positive); /// assert_eq!(127i8.get_sign(), Sign::Positive); /// assert_eq!((-1i8).get_sign(), Sign::Negative); /// assert_eq!((-128i8).get_sign(), Sign::Negative); /// /// /// ``` /// #[inline] fn get_sign(self) -> Sign { if self < Self::ZERO { Sign::Negative } else { Sign::Positive } } /// Non-panicking division which returns `self` when `other == 0`. /// /// # Example /// /// ``` /// use core_extensions::IntegerExt; /// /// assert_eq!(60.safe_div(12), 5); /// assert_eq!(60.safe_div(30), 2); /// assert_eq!(60.safe_div(31), 1); /// /// assert_eq!(60.safe_div(0), 60); /// assert_eq!(13.safe_div(0), 13); /// /// ``` /// /// #[inline] fn safe_div(self, other: Self) -> Self { if other == Self::ZERO { self } else { self / other } } /// Returns the number of decimal digits of `self`. /// /// This counts the `-` sign as a digit. /// /// # Example /// /// ``` /// use core_extensions::IntegerExt; /// /// assert_eq!(100.number_of_digits(), 3); /// assert_eq!(10.number_of_digits(), 2); /// assert_eq!(1.number_of_digits(), 1); /// assert_eq!(0.number_of_digits(), 1); /// assert_eq!((-1).number_of_digits(), 2); /// assert_eq!((-100).number_of_digits(), 4); /// /// ``` /// fn number_of_digits(self) -> u32; } /// Converts an integer to a Duration of the unit. /// pub trait ToTime { /// Creates a [`Duration`] of `self` hours. /// /// [`Duration`]: https://doc.rust-lang.org/core/time/struct.Duration.html /// # Example /// /// ``` /// use core_extensions::ToTime; /// /// use std::time::Duration; /// /// assert_eq!(1 .hours(), Duration::from_secs(1 *3600)); /// assert_eq!(10 .hours(), Duration::from_secs(10 *3600)); /// assert_eq!(101.hours(), Duration::from_secs(101*3600)); /// ``` fn hours(self) -> Duration; /// Creates a [`Duration`] of `self` minutes. /// /// [`Duration`]: https://doc.rust-lang.org/core/time/struct.Duration.html /// # Example /// /// ``` /// use core_extensions::ToTime; /// /// use std::time::Duration; /// /// assert_eq!(1 .minutes(), Duration::from_secs(1 *60)); /// assert_eq!(10 .minutes(), Duration::from_secs(10 *60)); /// assert_eq!(101.minutes(), Duration::from_secs(101*60)); /// ``` fn minutes(self) -> Duration; /// Creates a [`Duration`] of `self` seconds /// /// [`Duration`]: https://doc.rust-lang.org/core/time/struct.Duration.html /// # Example /// /// ``` /// use core_extensions::ToTime; /// /// use std::time::Duration; /// /// assert_eq!(1.seconds(), Duration::from_secs(1)); /// assert_eq!(10.seconds(), Duration::from_secs(10)); /// assert_eq!(101.seconds(), Duration::from_secs(101)); /// ``` fn seconds(self) -> Duration; /// Creates a [`Duration`] of `self` milliseconds /// /// [`Duration`]: https://doc.rust-lang.org/core/time/struct.Duration.html /// # Example /// /// ``` /// use core_extensions::ToTime; /// /// use std::time::Duration; /// /// assert_eq!(0.milliseconds(), Duration::from_millis(0)); /// assert_eq!(1.milliseconds(), Duration::from_millis(1)); /// assert_eq!(10.milliseconds(), Duration::from_millis(10)); /// /// ``` fn milliseconds(self) -> Duration; /// Creates a [`Duration`] of `self` microseconds /// /// [`Duration`]: https://doc.rust-lang.org/core/time/struct.Duration.html /// # Example /// /// ``` /// use core_extensions::ToTime; /// /// use std::time::Duration; /// /// assert_eq!(10.microseconds(), Duration::new(0,10_000)); /// assert_eq!(10_000_001.microseconds(), Duration::new(10,1_000)); /// /// ``` fn microseconds(self) -> Duration; /// Creates a [`Duration`] of `self` nanoseconds /// /// [`Duration`]: https://doc.rust-lang.org/core/time/struct.Duration.html /// # Example /// /// ``` /// use core_extensions::ToTime; /// /// use std::time::Duration; /// /// assert_eq!(10.nanoseconds(), Duration::new(0,10)); /// assert_eq!(1_000_000.nanoseconds(), Duration::new(0,1_000_000)); /// assert_eq!(1_000_000_000.nanoseconds(), Duration::new(1,0)); /// assert_eq!(1_000_001_000.nanoseconds(), Duration::new(1,1_000)); /// /// ``` fn nanoseconds(self) -> Duration; } impl ToTime for T where T: IntegerExt + Copy, ::Unsigned: Into, { fn hours(self) -> Duration { Duration::from_secs(self.abs_unsigned().into() * 3600) } fn minutes(self) -> Duration { Duration::from_secs(self.abs_unsigned().into() * 60) } fn seconds(self) -> Duration { Duration::from_secs(self.abs_unsigned().into()) } fn milliseconds(self) -> Duration { Duration::from_millis(self.abs_unsigned().into()) } fn microseconds(self) -> Duration { let number: u64 = self.abs_unsigned().into(); Duration::new(number / 1_000_000, (number % 1_000_000 * 1000) as u32) } fn nanoseconds(self) -> Duration { let number: u64 = self.abs_unsigned().into(); Duration::new(number / 1_000_000_000, (number % 1_000_000_000) as u32) } } //------------------------------------------------------------------------------------ /// Represents the signedness of an integer #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Sign { /// Positive integer Positive = 0, /// Negative integer Negative = 1, } impl Sign { /// How long the string representation of this sign is. /// /// # Example /// /// ``` /// use core_extensions::integers::Sign; /// /// assert_eq!(Sign::Positive.sign_len(), 0); /// assert_eq!(Sign::Negative.sign_len(), 1); /// ``` /// #[inline] pub const fn sign_len(self) -> usize { self as _ } /// The string representation of this sign. /// /// # Example /// /// ``` /// use core_extensions::integers::Sign; /// /// assert_eq!(Sign::Positive.sign_string(), ""); /// assert_eq!(Sign::Negative.sign_string(), "-"); /// ``` /// #[inline] pub const fn sign_string(self) -> &'static str { cfg_if!{ (feature = "rust_1_46") { match self { Sign::Positive => "", Sign::Negative => "-", } } else { ["", "-"][self as usize] } } } } impl fmt::Display for Sign { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self.sign_string(), f) } } //---------------------------------- IMPLS ------------------------------------------- macro_rules! impl_absolute_unsigned_numbers { (from_u8;8,signed)=>{ #[inline(always)] fn from_u8(n:u8)->Self{ cmp::min(n,127) as _ } }; (from_u8;$($_bits:tt)*)=>{ #[inline(always)] fn from_u8(n:u8)->Self{ n as _ } }; (from_i8;unsigned)=>{ #[inline(always)] fn from_i8(n:i8)->Self{ cmp::max(n,0) as _ } }; (from_i8;signed)=>{ #[inline(always)] fn from_i8(n:i8)->Self{ n as _ } }; (num number_of_digits;delegate $n:ident $len:ident)=>{ $n.number_of_digits() }; (num number_of_digits;128 $n:ident $len:ident)=>{{ if $n >= 1_0000_0000_0000_0000{$n /= 1_0000_0000_0000_0000; $len += 16;} impl_absolute_unsigned_numbers!(num number_of_digits;64 $n $len) }}; (num number_of_digits;64 $n:ident $len:ident)=>{{ if $n >= 1_0000_0000_0000{$n /= 1_0000_0000_0000; $len += 12;} impl_absolute_unsigned_numbers!(num number_of_digits;32 $n $len) }}; (num number_of_digits;32 $n:ident $len:ident)=>{{ if $n >= 1_0000_0000{$n /= 100_000_000; $len += 8;} impl_absolute_unsigned_numbers!(num number_of_digits;16 $n $len) }}; (num number_of_digits;16 $n:ident $len:ident)=>{{ if $n >= 1_0000{$n /= 1_0000; $len += 4;} impl_absolute_unsigned_numbers!(num number_of_digits;8 $n $len) }}; (num number_of_digits;8 $n:ident $len:ident)=>{{ if $n >= 100{$n /= 100; $len += 2;} if $n >= 10{ $len += 1;} $len }}; (impl_either; type=$This:ty , bits=$bits:tt , $(cast=$cast_to:ty,)* )=>{ #[allow(unused_mut,unused_variables)] fn number_of_digits(self)-> u32 { let mut n=self.abs_unsigned() $(as $cast_to)* ; let mut len=self.get_sign().sign_len() as u32+1; impl_absolute_unsigned_numbers!(num number_of_digits;$bits n len) } #[inline] fn power(self,n:u32)->Self{ self.pow(n) } }; ( $([ $tsig:ty, $tuns:ty, bits=$bits:tt , $(cast=$cast_to:ty,)* $(#[$meta:meta])* ])* ) => {$( $(#[$meta])* impl IntegerExt for $tsig { type Unsigned = $tuns; #[inline] fn abs_unsigned(self) -> Self::Unsigned { // using this instead of self.abs() to avoid // panicking on self==Self::min_value() self.wrapping_abs() as Self::Unsigned } const ZERO: Self = 0; const ONE: Self = 1; const MIN: Self = Self::min_value(); const MAX: Self = Self::max_value(); impl_absolute_unsigned_numbers!{impl_either; type=$tsig, bits=$bits, $(cast=$cast_to,)* } impl_absolute_unsigned_numbers!{from_u8;$bits,signed} impl_absolute_unsigned_numbers!{from_i8;signed} } $(#[$meta])* impl IntegerExt for $tuns { type Unsigned = $tuns; #[inline] fn abs_unsigned(self) -> Self::Unsigned { self } const ZERO: Self = 0; const ONE: Self = 1; const MIN: Self = Self::min_value(); const MAX: Self = Self::max_value(); impl_absolute_unsigned_numbers!{impl_either; type=$tuns, bits=$bits, $(cast=$cast_to,)* } impl_absolute_unsigned_numbers!{from_u8;$bits,unsigned} impl_absolute_unsigned_numbers!{from_i8;unsigned} } )*} } #[cfg(target_pointer_width = "8")] type UWord = u8; #[cfg(target_pointer_width = "16")] type UWord = u16; #[cfg(target_pointer_width = "32")] type UWord = u32; #[cfg(target_pointer_width = "64")] type UWord = u64; #[cfg(target_pointer_width = "128")] type UWord = u128; impl_absolute_unsigned_numbers!( [i8 ,u8 ,bits=8, ] [i16,u16,bits=16,] [i32,u32,bits=32,] [i64,u64,bits=64,] [i128,u128,bits=128,] [isize,usize,bits=delegate,cast=UWord,] ); //---------------------------------- TESTS ------------------------------------------- #[cfg(test)] #[cfg(feature = "alloc")] mod tests { use super::*; use alloc::vec::Vec; const MAX_POWER: u32 = 38; fn check_number_of_digits(iter: I) where I: IntoIterator, N: PartialEq + fmt::Display + Default + Copy + IntegerExt, { for (n, digits) in iter { assert_eq!(n.number_of_digits(), digits, " n:{} ", n); } } fn generate_numbers() -> Vec<(u128, u32)> { let ten: u128 = 10; let mut out: Vec<(u128, u32)> = vec![(0, 1), (1, 1), (9, 1)]; for power in 1..MAX_POWER { let digits = power + 1; out.push((ten.pow(power), digits)); out.push((ten.pow(power) + 1, digits)); out.push((ten.pow(power + 1) - 1, digits)); } out.push((ten.pow(MAX_POWER), MAX_POWER + 1)); out.push((ten.pow(MAX_POWER) + 1, MAX_POWER + 1)); out.push((u128::max_value(), MAX_POWER + 1)); out } macro_rules! check_number_of_digits_ { ($($ty:ty),*) => { $( check_number_of_digits( generate_numbers() .into_iter() .filter(|v| v.0 <= (<$ty>::max_value() as u128)) .map(|v| (v.0 as $ty, v.1)), ); )* }; } #[test] fn number_of_digits_i8() { check_number_of_digits_!(i8, u8, i16, u16, i32, u32, u64, i64, usize, isize, u128, i128); } macro_rules! check_assoc_consts { ($($ty:ty),*) => { $({ assert_eq!(<$ty as IntegerExt>::MIN, <$ty>::min_value()); assert_eq!(<$ty as IntegerExt>::MAX, <$ty>::max_value()); assert_eq!(<$ty as IntegerExt>::ZERO, 0); assert_eq!(<$ty as IntegerExt>::ONE, 1); })* }; } #[test] fn associated_constants() { check_assoc_consts!(i8, u8, i16, u16, i32, u32, u64, i64, usize, isize, u128, i128); } }