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