machine_check/types/
unsigned.rs

1use std::{
2    fmt::Debug,
3    ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub},
4};
5
6use mck::{
7    concr::{self, IntoMck},
8    forward::{Bitwise, HwArith, HwShift},
9};
10
11use crate::{traits::Ext, Bitvector, Signed};
12
13///
14/// Unsigned bitvector.
15///
16/// The number of bits is specified in the generic parameter L.
17/// Unsigned bitvectors support bitwise operations and wrapping-arithmetic operations.
18/// Logical bit extension is also possible (any new bits are zero).
19/// Signed bitvectors be converted into [`Unsigned`] or [`Bitvector`].
20#[derive(Clone, Copy, Hash, PartialEq, Eq)]
21pub struct Unsigned<const L: u32>(pub(super) concr::Bitvector<L>);
22
23impl<const L: u32> Unsigned<L> {
24    ///
25    /// Creates a new bitvector with the given value.
26    /// Panics if the value does not fit into the type.
27    ///
28    pub fn new(value: u64) -> Self {
29        Unsigned(concr::Bitvector::new(value))
30    }
31}
32// --- BITWISE OPERATIONS ---
33
34impl<const L: u32> Not for Unsigned<L> {
35    type Output = Self;
36
37    /// Performs bitwise NOT.
38    fn not(self) -> Self::Output {
39        Self(self.0.bit_not())
40    }
41}
42
43impl<const L: u32> BitAnd<Unsigned<L>> for Unsigned<L> {
44    type Output = Self;
45
46    /// Performs bitwise AND.
47    fn bitand(self, rhs: Unsigned<L>) -> Self::Output {
48        Self(self.0.bit_and(rhs.0))
49    }
50}
51impl<const L: u32> BitOr<Unsigned<L>> for Unsigned<L> {
52    type Output = Self;
53
54    /// Performs bitwise OR.
55    fn bitor(self, rhs: Unsigned<L>) -> Self::Output {
56        Self(self.0.bit_or(rhs.0))
57    }
58}
59impl<const L: u32> BitXor<Unsigned<L>> for Unsigned<L> {
60    type Output = Self;
61
62    /// Performs bitwise XOR.
63    fn bitxor(self, rhs: Unsigned<L>) -> Self::Output {
64        Self(self.0.bit_xor(rhs.0))
65    }
66}
67
68// --- ARITHMETIC OPERATIONS ---
69
70impl<const L: u32> Add<Unsigned<L>> for Unsigned<L> {
71    type Output = Self;
72
73    /// Performs wrapping addition.
74    fn add(self, rhs: Unsigned<L>) -> Self::Output {
75        Self(self.0.add(rhs.0))
76    }
77}
78
79impl<const L: u32> Sub<Unsigned<L>> for Unsigned<L> {
80    type Output = Self;
81
82    /// Performs wrapping subtraction.
83    fn sub(self, rhs: Unsigned<L>) -> Self::Output {
84        Self(self.0.sub(rhs.0))
85    }
86}
87
88impl<const L: u32> Mul<Unsigned<L>> for Unsigned<L> {
89    type Output = Self;
90
91    /// Performs wrapping multiplication.
92    fn mul(self, rhs: Unsigned<L>) -> Self::Output {
93        Self(self.0.mul(rhs.0))
94    }
95}
96
97impl<const L: u32> Div<Unsigned<L>> for Unsigned<L> {
98    type Output = Self;
99
100    /// Performs wrapping unsigned division.
101    ///
102    /// While the division is defined to be wrapping,
103    /// no wrapping actually can happen in unsigned division.
104    ///
105    /// # Panics
106    ///
107    /// Panics if `rhs` is zero.
108    fn div(self, rhs: Unsigned<L>) -> Self::Output {
109        let panic_result = self.0.udiv(rhs.0);
110        if panic_result.panic.is_nonzero() {
111            panic!("attempt to divide by zero")
112        }
113        Self(panic_result.result)
114    }
115}
116
117impl<const L: u32> Rem<Unsigned<L>> for Unsigned<L> {
118    type Output = Self;
119
120    /// Performs wrapping unsigned remainer.
121    ///
122    /// While the remainder is defined to be wrapping,
123    /// no wrapping actually can happen in unsigned remainder.
124    ///
125    /// # Panics
126    ///
127    /// Panics if `rhs` is zero.
128    fn rem(self, rhs: Unsigned<L>) -> Self::Output {
129        let panic_result = self.0.urem(rhs.0);
130        if panic_result.panic.is_nonzero() {
131            panic!("attempt to calculate the remainder with a divisor of zero")
132        }
133        Self(panic_result.result)
134    }
135}
136
137impl<const L: u32> Shl<Unsigned<L>> for Unsigned<L> {
138    type Output = Self;
139
140    /// Performs a left shift.
141    ///
142    /// Unlike a right shift, where the behaviour is dependent on signedness,
143    /// the left shift has the same behaviour: shifted-out bits on the left
144    /// are discarded and zeros are shifted in on the right.
145    ///
146    /// The right-hand side operand is interpreted as unsigned and if it
147    /// is equal or greater to the bit-width, the result is all-zeros,
148    /// as in Rust `unbounded_shl`. It is planned to restrict the bit-width
149    /// in the future so that this edge case can never occur.
150    fn shl(self, rhs: Unsigned<L>) -> Self::Output {
151        Self(self.0.logic_shl(rhs.0))
152    }
153}
154
155impl<const L: u32> Shr<Unsigned<L>> for Unsigned<L> {
156    type Output = Self;
157
158    /// Performs a logic right shift.
159    ///
160    /// The right-hand side operand is interpreted as unsigned and if it
161    /// is equal or greater to the bit-width, the result is all-zeros,
162    /// as in Rust `unbounded_shr` on unsigned primitives.
163    /// It is planned to restrict the bit-width in the future so that this edge
164    /// case can never occur.
165    fn shr(self, rhs: Unsigned<L>) -> Self::Output {
166        Self(self.0.logic_shr(rhs.0))
167    }
168}
169
170// --- EXTENSION ---
171impl<const L: u32, const X: u32> Ext<X> for Unsigned<L> {
172    type Output = Unsigned<X>;
173
174    /// Extends or narrows the bit-vector.
175    ///
176    /// If an extension is performed, the upper bits will be zero.
177    fn ext(self) -> Self::Output {
178        Unsigned::<X>(mck::forward::Ext::uext(self.0))
179    }
180}
181
182// --- ORDERING ---
183
184impl<const L: u32> PartialOrd for Unsigned<L> {
185    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
186        Some(self.cmp(other))
187    }
188}
189
190impl<const L: u32> Ord for Unsigned<L> {
191    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
192        self.0.unsigned_cmp(&other.0)
193    }
194}
195
196// --- CONVERSION ---
197
198impl<const L: u32> From<Bitvector<L>> for Unsigned<L> {
199    /// Adds signedness information to `Bitvector`.
200    fn from(value: Bitvector<L>) -> Self {
201        Self(value.0)
202    }
203}
204
205impl<const L: u32> From<Signed<L>> for Unsigned<L> {
206    /// Converts the signedness information from `Signed` to `Unsigned`.
207    fn from(value: Signed<L>) -> Self {
208        Self(value.0)
209    }
210}
211
212// --- MISC ---
213
214impl<const L: u32> Debug for Unsigned<L> {
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        std::fmt::Debug::fmt(&self.0, f)
217    }
218}
219
220// --- INTERNAL IMPLEMENTATIONS ---
221
222#[doc(hidden)]
223impl<const L: u32> IntoMck for Unsigned<L> {
224    type Type = mck::concr::Bitvector<L>;
225
226    fn into_mck(self) -> Self::Type {
227        self.0
228    }
229}