machine_check/types/
bitvector.rs

1use std::{
2    fmt::Debug,
3    ops::{Add, BitAnd, BitOr, BitXor, Mul, Not, Shl, Sub},
4};
5
6use mck::{
7    concr::{self, IntoMck},
8    forward::{Bitwise, HwArith, HwShift},
9};
10
11use crate::{Signed, Unsigned};
12
13/// Bitvector without signedness information.
14///
15/// The number of bits is specified in the generic parameter L.
16/// Bitvectors support bitwise operations and wrapping-arithmetic operations.
17/// Only operations where the behaviour of signed and unsigned numbers match are implemented.
18/// For others, conversion into [`Unsigned`] or [`Signed`] is necessary.
19/// Bit-extension is not possible directly, as signed and unsigned bitvectors are extended differently.
20#[derive(Clone, Copy, Hash, PartialEq, Eq)]
21pub struct Bitvector<const L: u32>(pub(super) concr::Bitvector<L>);
22
23impl<const L: u32> Bitvector<L> {
24    /// Creates a new bitvector with the given value.
25    ///
26    /// Panics if the value does not fit into the type.
27    pub fn new(value: u64) -> Self {
28        Bitvector(concr::Bitvector::new(value))
29    }
30}
31// --- BITWISE OPERATIONS ---
32
33impl<const L: u32> Not for Bitvector<L> {
34    type Output = Self;
35
36    /// Performs bitwise NOT.
37    fn not(self) -> Self::Output {
38        Self(self.0.bit_not())
39    }
40}
41
42impl<const L: u32> BitAnd<Bitvector<L>> for Bitvector<L> {
43    type Output = Self;
44
45    /// Performs bitwise AND.
46    fn bitand(self, rhs: Bitvector<L>) -> Self::Output {
47        Self(self.0.bit_and(rhs.0))
48    }
49}
50impl<const L: u32> BitOr<Bitvector<L>> for Bitvector<L> {
51    type Output = Self;
52
53    /// Performs bitwise OR.
54    fn bitor(self, rhs: Bitvector<L>) -> Self::Output {
55        Self(self.0.bit_or(rhs.0))
56    }
57}
58impl<const L: u32> BitXor<Bitvector<L>> for Bitvector<L> {
59    type Output = Self;
60
61    /// Performs bitwise XOR.
62    fn bitxor(self, rhs: Bitvector<L>) -> Self::Output {
63        Self(self.0.bit_xor(rhs.0))
64    }
65}
66
67// --- ARITHMETIC OPERATIONS ---
68
69impl<const L: u32> Add<Bitvector<L>> for Bitvector<L> {
70    type Output = Self;
71
72    /// Performs wrapping addition.
73    fn add(self, rhs: Bitvector<L>) -> Self::Output {
74        Self(self.0.add(rhs.0))
75    }
76}
77
78impl<const L: u32> Sub<Bitvector<L>> for Bitvector<L> {
79    type Output = Self;
80
81    /// Performs wrapping subtraction.
82    fn sub(self, rhs: Bitvector<L>) -> Self::Output {
83        Self(self.0.sub(rhs.0))
84    }
85}
86
87impl<const L: u32> Mul<Bitvector<L>> for Bitvector<L> {
88    type Output = Self;
89
90    /// Performs wrapping multiplication.
91    fn mul(self, rhs: Bitvector<L>) -> Self::Output {
92        Self(self.0.mul(rhs.0))
93    }
94}
95
96// --- SHIFT ---
97impl<const L: u32> Shl<Bitvector<L>> for Bitvector<L> {
98    type Output = Self;
99
100    /// Performs a left shift.
101    ///
102    /// Unlike a right shift, where the behaviour is dependent on signedness,
103    /// the left shift has the same behaviour: shifted-out bits on the left
104    /// are discarded and zeros are shifted in on the right.
105    ///
106    /// The right-hand side operand is interpreted as unsigned and if it
107    /// is equal or greater to the bit-width, the result is all-zeros,
108    /// as in Rust `unbounded_shl`. It is planned to restrict the bit-width
109    /// in the future so that this edge case can never occur.
110    fn shl(self, rhs: Bitvector<L>) -> Self::Output {
111        Self(self.0.logic_shl(rhs.0))
112    }
113}
114
115// --- CONVERSION ---
116impl<const L: u32> From<Unsigned<L>> for Bitvector<L> {
117    /// Drops the signedness information from `Unsigned`.
118    fn from(value: Unsigned<L>) -> Self {
119        Self(value.0)
120    }
121}
122
123impl<const L: u32> From<Signed<L>> for Bitvector<L> {
124    /// Drops the signedness information from `Signed`.
125    fn from(value: Signed<L>) -> Self {
126        Self(value.0)
127    }
128}
129
130impl<const L: u32> Debug for Bitvector<L> {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        std::fmt::Debug::fmt(&self.0, f)
133    }
134}
135
136// --- INTERNAL IMPLEMENTATIONS ---
137
138#[doc(hidden)]
139impl<const L: u32> IntoMck for Bitvector<L> {
140    type Type = mck::concr::Bitvector<L>;
141
142    fn into_mck(self) -> Self::Type {
143        self.0
144    }
145}