nostd_bv/traits/
bits_mut_ext.rs

1use super::{Bits, BitsMut};
2use crate::BlockType;
3
4/// Extension trait for mutable operations on bit slices.
5pub trait BitsMutExt: BitsMut {
6    /// Assigns the bits of `other` to `self`.
7    ///
8    /// # Panics
9    ///
10    /// If `self.bit_len() != other.bit_len()`.
11    fn bit_assign<T: Bits<Block = Self::Block>>(&mut self, other: T) {
12        assert_eq!(
13            self.bit_len(),
14            other.bit_len(),
15            "BitsMutExt::bit_assign: arguments have different lengths"
16        );
17
18        let bit_len = self.bit_len();
19        let full_blocks = Self::Block::div_nbits(bit_len);
20        let extra_bits = Self::Block::mod_nbits(bit_len);
21
22        for i in 0..full_blocks {
23            let block = other.get_raw_block(i);
24            self.set_block(i, block);
25        }
26
27        if extra_bits > 0 {
28            let block = other.get_raw_block(full_blocks);
29            self.set_bits(bit_len - extra_bits as u64, extra_bits, block);
30        }
31    }
32
33    /// Assigns the bit-wise *and* of `self` and `other` to `self`.
34    ///
35    /// # Panics
36    ///
37    /// If `self.bit_len() != other.bit_len()`.
38    fn bit_and_assign<T: Bits<Block = Self::Block>>(&mut self, other: T) {
39        self.bit_zip_assign(other, |b1, b2| b1 & b2);
40    }
41
42    /// Assigns the bit-wise *or* of `self` and `other` to `self`.
43    ///
44    /// # Panics
45    ///
46    /// If `self.bit_len() != other.bit_len()`.
47    fn bit_or_assign<T: Bits<Block = Self::Block>>(&mut self, other: T) {
48        self.bit_zip_assign(other, |b1, b2| b1 | b2);
49    }
50
51    /// Assigns the bit-wise *xor* of `self` and `other` to `self`.
52    ///
53    /// # Panics
54    ///
55    /// If `self.bit_len() != other.bit_len()`.
56    fn bit_xor_assign<T: Bits<Block = Self::Block>>(&mut self, other: T) {
57        self.bit_zip_assign(other, |b1, b2| b1 ^ b2);
58    }
59
60    /// Performs an op-assignment from `other` to `self`.
61    ///
62    /// In particular, the given function is used to combine each
63    /// block of `self` with a block of `other`, assigning the result
64    /// back to `self`.
65    ///
66    /// # Panics
67    ///
68    /// If `self.bit_len() != other.bit_len()`.
69    fn bit_zip_assign<T, F>(&mut self, other: T, mut fun: F)
70    where
71        T: Bits<Block = Self::Block>,
72        F: FnMut(Self::Block, Self::Block) -> Self::Block,
73    {
74        assert_eq!(
75            self.bit_len(),
76            other.bit_len(),
77            "BitsMutExt::bit_zip_assign: arguments have different lengths"
78        );
79
80        let bit_len = self.bit_len();
81        let full_blocks = Self::Block::div_nbits(bit_len);
82        let extra_bits = Self::Block::mod_nbits(bit_len);
83
84        for i in 0..full_blocks {
85            let self_block = self.get_raw_block(i);
86            let other_block = other.get_raw_block(i);
87            let combined_block = fun(self_block, other_block);
88            self.set_block(i, combined_block);
89        }
90
91        if extra_bits > 0 {
92            let self_block = self.get_block(full_blocks);
93            let other_block = other.get_block(full_blocks);
94            let combined_block = fun(self_block, other_block);
95            self.set_bits(bit_len - extra_bits as u64, extra_bits, combined_block);
96        }
97    }
98}
99
100impl<T: BitsMut> BitsMutExt for T {}
101
102#[cfg(test)]
103mod test {
104    use super::*;
105    use crate::{BitSliceable, BitSliceableMut, BitVec};
106    use alloc::vec;
107
108    #[test]
109    fn bit_and_assign() {
110        let mut bv1: BitVec = bit_vec![false, false, true, true];
111        let bv2: BitVec = bit_vec![false, true, true, false];
112
113        bv1.bit_and_assign(&bv2);
114        assert_eq!(bv1, bit_vec![false, false, true, false]);
115    }
116
117    #[test]
118    #[should_panic]
119    fn bit_and_assign_bad_sizes() {
120        let mut bv1: BitVec = bit_vec![false, false, true, true, true];
121        let bv2: BitVec = bit_vec![false, true, true, false];
122
123        bv1.bit_and_assign(&bv2);
124    }
125
126    #[test]
127    fn bit_xor_assign_slice() {
128        let mut v1 = vec![0b0000_1111_u8];
129        let v2 = [0b0101_0101_u8];
130
131        v1.bit_slice_mut(2..6).bit_xor_assign(v2.bit_slice(3..7));
132
133        assert_eq!(v1, vec![0b00100111])
134    }
135}