mysqlbinlog_network/mysql_binlog/
bit_set.rs

1use std::error::Error;
2use std::fmt;
3
4/// A simple set implemented by using a bit-mask stored in sequential bytes (no word-level
5/// packing is done to maintain compatibility with MySQL's).
6///
7/// Could probably be replaced by one of the BitVec crates if any of them do the right thing.
8pub struct BitSet {
9    num_elems: usize,
10    inner: Vec<u8>,
11}
12
13impl fmt::Debug for BitSet {
14    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15        write!(f, "BitSet {{ num_elems: {} }}", self.num_elems)
16    }
17}
18
19#[derive(Debug)]
20pub enum BitSetError {
21    ItemOutOfRange,
22    SliceTooSmall,
23}
24
25impl fmt::Display for BitSetError {
26    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27        <Self as fmt::Debug>::fmt(self, f)
28    }
29}
30
31impl Error for BitSetError {
32    fn description(&self) -> &'static str {
33        "bitset error"
34    }
35}
36
37impl BitSet {
38    pub fn new(num_elems: usize) -> Self {
39        let vec_len = (num_elems + 7) >> 3;
40        BitSet {
41            num_elems,
42            inner: vec![0u8; vec_len],
43        }
44    }
45
46    pub fn from_slice(num_elems: usize, slice: &[u8]) -> Result<Self, BitSetError> {
47        let vec_len = (num_elems + 7) >> 3;
48        if slice.len() < vec_len {
49            return Err(BitSetError::SliceTooSmall);
50        }
51        Ok(BitSet {
52            num_elems,
53            inner: slice[0..vec_len].to_owned(),
54        })
55    }
56
57    fn get_byte_offset(&self, item: usize) -> usize {
58        if item >= self.num_elems {
59            panic!(
60                "attempted to index bit_set out of range: {} >= {}",
61                item, self.num_elems
62            );
63        }
64        item >> 3
65    }
66
67    pub fn set_value(&mut self, item: usize, value: bool) -> () {
68        let offset = self.get_byte_offset(item);
69        if value {
70            self.inner[offset] |= 1 << (item & 0x07);
71        } else {
72            self.inner[offset] &= !(1 << (item & 0x07));
73        }
74        ()
75    }
76
77    pub fn set(&mut self, item: usize) -> () {
78        self.set_value(item, true)
79    }
80
81    pub fn unset(&mut self, item: usize) -> () {
82        self.set_value(item, false)
83    }
84
85    pub fn is_set(&self, item: usize) -> bool {
86        let byte = self.inner[self.get_byte_offset(item)];
87        byte & (1 << (item & 0x07)) != 0
88    }
89
90    pub fn as_vec(&self) -> Vec<bool> {
91        let mut out = Vec::new();
92        for i in 0..self.num_elems {
93            out.push(self.is_set(i));
94        }
95        out
96    }
97
98    pub fn bits_set(&self) -> usize {
99        self.inner.iter().map(|c| c.count_ones() as usize).sum()
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::BitSet;
106
107    #[test]
108    fn test_basic() {
109        assert_eq!(BitSet::new(24).inner.len(), 3);
110        assert_eq!(BitSet::new(25).inner.len(), 4);
111        let mut b = BitSet::new(25);
112        for i in 0..25 {
113            assert!(!b.is_set(i));
114        }
115        b.set(0);
116        assert!(b.is_set(0));
117        for i in 1..25 {
118            assert!(!b.is_set(i));
119        }
120        b.set(20);
121        assert!(!b.is_set(19));
122        assert!(b.is_set(20));
123        assert!(!b.is_set(21));
124        assert_eq!(b.bits_set(), 2);
125    }
126
127    #[test]
128    fn test_from_slice() {
129        let b = BitSet::from_slice(9, &[255u8, 0u8]).expect("should construct");
130        assert!(b.is_set(0));
131        assert!(!b.is_set(8));
132    }
133}