Skip to main content

procem/
word.rs

1//! The [`Word`] trait, its super traits and its implementations for all signed integer types.
2
3use core::fmt::{Debug, Display};
4use core::num::ParseIntError;
5use core::ops::{
6    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, Mul, MulAssign,
7    Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
8};
9
10/// The `WordBase` trait defines the base trait constraints for the Word type.
11/// It has a blanket implementation for all types that implement its super traits.
12pub trait WordBase: Debug + Display + Copy + Eq + Ord + Default {}
13
14impl<T> WordBase for T where T: Debug + Display + Copy + Eq + Ord + Default {}
15
16/// The `WordConvert` trait defines the convertion trait constraints for the Word type.
17/// It has a blanket implementation for all types that implement its super traits.
18pub trait WordConvert: TryFrom<usize> + Into<usize> + From<i32> {}
19
20impl<T> WordConvert for T where T: TryFrom<usize> + Into<usize> + From<i32> {}
21
22/// The `WordOps` trait defines operation trait constraints for the Word type.
23/// It has a blanket implementation for all types that implement its super traits.
24pub trait WordOps:
25    Sized
26    + Add<Output = Self>
27    + Sub<Output = Self>
28    + Mul<Output = Self>
29    + Div<Output = Self>
30    + AddAssign
31    + SubAssign
32    + MulAssign
33    + DivAssign
34    + Neg
35    + Rem
36    + RemAssign
37{
38}
39
40impl<T> WordOps for T where
41    T: Add<Output = Self>
42        + Sub<Output = Self>
43        + Mul<Output = Self>
44        + Div<Output = Self>
45        + Rem<Output = Self>
46        + AddAssign
47        + SubAssign
48        + MulAssign
49        + DivAssign
50        + RemAssign
51        + Neg
52{
53}
54
55/// The `WordBitOps` trait defines bitwise operation trait constraints for the Word type.
56/// It has a blanket implementation for all types that implement its super traits.
57pub trait WordBitOps:
58    Sized
59    + BitAnd<Self, Output = Self>
60    + BitOr<Self, Output = Self>
61    + BitXor<Self, Output = Self>
62    + Not<Output = Self>
63    + Shl<Self, Output = Self>
64    + Shr<Self, Output = Self>
65    + BitAndAssign
66    + BitOrAssign
67    + BitXorAssign
68    + ShlAssign
69    + ShrAssign
70{
71}
72
73impl<T> WordBitOps for T where
74    T: BitAnd<Self, Output = Self>
75        + BitOr<Self, Output = Self>
76        + BitXor<Self, Output = Self>
77        + Not<Output = Self>
78        + Shl<Self, Output = Self>
79        + Shr<Self, Output = Self>
80        + BitAndAssign
81        + BitOrAssign
82        + BitXorAssign
83        + ShlAssign
84        + ShrAssign
85{
86}
87
88/// The Word trait wraps the underlying type used as the processor’s word size, mimicking real-world architectures
89/// (e.g., [`I32`] corresponds to a 32-bit architecture).
90///
91/// The [`Word`] trait is implemented for the following signed integer types:
92/// - [`I8`]
93/// - [`I16`]
94/// - [`I32`]
95/// - [`I64`]
96/// - [`I128`]
97/// - [`ISize`]
98///
99/// These types use two's complement representation, mirroring how real-world processor architectures work.
100/// To implement custom [`Word`] types, you can define your own type that implements the [`Word`] trait.
101pub trait Word: WordBase + WordConvert + WordOps + WordBitOps {
102    /// This is a wrapper around the [`from_str_radix()`](i32::from_str_radix()) function that is implemented for all of Rust's numeric types.
103    ///
104    /// # Errors
105    /// Returns [`ParseIntError`] when the parsing failed.
106    fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseIntError>;
107
108    /// Checks for carry when adding.
109    #[must_use]
110    fn check_carry_add(&self, rhs: Self) -> bool;
111
112    /// Checks for carry when subtracting.
113    #[must_use]
114    fn check_carry_sub(&self, rhs: Self) -> bool;
115
116    /// Checks for carry when multiplying.
117    #[must_use]
118    fn check_carry_mul(&self, rhs: Self) -> bool;
119
120    /// Checks for division overflow (i.e., MIN / -1 for signed types).
121    /// Similiar to [`Word::overflowing_div()`] this is a convenience wrapper over Rust's [`overflowing_div()`](i32::overflowing_div()).
122    /// However it discards the result of the division.
123    #[must_use]
124    fn check_carry_div(&self, rhs: Self) -> bool;
125
126    /// Convenience wrapper over Rust's [`overflowing_add()`](i32::overflowing_add()).
127    #[must_use]
128    fn overflowing_add(&self, rhs: Self) -> (Self, bool);
129    /// Convenience wrapper over Rust's [`overflowing_sub()`](i32::overflowing_sub()).
130    #[must_use]
131    fn overflowing_sub(&self, rhs: Self) -> (Self, bool);
132    /// Convenience wrapper over Rust's [`overflowing_mul()`](i32::overflowing_mul()).
133    #[must_use]
134    fn overflowing_mul(&self, rhs: Self) -> (Self, bool);
135    /// Convenience wrapper over Rust's [`overflowing_div()`](i32::overflowing_div()).
136    #[must_use]
137    fn overflowing_div(&self, rhs: Self) -> (Self, bool);
138
139    /// Convenience wrapper over Rust's [`rotate_left()`](i32::rotate_left()).
140    #[must_use]
141    fn rotate_left(&self, val: u32) -> Self;
142    /// Convenience wrapper over Rust's [`rotate_right()`](i32::rotate_right()).
143    #[must_use]
144    fn rotate_right(&self, val: u32) -> Self;
145}
146
147// Implements the From<i32> trait for a wrapper struct around another type like i8.
148// It is necessary as Word is implemented for all signed types also i32.
149// From<i32> cannot be implemented for i32 and therefore this extra macro is needed.
150macro_rules! from_i32 {
151    ($name: ident, $type: ty $(,)? ) => {
152        impl ::core::convert::From<i32> for $name {
153            fn from(value: i32) -> Self {
154                #[allow(clippy::cast_possible_truncation)]
155                #[allow(clippy::cast_lossless)]
156                #[allow(clippy::cast_sign_loss)]
157                $name(value as $type)
158            }
159        }
160    };
161}
162
163// Implements the Word trait for a wrapper struct around another type like i8.
164macro_rules! impl_word {
165    ($name: ident, $type: ty $(,)? ) => {
166        #[doc = concat!("Wrapper struct around ", stringify!($type), ".")]
167        #[doc = concat!("Represents a ", stringify!($type), "-bit processor architecture.")]
168        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
169        #[repr(transparent)]
170        pub struct $name($type);
171
172        impl Word for $name {
173            fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseIntError> {
174                <$type>::from_str_radix(s, radix).map($name)
175            }
176
177            fn check_carry_add(&self, rhs: Self) -> bool {
178                #[allow(clippy::cast_sign_loss)]
179                let (lhs, rhs) = (self.0 as u128, rhs.0 as u128);
180                lhs + rhs > <$type>::MAX as u128
181            }
182
183            fn check_carry_sub(&self, rhs: Self) -> bool {
184                #[allow(clippy::cast_sign_loss)]
185                let (lhs, rhs) = (self.0 as u128, rhs.0 as u128);
186                lhs < rhs
187            }
188
189            fn check_carry_mul(&self, rhs: Self) -> bool {
190                #[allow(clippy::cast_sign_loss)]
191                let (lhs, rhs) = (self.0 as u128, rhs.0 as u128);
192                lhs * rhs > <$type>::MAX as u128
193            }
194
195            fn check_carry_div(&self, rhs: Self) -> bool {
196                self.0.overflowing_div(rhs.0).1
197            }
198
199            fn overflowing_add(&self, rhs: Self) -> (Self, bool) {
200                let (res, overflow) = self.0.overflowing_add(rhs.0);
201                (Self(res), overflow)
202            }
203
204            fn overflowing_sub(&self, rhs: Self) -> (Self, bool) {
205                let (res, overflow) = self.0.overflowing_sub(rhs.0);
206                (Self(res), overflow)
207            }
208
209            fn overflowing_mul(&self, rhs: Self) -> (Self, bool) {
210                let (res, overflow) = self.0.overflowing_mul(rhs.0);
211                (Self(res), overflow)
212            }
213
214            fn overflowing_div(&self, rhs: Self) -> (Self, bool) {
215                let (res, overflow) = self.0.overflowing_div(rhs.0);
216                (Self(res), overflow)
217            }
218
219            fn rotate_left(&self, val: u32) -> Self {
220                Self(self.0.rotate_left(val))
221            }
222
223            fn rotate_right(&self, val: u32) -> Self {
224                Self(self.0.rotate_right(val))
225            }
226        }
227
228        impl ::core::fmt::Display for $name {
229            fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> Result<(), ::core::fmt::Error> {
230                write!(f, "{}", self.0)
231            }
232        }
233
234        impl ::core::convert::From<$name> for usize {
235            #[allow(clippy::cast_sign_loss)]
236            #[allow(clippy::cast_possible_truncation)]
237            fn from(value: $name) -> usize {
238                value.0 as usize
239            }
240        }
241
242        impl ::core::convert::TryFrom<usize> for $name {
243            type Error = ::core::num::TryFromIntError;
244
245            fn try_from(value: usize) -> Result<Self, Self::Error> {
246                Ok(Self(<$type>::try_from(value)?))
247            }
248        }
249
250        impl ::core::convert::From<$type> for $name {
251            fn from(value: $type) -> Self {
252                Self(value)
253            }
254        }
255
256        impl ::core::ops::Add for $name {
257            type Output = Self;
258
259            fn add(self, rhs: Self) -> Self {
260                Self(self.0.wrapping_add(rhs.0))
261            }
262        }
263
264        impl ::core::ops::AddAssign for $name {
265            fn add_assign(&mut self, other: Self) {
266                *self = *self + other;
267            }
268        }
269
270        impl ::core::ops::Sub for $name {
271            type Output = Self;
272
273            fn sub(self, rhs: Self) -> Self {
274                Self(self.0.wrapping_sub(rhs.0))
275            }
276        }
277
278        impl ::core::ops::SubAssign for $name {
279            fn sub_assign(&mut self, other: Self) {
280                *self = *self - other;
281            }
282        }
283
284        impl ::core::ops::Mul for $name {
285            type Output = Self;
286
287            fn mul(self, rhs: Self) -> Self {
288                Self(self.0.wrapping_mul(rhs.0))
289            }
290        }
291
292        impl ::core::ops::MulAssign for $name {
293            fn mul_assign(&mut self, other: Self) {
294                *self = *self * other;
295            }
296        }
297
298        impl ::core::ops::Div for $name {
299            type Output = Self;
300
301            fn div(self, rhs: Self) -> Self {
302                Self(self.0.wrapping_div(rhs.0))
303            }
304        }
305
306        impl ::core::ops::DivAssign for $name {
307            fn div_assign(&mut self, other: Self) {
308                *self = *self / other;
309            }
310        }
311
312        impl ::core::ops::Neg for $name {
313            type Output = Self;
314
315            fn neg(self) -> Self {
316                Self(self.0.wrapping_neg())
317            }
318        }
319
320        impl ::core::ops::Rem for $name {
321            type Output = Self;
322
323            fn rem(self, rhs: Self) -> Self {
324                Self(self.0.wrapping_rem(rhs.0))
325            }
326        }
327
328        impl ::core::ops::RemAssign for $name {
329            fn rem_assign(&mut self, rhs: Self) {
330                *self = *self % rhs
331            }
332        }
333
334        impl ::core::ops::BitAnd for $name {
335            type Output = Self;
336
337            fn bitand(self, rhs: Self) -> Self {
338                Self(self.0 & rhs.0)
339            }
340        }
341
342        impl ::core::ops::BitOr for $name {
343            type Output = Self;
344
345            fn bitor(self, rhs: Self) -> Self {
346                Self(self.0 | rhs.0)
347            }
348        }
349
350        impl ::core::ops::BitXor for $name {
351            type Output = Self;
352
353            fn bitxor(self, rhs: Self) -> Self {
354                Self(self.0 ^ rhs.0)
355            }
356        }
357
358        impl ::core::ops::Not for $name {
359            type Output = Self;
360
361            fn not(self) -> Self {
362                Self(!self.0)
363            }
364        }
365
366        impl ::core::ops::Shl for $name {
367            type Output = Self;
368
369            fn shl(self, rhs: Self) -> Self {
370                Self(self.0 << rhs.0)
371            }
372        }
373
374        impl ::core::ops::Shr for $name {
375            type Output = Self;
376
377            fn shr(self, rhs: Self) -> Self {
378                Self(self.0 >> rhs.0)
379            }
380        }
381
382        impl ::core::ops::BitAndAssign for $name {
383            fn bitand_assign(&mut self, rhs: Self) {
384                self.0 &= rhs.0;
385            }
386        }
387
388        impl ::core::ops::BitOrAssign for $name {
389            fn bitor_assign(&mut self, rhs: Self) {
390                self.0 |= rhs.0;
391            }
392        }
393
394        impl ::core::ops::BitXorAssign for $name {
395            fn bitxor_assign(&mut self, rhs: Self) {
396                self.0 ^= rhs.0;
397            }
398        }
399
400        impl ::core::ops::ShlAssign for $name {
401            fn shl_assign(&mut self, rhs: Self) {
402                self.0 <<= rhs.0;
403            }
404        }
405
406        impl ::core::ops::ShrAssign for $name {
407            fn shr_assign(&mut self, rhs: Self) {
408                self.0 >>= rhs.0;
409            }
410        }
411    };
412}
413
414impl_word!(I8, i8);
415impl_word!(I16, i16);
416impl_word!(I32, i32);
417impl_word!(I64, i64);
418impl_word!(I128, i128);
419impl_word!(ISize, isize);
420
421from_i32!(I8, i8);
422from_i32!(I16, i16);
423from_i32!(I64, i64);
424from_i32!(I128, i128);
425from_i32!(ISize, isize);