bitarray_naive/
lib.rs

1#![allow(dead_code, unused_variables)]
2
3use std::fmt;
4
5use serde::{Deserialize, Serialize};
6
7/// A constant to describe the number of bits in one byte.
8/// Defined just to improve readability.
9const ONE_BYTE_BITS_COUNT: i8 = 8;
10
11/// Struct represents a custom error that should be raised every time
12/// a user tries to access or set the bit in the array that is out of this bit array size.
13#[derive(Clone, Debug)]
14pub struct OutOfRangeError {
15    pub bitarray_size: i64,
16    pub bitarray_position: i64,
17}
18
19impl OutOfRangeError {
20    /// Constructor used to initialize a new OutOfRangeError with a given bitarray_size and bitarray_position.
21    /// "bitarray_size" - The size in bits of the bitarray where the error was raised.
22    /// "bitarray_position" - The wrong position caused an error.
23    pub fn new(bitarray_size: i64, bitarray_position: i64) -> Self {
24        Self {
25            bitarray_size,
26            bitarray_position,
27        }
28    }
29}
30
31impl fmt::Display for OutOfRangeError {
32    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33        write!(
34            f,
35            "Given position: {} is out of the bitarray size {}.",
36            self.bitarray_position, self.bitarray_size
37        )
38    }
39}
40
41/// A structure aimed to bring the bitarray functionality.
42/// Structure is described within two fields.
43/// "size" - The number of bits that will be allocated during the
44///          struct instance initialization.
45/// "bit_array" - The vector of 8 bit integer used to represent bits
46///               where each 8 bits are packed in every 8 bit integer.
47/// ```rust
48/// use bitarray_naive::BitArray;
49///
50/// let bitarray_size: i64 = 9999;
51///
52/// let mut bitarray: BitArray = BitArray::new(bitarray_size);
53///
54/// bitarray.set(12, true).unwrap();
55///
56/// assert_eq!(bitarray.get(12).unwrap(), true);
57/// ```
58#[derive(Debug, Serialize, Deserialize)]
59pub struct BitArray {
60    pub size: i64,
61    pub bit_array: Vec<u8>,
62}
63
64impl BitArray {
65    /// Constructor used to initialize a new instance of the bitarray with a given size.
66    /// "size" - The number of bits that will be allocated during the
67    ///          struct instance initialization.
68    pub fn new(size: i64) -> Self {
69        // Calculates the number of elements should be allocated in vector per given size
70        let _capacity: usize = (size / ONE_BYTE_BITS_COUNT as i64) as usize + 1;
71
72        let mut bit_array: Vec<u8> = Vec::with_capacity(_capacity);
73
74        // Initialize vector with default 0 values. Where each value equal to 8 false bits.
75        for _ in 0.._capacity {
76            bit_array.push(0);
77        }
78
79        Self { size, bit_array }
80    }
81
82    /// Calculates the element in bit array vector should be picked per given bit position.
83    /// In other words, calculates the index in bitarray vector.
84    fn calc_vec_position(position: i64) -> usize {
85        (position / ONE_BYTE_BITS_COUNT as i64) as usize
86    }
87
88    /// Calculates the bit offset (position) in a given 8 bit integer.
89    /// The position should be counted from right to left.
90    fn calc_byte_offset(position: i64) -> u8 {
91        let _pow: i64 = position % ONE_BYTE_BITS_COUNT as i64;
92
93        2u64.pow(_pow as u32) as u8
94    }
95
96    /// Sets either true or false value in bit array at given position.
97    pub fn set(&mut self, position: i64, flag: bool) -> Result<(), OutOfRangeError> {
98        if position >= self.size {
99            Err(OutOfRangeError::new(self.size, position as i64))
100        } else {
101            let vec_position: usize = Self::calc_vec_position(position);
102            let byte_offset: u8 = Self::calc_byte_offset(position);
103
104            if flag {
105                self.bit_array[vec_position] |= byte_offset;
106            } else {
107                self.bit_array[vec_position] &= !byte_offset;
108            }
109
110            Ok(())
111        }
112    }
113
114    /// Gets either true or false value in bit array at given position.
115    pub fn get(&self, position: i64) -> Result<bool, OutOfRangeError> {
116        if position >= self.size {
117            Err(OutOfRangeError::new(self.size, position))
118        } else {
119            let vec_position: usize = Self::calc_vec_position(position);
120            let byte_offset: u8 = Self::calc_byte_offset(position);
121
122            Ok(self.bit_array[vec_position] == (self.bit_array[vec_position] | byte_offset))
123        }
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::{BitArray, ONE_BYTE_BITS_COUNT};
130
131    #[test]
132    fn test_init_bitarray() {
133        // Bit array size is a number of bits that will be allocated
134        // in a given bitarray.
135        // Bit array based on the vector of u8 integers
136        // Each u8 integer occupy 8 bits of memory.
137        // So the bitarray's vector should be of bitarray_size size / 8 size.
138        let bitarray_size: i64 = 10;
139
140        let bitarray: BitArray = BitArray::new(bitarray_size);
141
142        assert_eq!(
143            bitarray.bit_array.len(),
144            (bitarray_size / ONE_BYTE_BITS_COUNT as i64) as usize + 1
145        );
146        assert_eq!(bitarray.bit_array.len(), 2);
147    }
148
149    #[test]
150    fn test_bitarray_set_true() {
151        let bitarray_size: i64 = 10;
152        let bitarray_position: i64 = 9;
153
154        let mut bitarray: BitArray = BitArray::new(bitarray_size);
155
156        let success: bool = match bitarray.set(bitarray_position, true) {
157            Ok(_) => true,
158            Err(_) => false,
159        };
160
161        assert!(success);
162    }
163
164    #[test]
165    fn test_bitarray_set_with_error() {
166        let bitarray_size: i64 = 10;
167        let bitarray_position: i64 = 10;
168
169        let mut bitarray: BitArray = BitArray::new(bitarray_size);
170
171        let success: bool = match bitarray.set(bitarray_position, true) {
172            Ok(_) => false,
173            Err(err) => {
174                err.bitarray_position == 10
175                    && err.bitarray_size == 10
176                    && format!("{}", err) == "Given position: 10 is out of the bitarray size 10."
177            }
178        };
179
180        assert!(success);
181    }
182
183    #[test]
184    fn test_bitarray_get_with_error() {
185        let bitarray_size: i64 = 10;
186        let bitarray_position: i64 = 10;
187
188        let bitarray: BitArray = BitArray::new(bitarray_size);
189
190        let success: bool = match bitarray.get(bitarray_position) {
191            Ok(_) => false,
192            Err(err) => {
193                err.bitarray_position == 10
194                    && err.bitarray_size == 10
195                    && format!("{}", err) == "Given position: 10 is out of the bitarray size 10."
196            }
197        };
198
199        assert!(success);
200    }
201
202    #[test]
203    fn test_bit_array_get_set() {
204        let bitarray_size: i64 = 74845;
205
206        let mut bitarray: BitArray = BitArray::new(bitarray_size);
207
208        for bitarray_position in 0..bitarray_size - 1 {
209            assert!(!bitarray.get(bitarray_position).unwrap());
210        }
211
212        for bitarray_position in 0..bitarray_size {
213            bitarray.set(bitarray_position, true).unwrap();
214
215            assert!(bitarray.get(bitarray_position).unwrap());
216        }
217
218        for bitarray_position in 0..bitarray_size - 1 {
219            assert!(bitarray.get(bitarray_position).unwrap());
220        }
221
222        for bitarray_position in 0..bitarray_size {
223            bitarray.set(bitarray_position, false).unwrap();
224
225            assert!(!bitarray.get(bitarray_position).unwrap());
226        }
227
228        for bitarray_position in 0..bitarray_size - 1 {
229            assert!(!bitarray.get(bitarray_position).unwrap());
230        }
231    }
232}