1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::{
    fmt::Debug,
    ops::{Add, BitAnd, BitOr, BitXor, Mul, Not, Shl, Sub},
};

use mck::{
    concr::{self, IntoMck},
    forward::{Bitwise, HwArith, HwShift},
};

use crate::{Signed, Unsigned};

/// Bitvector without signedness information.
///
/// The number of bits is specified in the generic parameter L.
/// Bitvectors support bitwise operations and wrapping-arithmetic operations.
/// Only operations where the behaviour of signed and unsigned numbers match are implemented.
/// For others, conversion into [`Unsigned`] or [`Signed`] is necessary.
/// Bit-extension is not possible directly, as signed and unsigned bitvectors are extended differently.
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct Bitvector<const L: u32>(pub(super) concr::Bitvector<L>);

impl<const L: u32> Bitvector<L> {
    ///
    /// Creates a new bitvector with the given value.
    /// Panics if the value does not fit into the type.
    ///
    pub fn new(value: u64) -> Self {
        Bitvector(concr::Bitvector::new(value))
    }
}
// --- BITWISE OPERATIONS ---

impl<const L: u32> Not for Bitvector<L> {
    type Output = Self;

    fn not(self) -> Self::Output {
        Self(self.0.bit_not())
    }
}

impl<const L: u32> BitAnd<Bitvector<L>> for Bitvector<L> {
    type Output = Self;

    fn bitand(self, rhs: Bitvector<L>) -> Self::Output {
        Self(self.0.bit_and(rhs.0))
    }
}
impl<const L: u32> BitOr<Bitvector<L>> for Bitvector<L> {
    type Output = Self;

    fn bitor(self, rhs: Bitvector<L>) -> Self::Output {
        Self(self.0.bit_or(rhs.0))
    }
}
impl<const L: u32> BitXor<Bitvector<L>> for Bitvector<L> {
    type Output = Self;

    fn bitxor(self, rhs: Bitvector<L>) -> Self::Output {
        Self(self.0.bit_xor(rhs.0))
    }
}

// --- ARITHMETIC OPERATIONS ---

impl<const L: u32> Add<Bitvector<L>> for Bitvector<L> {
    type Output = Self;

    fn add(self, rhs: Bitvector<L>) -> Self::Output {
        Self(self.0.add(rhs.0))
    }
}

impl<const L: u32> Sub<Bitvector<L>> for Bitvector<L> {
    type Output = Self;

    fn sub(self, rhs: Bitvector<L>) -> Self::Output {
        Self(self.0.sub(rhs.0))
    }
}

impl<const L: u32> Mul<Bitvector<L>> for Bitvector<L> {
    type Output = Self;

    fn mul(self, rhs: Bitvector<L>) -> Self::Output {
        Self(self.0.mul(rhs.0))
    }
}

// --- SHIFT ---
impl<const L: u32> Shl<Bitvector<L>> for Bitvector<L> {
    type Output = Self;

    fn shl(self, rhs: Bitvector<L>) -> Self::Output {
        Self(self.0.logic_shl(rhs.0))
    }
}

// --- CONVERSION ---
impl<const L: u32> From<Unsigned<L>> for Bitvector<L> {
    fn from(value: Unsigned<L>) -> Self {
        Self(value.0)
    }
}

impl<const L: u32> From<Signed<L>> for Bitvector<L> {
    fn from(value: Signed<L>) -> Self {
        Self(value.0)
    }
}

impl<const L: u32> Debug for Bitvector<L> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Debug::fmt(&self.0, f)
    }
}

// --- INTERNAL IMPLEMENTATIONS ---

#[doc(hidden)]
impl<const L: u32> IntoMck for Bitvector<L> {
    type Type = mck::concr::Bitvector<L>;

    fn into_mck(self) -> Self::Type {
        self.0
    }
}