num_primitive/signed.rs
1use core::convert::Infallible;
2use core::num::NonZero;
3
4use crate::{
5 NonZeroPrimitiveInteger, NonZeroPrimitiveUnsigned, PrimitiveInteger, PrimitiveIntegerRef,
6 PrimitiveUnsigned,
7};
8
9/// Trait for all primitive [signed integer types], including the supertraits [`PrimitiveInteger`]
10/// and [`PrimitiveNumber`][crate::PrimitiveNumber].
11///
12/// This encapsulates trait implementations and inherent methods that are common among all of the
13/// primitive signed integer types: [`i8`], [`i16`], [`i32`], [`i64`], [`i128`], and [`isize`].
14///
15/// See the corresponding items on the individual types for more documentation and examples.
16///
17/// This trait is sealed with a private trait to prevent downstream implementations, so we may
18/// continue to expand along with the standard library without worrying about breaking changes for
19/// implementors.
20///
21/// [signed integer types]: https://doc.rust-lang.org/reference/types/numeric.html#r-type.numeric.int.signed
22///
23/// # Examples
24///
25/// ```
26/// use num_primitive::PrimitiveSigned;
27///
28/// // GCD with Bézout coefficients (extended Euclidean algorithm)
29/// fn extended_gcd<T: PrimitiveSigned>(a: T, b: T) -> (T, T, T) {
30/// let zero = T::from(0i8);
31/// let one = T::from(1i8);
32///
33/// let (mut old_r, mut r) = (a, b);
34/// let (mut old_s, mut s) = (one, zero);
35/// let (mut old_t, mut t) = (zero, one);
36///
37/// while r != zero {
38/// let quotient = old_r.div_euclid(r);
39/// (old_r, r) = (r, old_r - quotient * r);
40/// (old_s, s) = (s, old_s - quotient * s);
41/// (old_t, t) = (t, old_t - quotient * t);
42/// }
43///
44/// let (gcd, x, y) = if old_r.is_negative() {
45/// (-old_r, -old_s, -old_t)
46/// } else {
47/// (old_r, old_s, old_t)
48/// };
49/// assert_eq!(gcd, a * x + b * y);
50/// (gcd, x, y)
51/// }
52///
53/// assert_eq!(extended_gcd::<i8>(0, -42), (42, 0, -1));
54/// assert_eq!(extended_gcd::<i8>(48, 18), (6, -1, 3));
55/// assert_eq!(extended_gcd::<i16>(1071, -462), (21, -3, -7));
56/// assert_eq!(extended_gcd::<i64>(6_700_417, 2_147_483_647), (1, 715_828_096, -2_233_473));
57/// ```
58pub trait PrimitiveSigned:
59 PrimitiveInteger
60 + core::convert::From<i8>
61 + core::convert::TryFrom<i8, Error = Infallible>
62 + core::ops::Neg<Output = Self>
63{
64 /// The unsigned integer type used by methods like [`abs_diff`][Self::abs_diff] and
65 /// [`checked_add_unsigned`][Self::checked_add_unsigned].
66 type Unsigned: PrimitiveUnsigned;
67
68 /// Computes the absolute value of `self`.
69 fn abs(self) -> Self;
70
71 /// Computes the absolute difference between `self` and `other`.
72 fn abs_diff(self, other: Self) -> Self::Unsigned;
73
74 /// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size.
75 fn cast_unsigned(self) -> Self::Unsigned;
76
77 /// Checked absolute value. Computes `self.abs()`, returning `None` if `self == MIN`.
78 fn checked_abs(self) -> Option<Self>;
79
80 /// Checked addition with an unsigned integer. Computes `self + rhs`, returning `None` if
81 /// overflow occurred.
82 fn checked_add_unsigned(self, rhs: Self::Unsigned) -> Option<Self>;
83
84 /// Returns the square root of the number, rounded down. Returns `None` if `self` is negative.
85 fn checked_isqrt(self) -> Option<Self>;
86
87 /// Checked subtraction with an unsigned integer. Computes `self - rhs`, returning `None` if
88 /// overflow occurred.
89 fn checked_sub_unsigned(self, rhs: Self::Unsigned) -> Option<Self>;
90
91 /// Returns true if `self` is negative and false if the number is zero or positive.
92 fn is_negative(self) -> bool;
93
94 /// Returns true if `self` is positive and false if the number is zero or negative.
95 fn is_positive(self) -> bool;
96
97 /// Computes the absolute value of `self`. Returns a tuple of the absolute version of `self`
98 /// along with a boolean indicating whether an overflow happened.
99 fn overflowing_abs(self) -> (Self, bool);
100
101 /// Calculates `self + rhs` with an unsigned `rhs`. Returns a tuple of the addition along with
102 /// a boolean indicating whether an arithmetic overflow would occur.
103 fn overflowing_add_unsigned(self, rhs: Self::Unsigned) -> (Self, bool);
104
105 /// Calculates `self - rhs` with an unsigned `rhs`. Returns a tuple of the subtraction along
106 /// with a boolean indicating whether an arithmetic overflow would occur.
107 fn overflowing_sub_unsigned(self, rhs: Self::Unsigned) -> (Self, bool);
108
109 /// Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self == MIN` instead
110 /// of overflowing.
111 fn saturating_abs(self) -> Self;
112
113 /// Saturating addition with an unsigned integer. Computes `self + rhs`, saturating at the
114 /// numeric bounds instead of overflowing.
115 fn saturating_add_unsigned(self, rhs: Self::Unsigned) -> Self;
116
117 /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` instead of
118 /// overflowing.
119 fn saturating_neg(self) -> Self;
120
121 /// Saturating subtraction with an unsigned integer. Computes `self - rhs`, saturating at the
122 /// numeric bounds instead of overflowing.
123 fn saturating_sub_unsigned(self, rhs: Self::Unsigned) -> Self;
124
125 /// Returns a number representing sign of `self`.
126 fn signum(self) -> Self;
127
128 /// Strict absolute value. Computes `self.abs()`, panicking if `self == MIN`.
129 fn strict_abs(self) -> Self;
130
131 /// Strict addition with an unsigned integer. Computes `self + rhs`,
132 /// panicking if overflow occurred.
133 fn strict_add_unsigned(self, rhs: Self::Unsigned) -> Self;
134
135 /// Strict subtraction with an unsigned integer. Computes `self - rhs`,
136 /// panicking if overflow occurred.
137 fn strict_sub_unsigned(self, rhs: Self::Unsigned) -> Self;
138
139 /// Computes the absolute value of `self` without any wrapping or panicking.
140 fn unsigned_abs(self) -> Self::Unsigned;
141
142 /// Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at the boundary
143 /// of the type.
144 fn wrapping_abs(self) -> Self;
145
146 /// Wrapping (modular) addition with an unsigned integer. Computes `self + rhs`, wrapping
147 /// around at the boundary of the type.
148 fn wrapping_add_unsigned(self, rhs: Self::Unsigned) -> Self;
149
150 /// Wrapping (modular) subtraction with an unsigned integer. Computes `self - rhs`, wrapping
151 /// around at the boundary of the type.
152 fn wrapping_sub_unsigned(self, rhs: Self::Unsigned) -> Self;
153
154 /// Unchecked negation. Computes `-self`, assuming overflow cannot occur.
155 ///
156 /// # Safety
157 ///
158 /// This results in undefined behavior when `self == Self::MIN`, i.e. when
159 /// [`checked_neg`][PrimitiveInteger::checked_neg] would return `None`.
160 unsafe fn unchecked_neg(self) -> Self;
161}
162
163/// Trait for references to primitive signed integer types ([`PrimitiveSigned`]).
164///
165/// This enables traits like the standard operators in generic code,
166/// e.g. `where &T: PrimitiveSignedRef<T>`.
167pub trait PrimitiveSignedRef<T>: PrimitiveIntegerRef<T> + core::ops::Neg<Output = T> {}
168
169/// Trait for [`NonZero`] primitive signed integers, including the supertrait
170/// [`NonZeroPrimitiveInteger`].
171///
172/// This encapsulates trait implementations and inherent methods that are common among all of the
173/// implementations of `NonZero<T>`, where `T` is a [`PrimitiveSigned`].
174///
175/// See the corresponding items on the individual types for more documentation and examples.
176///
177/// This trait is sealed with a private trait to prevent downstream implementations, so we may
178/// continue to expand along with the standard library without worrying about breaking changes for
179/// implementors.
180///
181/// # Examples
182///
183/// ```
184/// use num_primitive::NonZeroPrimitiveSigned;
185/// use core::num::NonZero;
186///
187/// fn sign_and_magnitude<T: NonZeroPrimitiveSigned>(n: T) -> (bool, T::NonZeroUnsigned) {
188/// (n.is_negative(), n.unsigned_abs())
189/// }
190///
191/// let n = NonZero::new(-42i16).unwrap();
192/// assert_eq!(sign_and_magnitude(n), (true, NonZero::new(42u16).unwrap()));
193/// ```
194pub trait NonZeroPrimitiveSigned:
195 NonZeroPrimitiveInteger<Integer: PrimitiveSigned>
196 + core::convert::From<NonZero<i8>>
197 + core::ops::Neg<Output = Self>
198{
199 /// The unsigned non-zero integer type used by methods like
200 /// [`cast_unsigned`][Self::cast_unsigned].
201 ///
202 /// For `core::num::NonZero<T>`, this is `NonZero<T::Unsigned>`.
203 type NonZeroUnsigned: NonZeroPrimitiveUnsigned;
204
205 /// Computes the absolute value of self.
206 fn abs(self) -> Self;
207
208 /// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size.
209 fn cast_unsigned(self) -> Self::NonZeroUnsigned;
210
211 /// Checked absolute value. Checks for overflow and returns [`None`] if `self == Self::MIN`.
212 fn checked_abs(self) -> Option<Self>;
213
214 /// Checked negation. Computes `-self`, returning `None` if `self == Self::MIN`.
215 fn checked_neg(self) -> Option<Self>;
216
217 /// Returns `true` if `self` is positive and `false` if the number is negative.
218 fn is_positive(self) -> bool;
219
220 /// Returns `true` if `self` is negative and `false` if the number is positive.
221 fn is_negative(self) -> bool;
222
223 /// Computes the absolute value of self, with overflow information.
224 fn overflowing_abs(self) -> (Self, bool);
225
226 /// Negates self, overflowing if this is equal to the minimum value.
227 fn overflowing_neg(self) -> (Self, bool);
228
229 /// Saturating absolute value.
230 fn saturating_abs(self) -> Self;
231
232 /// Saturating negation. Computes `-self`, returning `Self::MAX`
233 /// if `self == Self::MIN` instead of overflowing.
234 fn saturating_neg(self) -> Self;
235
236 /// Computes the absolute value of self without any wrapping or panicking.
237 fn unsigned_abs(self) -> Self::NonZeroUnsigned;
238
239 /// Wrapping absolute value.
240 fn wrapping_abs(self) -> Self;
241
242 /// Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary
243 /// of the type.
244 fn wrapping_neg(self) -> Self;
245}
246
247// TODO: consider a NonZero*Ref hierarchy, including Neg here.
248// pub trait NonZeroPrimitiveSignedRef<NZ>: core::ops::Neg<Output = NZ> {}
249
250macro_rules! impl_signed {
251 ($Signed:ident, $Unsigned:ty) => {
252 impl PrimitiveSigned for $Signed {
253 type Unsigned = $Unsigned;
254
255 forward! {
256 fn abs(self) -> Self;
257 fn abs_diff(self, other: Self) -> Self::Unsigned;
258 fn cast_unsigned(self) -> Self::Unsigned;
259 fn checked_abs(self) -> Option<Self>;
260 fn checked_add_unsigned(self, rhs: Self::Unsigned) -> Option<Self>;
261 fn checked_isqrt(self) -> Option<Self>;
262 fn checked_sub_unsigned(self, rhs: Self::Unsigned) -> Option<Self>;
263 fn is_negative(self) -> bool;
264 fn is_positive(self) -> bool;
265 fn overflowing_abs(self) -> (Self, bool);
266 fn overflowing_add_unsigned(self, rhs: Self::Unsigned) -> (Self, bool);
267 fn overflowing_sub_unsigned(self, rhs: Self::Unsigned) -> (Self, bool);
268 fn saturating_abs(self) -> Self;
269 fn saturating_add_unsigned(self, rhs: Self::Unsigned) -> Self;
270 fn saturating_neg(self) -> Self;
271 fn saturating_sub_unsigned(self, rhs: Self::Unsigned) -> Self;
272 fn signum(self) -> Self;
273 fn strict_abs(self) -> Self;
274 fn strict_add_unsigned(self, rhs: Self::Unsigned) -> Self;
275 fn strict_sub_unsigned(self, rhs: Self::Unsigned) -> Self;
276 fn unsigned_abs(self) -> Self::Unsigned;
277 fn wrapping_abs(self) -> Self;
278 fn wrapping_add_unsigned(self, rhs: Self::Unsigned) -> Self;
279 fn wrapping_sub_unsigned(self, rhs: Self::Unsigned) -> Self;
280 }
281 forward! {
282 unsafe fn unchecked_neg(self) -> Self;
283 }
284 }
285
286 impl PrimitiveSignedRef<$Signed> for &$Signed {}
287
288 impl NonZeroPrimitiveSigned for NonZero<$Signed> {
289 type NonZeroUnsigned = NonZero<$Unsigned>;
290
291 forward! {
292 fn abs(self) -> Self;
293 fn cast_unsigned(self) -> Self::NonZeroUnsigned;
294 fn checked_abs(self) -> Option<Self>;
295 fn checked_neg(self) -> Option<Self>;
296 fn is_negative(self) -> bool;
297 fn is_positive(self) -> bool;
298 fn overflowing_abs(self) -> (Self, bool);
299 fn overflowing_neg(self) -> (Self, bool);
300 fn saturating_abs(self) -> Self;
301 fn saturating_neg(self) -> Self;
302 fn unsigned_abs(self) -> Self::NonZeroUnsigned;
303 fn wrapping_abs(self) -> Self;
304 fn wrapping_neg(self) -> Self;
305 }
306 }
307 };
308}
309
310impl_signed!(i8, u8);
311impl_signed!(i16, u16);
312impl_signed!(i32, u32);
313impl_signed!(i64, u64);
314impl_signed!(i128, u128);
315impl_signed!(isize, usize);