num_primitive/
signed.rs

1use crate::{PrimitiveInteger, PrimitiveIntegerRef, PrimitiveUnsigned};
2
3/// Trait for all primitive [signed integer types], including the supertraits [`PrimitiveInteger`]
4/// and [`PrimitiveNumber`][crate::PrimitiveNumber].
5///
6/// This encapsulates trait implementations and inherent methods that are common among all of the
7/// primitive signed integer types: [`i8`], [`i16`], [`i32`], [`i64`], [`i128`], and [`isize`].
8///
9/// See the corresponding items on the individual types for more documentation and examples.
10///
11/// This trait is sealed with a private trait to prevent downstream implementations, so we may
12/// continue to expand along with the standard library without worrying about breaking changes for
13/// implementors.
14///
15/// [signed integer types]: https://doc.rust-lang.org/reference/types/numeric.html#r-type.numeric.int.signed
16///
17/// # Examples
18///
19/// ```
20/// use num_primitive::PrimitiveSigned;
21///
22/// // GCD with Bézout coefficients (extended Euclidean algorithm)
23/// fn extended_gcd<T: PrimitiveSigned>(a: T, b: T) -> (T, T, T) {
24///     let zero = T::from(0i8);
25///     let one = T::from(1i8);
26///
27///     let (mut old_r, mut r) = (a, b);
28///     let (mut old_s, mut s) = (one, zero);
29///     let (mut old_t, mut t) = (zero, one);
30///
31///     while r != zero {
32///         let quotient = old_r.div_euclid(r);
33///         (old_r, r) = (r, old_r - quotient * r);
34///         (old_s, s) = (s, old_s - quotient * s);
35///         (old_t, t) = (t, old_t - quotient * t);
36///     }
37///
38///     let (gcd, x, y) = if old_r.is_negative() {
39///         (-old_r, -old_s, -old_t)
40///     } else {
41///         (old_r, old_s, old_t)
42///     };
43///     assert_eq!(gcd, a * x + b * y);
44///     (gcd, x, y)
45/// }
46///
47/// assert_eq!(extended_gcd::<i8>(0, -42), (42, 0, -1));
48/// assert_eq!(extended_gcd::<i8>(48, 18), (6, -1, 3));
49/// assert_eq!(extended_gcd::<i16>(1071, -462), (21, -3, -7));
50/// assert_eq!(extended_gcd::<i64>(6_700_417, 2_147_483_647), (1, 715_828_096, -2_233_473));
51/// ```
52pub trait PrimitiveSigned: PrimitiveInteger + From<i8> + core::ops::Neg<Output = Self> {
53    /// The unsigned integer type used by methods like [`abs_diff`][Self::abs_diff] and
54    /// [`checked_add_unsigned`][Self::checked_add_unsigned].
55    type Unsigned: PrimitiveUnsigned;
56
57    /// Computes the absolute value of `self`.
58    fn abs(self) -> Self;
59
60    /// Computes the absolute difference between `self` and `other`.
61    fn abs_diff(self, other: Self) -> Self::Unsigned;
62
63    /// Checked absolute value. Computes `self.abs()`, returning `None` if `self == MIN`.
64    fn checked_abs(self) -> Option<Self>;
65
66    /// Checked addition with an unsigned integer. Computes `self + rhs`, returning `None` if
67    /// overflow occurred.
68    fn checked_add_unsigned(self, rhs: Self::Unsigned) -> Option<Self>;
69
70    /// Returns the square root of the number, rounded down. Returns `None` if `self` is negative.
71    fn checked_isqrt(self) -> Option<Self>;
72
73    /// Checked subtraction with an unsigned integer. Computes `self - rhs`, returning `None` if
74    /// overflow occurred.
75    fn checked_sub_unsigned(self, rhs: Self::Unsigned) -> Option<Self>;
76
77    /// Returns true if `self` is negative and false if the number is zero or positive.
78    fn is_negative(self) -> bool;
79
80    /// Returns true if `self` is positive and false if the number is zero or negative.
81    fn is_positive(self) -> bool;
82
83    /// Computes the absolute value of `self`. Returns a tuple of the absolute version of `self`
84    /// along with a boolean indicating whether an overflow happened.
85    fn overflowing_abs(self) -> (Self, bool);
86
87    /// Calculates `self + rhs` with an unsigned `rhs`. Returns a tuple of the addition along with
88    /// a boolean indicating whether an arithmetic overflow would occur.
89    fn overflowing_add_unsigned(self, rhs: Self::Unsigned) -> (Self, bool);
90
91    /// Calculates `self - rhs` with an unsigned `rhs`. Returns a tuple of the subtraction along
92    /// with a boolean indicating whether an arithmetic overflow would occur.
93    fn overflowing_sub_unsigned(self, rhs: Self::Unsigned) -> (Self, bool);
94
95    /// Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self == MIN` instead
96    /// of overflowing.
97    fn saturating_abs(self) -> Self;
98
99    /// Saturating addition with an unsigned integer. Computes `self + rhs`, saturating at the
100    /// numeric bounds instead of overflowing.
101    fn saturating_add_unsigned(self, rhs: Self::Unsigned) -> Self;
102
103    /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` instead of
104    /// overflowing.
105    fn saturating_neg(self) -> Self;
106
107    /// Saturating subtraction with an unsigned integer. Computes `self - rhs`, saturating at the
108    /// numeric bounds instead of overflowing.
109    fn saturating_sub_unsigned(self, rhs: Self::Unsigned) -> Self;
110
111    /// Returns a number representing sign of `self`.
112    fn signum(self) -> Self;
113
114    /// Computes the absolute value of `self` without any wrapping or panicking.
115    fn unsigned_abs(self) -> Self::Unsigned;
116
117    /// Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at the boundary
118    /// of the type.
119    fn wrapping_abs(self) -> Self;
120
121    /// Wrapping (modular) addition with an unsigned integer. Computes `self + rhs`, wrapping
122    /// around at the boundary of the type.
123    fn wrapping_add_unsigned(self, rhs: Self::Unsigned) -> Self;
124
125    /// Wrapping (modular) subtraction with an unsigned integer. Computes `self - rhs`, wrapping
126    /// around at the boundary of the type.
127    fn wrapping_sub_unsigned(self, rhs: Self::Unsigned) -> Self;
128}
129
130/// Trait for references to primitive signed integer types ([`PrimitiveSigned`]).
131///
132/// This enables traits like the standard operators in generic code,
133/// e.g. `where &T: PrimitiveSignedRef<T>`.
134pub trait PrimitiveSignedRef<T>: PrimitiveIntegerRef<T> + core::ops::Neg<Output = T> {}
135
136macro_rules! impl_signed {
137    ($Signed:ident, $Unsigned:ty) => {
138        impl PrimitiveSigned for $Signed {
139            type Unsigned = $Unsigned;
140
141            forward! {
142                fn abs(self) -> Self;
143                fn abs_diff(self, other: Self) -> Self::Unsigned;
144                fn checked_abs(self) -> Option<Self>;
145                fn checked_add_unsigned(self, rhs: Self::Unsigned) -> Option<Self>;
146                fn checked_isqrt(self) -> Option<Self>;
147                fn checked_sub_unsigned(self, rhs: Self::Unsigned) -> Option<Self>;
148                fn is_negative(self) -> bool;
149                fn is_positive(self) -> bool;
150                fn overflowing_abs(self) -> (Self, bool);
151                fn overflowing_add_unsigned(self, rhs: Self::Unsigned) -> (Self, bool);
152                fn overflowing_sub_unsigned(self, rhs: Self::Unsigned) -> (Self, bool);
153                fn saturating_abs(self) -> Self;
154                fn saturating_add_unsigned(self, rhs: Self::Unsigned) -> Self;
155                fn saturating_neg(self) -> Self;
156                fn saturating_sub_unsigned(self, rhs: Self::Unsigned) -> Self;
157                fn signum(self) -> Self;
158                fn unsigned_abs(self) -> Self::Unsigned;
159                fn wrapping_abs(self) -> Self;
160                fn wrapping_add_unsigned(self, rhs: Self::Unsigned) -> Self;
161                fn wrapping_sub_unsigned(self, rhs: Self::Unsigned) -> Self;
162            }
163        }
164
165        impl PrimitiveSignedRef<$Signed> for &$Signed {}
166    };
167}
168
169impl_signed!(i8, u8);
170impl_signed!(i16, u16);
171impl_signed!(i32, u32);
172impl_signed!(i64, u64);
173impl_signed!(i128, u128);
174impl_signed!(isize, usize);