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