signed/
lib.rs

1use std::ops::{AddAssign, SubAssign};
2
3/// Wrapper type around signed integers to do generic operations no matter what size they are
4pub trait Signed: AddAssign + SubAssign
5where
6    Self: Sized + Copy,
7{
8    type Unsigned;
9    const ZERO: Self;
10
11    fn get_absolute(&mut self) -> Absolute<'_, Self>;
12
13    fn abs_diff(self, other: Self) -> Self::Unsigned;
14
15    fn abs(self) -> Self;
16
17    fn is_positive(self) -> bool;
18
19    fn is_negative(self) -> bool;
20
21    fn signum(self) -> Self;
22}
23
24/// A pointer to absolute value of a number
25///
26/// ```
27/// use signed::Signed;
28///
29/// let mut n: i32 = 42; // A number to test operations with it
30///
31/// let mut abs_n = n.get_absolute(); // Gets a "pointer" to an absolute value of a number
32///
33/// abs_n -= &2;
34/// drop(abs_n);
35///
36/// assert_eq!(n, 40);
37///
38/// let mut abs_n = n.get_absolute(); // Gets a "pointer" to an absolute value of a number
39///
40/// abs_n += &6;
41/// drop(abs_n);
42///
43/// assert_eq!(n, 46);
44///
45/// n = -42; // Let's try with negative number
46///
47/// // Unfortunately, due to assertions, abs_n has to be dropped before immutable use, but when n
48/// // is changed, abs_n is changed accordingly
49///
50/// let mut abs_n = n.get_absolute(); // Gets a "pointer" to an absolute value of a number
51///
52/// abs_n -= &4;
53/// drop(abs_n);
54///
55/// assert_eq!(n, -38); // Now that's different, we subtracted, but got a number *bigger* than the initial one.
56///
57/// let mut abs_n = n.get_absolute(); // Gets a "pointer" to an absolute value of a number
58///
59/// abs_n += &6;
60/// drop(abs_n);
61///
62/// assert_eq!(n, -44); // And by adding to the absolute value, we get a number *smaller*.
63///
64/// // All of this works for i8, i16, i32, i64 and i128!
65/// ```
66#[derive(Debug)]
67pub struct Absolute<'a, I: Signed> {
68    num: &'a mut I,
69}
70
71impl Signed for i8 {
72    type Unsigned = u8;
73    const ZERO: i8 = 0;
74
75    #[inline]
76    fn get_absolute(&mut self) -> Absolute<'_, Self> {
77        Absolute { num: self }
78    }
79
80    #[inline]
81    fn abs(self) -> Self {
82        self.abs()
83    }
84
85    #[inline]
86    fn abs_diff(self, other: Self) -> Self::Unsigned {
87        self.abs_diff(other)
88    }
89
90    #[inline]
91    fn is_positive(self) -> bool {
92        self.is_positive()
93    }
94
95    #[inline]
96    fn is_negative(self) -> bool {
97        self.is_negative()
98    }
99
100    #[inline]
101    fn signum(self) -> Self {
102        self.signum()
103    }
104}
105
106impl Signed for i16 {
107    type Unsigned = u16;
108    const ZERO: i16 = 0;
109
110    #[inline]
111    fn get_absolute(&mut self) -> Absolute<'_, Self> {
112        Absolute { num: self }
113    }
114
115    #[inline]
116    fn abs_diff(self, other: Self) -> Self::Unsigned {
117        self.abs_diff(other)
118    }
119
120    #[inline]
121    fn abs(self) -> Self {
122        self.abs()
123    }
124
125    #[inline]
126    fn is_positive(self) -> bool {
127        self.is_positive()
128    }
129
130    #[inline]
131    fn is_negative(self) -> bool {
132        self.is_negative()
133    }
134
135    #[inline]
136    fn signum(self) -> Self {
137        self.signum()
138    }
139}
140
141impl Signed for i32 {
142    type Unsigned = u32;
143    const ZERO: i32 = 0;
144
145    #[inline]
146    fn get_absolute(&mut self) -> Absolute<'_, Self> {
147        Absolute { num: self }
148    }
149
150    #[inline]
151    fn abs_diff(self, other: Self) -> Self::Unsigned {
152        self.abs_diff(other)
153    }
154
155    #[inline]
156    fn abs(self) -> Self {
157        self.abs()
158    }
159
160    #[inline]
161    fn is_positive(self) -> bool {
162        self.is_positive()
163    }
164
165    #[inline]
166    fn is_negative(self) -> bool {
167        self.is_negative()
168    }
169
170    #[inline]
171    fn signum(self) -> Self {
172        self.signum()
173    }
174}
175
176impl Signed for i64 {
177    type Unsigned = u64;
178    const ZERO: i64 = 0;
179
180    #[inline]
181    fn get_absolute(&mut self) -> Absolute<'_, Self> {
182        Absolute { num: self }
183    }
184
185    #[inline]
186    fn abs_diff(self, other: Self) -> Self::Unsigned {
187        self.abs_diff(other)
188    }
189
190    #[inline]
191    fn abs(self) -> Self {
192        self.abs()
193    }
194
195    #[inline]
196    fn is_positive(self) -> bool {
197        self.is_positive()
198    }
199
200    #[inline]
201    fn is_negative(self) -> bool {
202        self.is_negative()
203    }
204
205    fn signum(self) -> Self {
206        self.signum()
207    }
208}
209
210impl Signed for i128 {
211    type Unsigned = u128;
212    const ZERO: i128 = 0;
213
214    #[inline]
215    fn get_absolute(&mut self) -> Absolute<'_, Self> {
216        Absolute { num: self }
217    }
218
219    #[inline]
220    fn abs_diff(self, other: Self) -> Self::Unsigned {
221        self.abs_diff(other)
222    }
223
224    #[inline]
225    fn abs(self) -> Self {
226        self.abs()
227    }
228
229    #[inline]
230    fn is_positive(self) -> bool {
231        self.is_positive()
232    }
233
234    #[inline]
235    fn is_negative(self) -> bool {
236        self.is_negative()
237    }
238
239    #[inline]
240    fn signum(self) -> Self {
241        self.signum()
242    }
243}
244
245impl<'a, I: Signed> Absolute<'a, I> {
246    /// Get the value of an absolute of a number this absolute value has been taken of
247    #[inline]
248    pub fn get_value(&self) -> I::Unsigned {
249        self.num.abs_diff(I::ZERO)
250    }
251}
252
253impl<'a, I: Signed> AddAssign<&I> for Absolute<'a, I> {
254    #[inline]
255    fn add_assign(&mut self, rhs: &I) {
256        if self.num.is_negative() {
257            self.num.sub_assign(*rhs)
258        } else {
259            self.num.add_assign(*rhs)
260        };
261    }
262}
263
264impl<'a, I: Signed> SubAssign<&I> for Absolute<'a, I> {
265    #[inline]
266    fn sub_assign(&mut self, rhs: &I) {
267        if self.num.is_negative() {
268            self.num.add_assign(*rhs)
269        } else {
270            self.num.sub_assign(*rhs)
271        }
272    }
273}