prime_data/data/prime_byte.rs
1//! Module dedicated to the PrimeByte struct
2
3use std::ops::RangeInclusive;
4use super::K_VALUES;
5
6/// A "byte of primes", a chunk of 8 bits corresponding to the 8 values in the (0..30) range
7/// that are not divisible by 2, 3, or 5. Those values are also called **k-values**.
8///
9/// To learn more, read the [guide](crate::guide::data_structure::_1_prime_byte).
10///
11/// "k-values" are values k, such that (N % 30 = k) and N is coprime with 30. Those values
12/// are listed [here](crate::data::K_VALUES).
13#[derive(Clone, Copy, PartialEq, Eq)]
14pub struct PrimeByte {
15 byte: u8,
16}
17
18impl PrimeByte {
19 /// Creates a new byte, setting all k-values as prime
20 ///
21 /// # Examples
22 ///
23 /// ```
24 /// use prime_data::PrimeByte;
25 /// let byte = PrimeByte::new();
26 /// assert_eq!(u8::from(byte), 0b11111111);
27 /// ```
28 pub fn new() -> Self {
29 Self { byte: 255 }
30 }
31
32 /// Sets one of the bits to non-prime/composite based on the k-value
33 ///
34 /// If the bit was already set to non-prime, returns false. Otherwise, returns true.
35 ///
36 /// Returns an [OutOfBounds](crate::error::ErrorType::OutOfBounds) error if
37 /// the given value is not a k-value, returns an error.
38 ///
39 /// To understand what k-value maps to what bit, refer to the [k-values](crate::data::K_VALUES)
40 ///
41 /// # Examples
42 ///
43 /// ```
44 /// use prime_data::PrimeByte;
45 ///
46 /// let mut byte = PrimeByte::from(0b10110111);
47 /// // k-value 1 corresponds to the first bit
48 /// // returns Ok(true) because the first bit was indeed, a one
49 /// assert!(byte.set_nonprime(1).unwrap());
50 /// assert_eq!(byte.as_u8(), 0b00110111);
51 /// // now, if we try to set it to non-prime again, it'll return false,
52 /// // because it's already a zero
53 /// assert!(!byte.set_nonprime(1).unwrap());
54 /// // when given a non-k-value, returns an error
55 /// assert!(byte.set_nonprime(4).is_err());
56 /// ```
57 pub fn set_nonprime(&mut self, k_value: u8) -> Result<bool, ()> {
58 if let Ok(index) = K_VALUES.binary_search(&k_value) {
59
60 let bit = self.byte >> (7 - index);
61 let is_prime = Self::is_one(bit);
62
63 if is_prime {
64 self.byte -= 1 << (7 - index);
65 Ok(true)
66 } else {
67 Ok(false)
68 }
69
70 } else {
71 Err(())
72 }
73 }
74
75 /// Converts the bits into boolean entries
76 ///
77 /// # Examples
78 ///
79 /// ```
80 /// use prime_data::PrimeByte;
81 /// let byte = PrimeByte::from(0b10100110);
82 /// assert_eq!(
83 /// byte.as_boolean_array(),
84 /// [true, false, true, false, false, true, true, false]
85 /// );
86 /// ```
87 pub fn as_boolean_array(&self) -> [bool; 8] {
88
89 let byte = self.byte;
90
91 [7, 6, 5, 4, 3, 2, 1, 0]
92 .map(|shr| PrimeByte::is_one(byte >> shr))
93 }
94
95 /// Retrieves all bits set to one and converts them into their respective k-values
96 ///
97 /// For more information, read the [guide](crate::guide::data_structure::_1_prime_byte), or refer to the
98 /// list of [k-values](crate::data::K_VALUES).
99 ///
100 /// If you wish to retrieve k-values within a specific range, see [`PrimeByte::as_k_values_in_range`].
101 ///
102 /// # Examples
103 ///
104 /// ```
105 /// use prime_data::PrimeByte;
106 /// let byte = PrimeByte::from(0b10100110);
107 /// assert_eq!(
108 /// byte.as_k_values(),
109 /// vec![1, 11, 19, 23]
110 /// );
111 /// ```
112 pub fn as_k_values(&self) -> Vec<u8> {
113 self.as_boolean_array().iter()
114 .zip(K_VALUES.iter())
115 .filter(|(&is_prime, _)| is_prime)
116 .map(|(_, &k_value)| k_value)
117 .collect()
118 }
119
120 /// Retrieves all bits set to one and converts them into their respective k-values,
121 /// as long as they fall inside the inclusive range
122 ///
123 /// For more information, read the [guide](crate::guide::data_structure::_1_prime_byte), or refer to the
124 /// list of [k-values](crate::data::K_VALUES).
125 ///
126 /// If you wish to retrieve all k-values, see [`PrimeByte::as_k_values`].
127 ///
128 /// # Examples
129 ///
130 /// ```
131 /// use prime_data::PrimeByte;
132 /// let byte = PrimeByte::from(0b10100110);
133 /// assert_eq!(
134 /// byte.as_k_values_in_range(2..=23),
135 /// vec![11, 19, 23]
136 /// );
137 /// ```
138 pub fn as_k_values_in_range(&self, range: RangeInclusive<u8>) -> Vec<u8> {
139 self.as_boolean_array().iter()
140 .zip(K_VALUES.iter())
141 .filter(|(&is_prime, k_value)| is_prime && range.contains(k_value))
142 .map(|(_, &k_value)| k_value)
143 .collect()
144 }
145
146 /// Retrieves the k-values and converts them to actual prime numbers.
147 ///
148 /// For more information, read the [guide](crate::guide::data_structure::_1_prime_byte).
149 ///
150 /// Calling this function with `offset = 1` yields the same results as [`PrimeByte::as_k_values`],
151 /// except that it returns a vector of [`u64`] instead of [`u8`].
152 ///
153 /// If you wish to only retrieve primes within a range, see [`PrimeByte::as_primes_in_range`]
154 ///
155 /// # Examples
156 ///
157 /// ```
158 /// use prime_data::PrimeByte;
159 /// let byte = PrimeByte::from(0b10100110);
160 /// assert_eq!(
161 /// byte.as_primes(21),
162 /// vec![631, 641, 649, 653]
163 /// );
164 /// ```
165 pub fn as_primes(&self, offset: u64) -> Vec<u64> {
166 self.as_boolean_array().iter()
167 .zip(K_VALUES.iter())
168 .filter(|(&is_prime, _)| is_prime)
169 .map(|(_, &k_value)| 30 * offset + (k_value as u64))
170 .collect()
171 }
172
173 /// Retrieves the k-values, as long as they fall inside the inclusive range,
174 /// and converts them to actual prime numbers
175 ///
176 /// Calling this function with `offset = 1` yields the same results as
177 /// [`PrimeByte::as_k_values_in_range`], except that it returns a vector of [`u64`] instead of [`u8`].
178 ///
179 /// If you wish to retrieve all primes, see [`PrimeByte::as_primes`]
180 ///
181 /// # Examples
182 ///
183 /// ```
184 /// use prime_data::PrimeByte;
185 /// let byte = PrimeByte::from(0b10100110);
186 /// assert_eq!(
187 /// byte.as_primes_in_range(21, 2..=23),
188 /// vec![641, 649, 653]
189 /// );
190 /// ```
191 pub fn as_primes_in_range(&self, offset: u64, range: RangeInclusive<u8>) -> Vec<u64> {
192 self.as_boolean_array().iter()
193 .zip(K_VALUES.iter())
194 .filter(|(&is_prime, k_value)| is_prime && range.contains(k_value))
195 .map(|(_, &k_value)| 30 * offset + (k_value as u64))
196 .collect()
197 }
198
199 /// Overwrites the bits in this byte with the bits in the other byte, from a given position
200 ///
201 /// The position should be a bit index in the range (0..=7), 0 meaning it'll overwrite the
202 /// entire byte with the given one.
203 ///
204 /// This function is useful for joining two data structures of Prime Bytes, as most of the time
205 /// the former's end and the latter's start intersect in the middle of a prime byte. That way,
206 /// we overwrite the byte at the intersection.
207 ///
208 /// # Panics
209 ///
210 /// Panics if `position > 7`
211 ///
212 /// # Examples
213 ///
214 /// ```
215 /// use prime_data::PrimeByte;
216 /// let mut original = PrimeByte::from(0b00000000);
217 /// let new_bits = PrimeByte::from(0b11111111);
218 /// original.overwrite_at(new_bits, 5);
219 /// assert_eq!(
220 /// u8::from(original),
221 /// 0b00000111
222 /// );
223 /// ```
224 pub fn overwrite_at(&mut self, overwriting: Self, position: u8) {
225
226 self.byte = if position == 0 {
227 overwriting.byte
228 } else {
229 let clear_byte = (self.byte >> (8 - position)) << (8 - position);
230 let new_bits = (overwriting.byte << position) >> position;
231
232 clear_byte + new_bits
233 }
234
235 }
236
237 /// Vefifies if the given `x` is prime, based on the [k-values](crate::data::K_VALUES)
238 ///
239 /// **Warning**: It will return false for 2, 3, and 5. So take care of those cases
240 /// before you call this function.
241 ///
242 /// **Second Warning**: Will return false for values above 29. So always make sure to
243 /// apply modulo 30 when calling this function.
244 ///
245 /// # Examples
246 ///
247 /// ```
248 /// use prime_data::PrimeByte;
249 /// let byte = PrimeByte::from(0b00101000);
250 /// assert!( byte.is_prime(11));
251 /// assert!(!byte.is_prime(13));
252 /// assert!( byte.is_prime(17));
253 /// ```
254 pub fn is_prime(&self, x: u8) -> bool {
255 if let Some(thing) = self.as_boolean_array().iter()
256 .zip(K_VALUES.iter())
257 .find(|(_, &k_value)| k_value == x)
258 {
259 *thing.0
260 } else {
261 false
262 }
263 }
264
265 /// Counts the number of primes (a.k.a the number of ones) it has.
266 ///
267 /// If you wish to count primes in a specific range, see [`PrimeByte::count_primes_in_range`]
268 ///
269 /// # Examples
270 ///
271 /// ```
272 /// use prime_data::PrimeByte;
273 /// let byte = PrimeByte::from(0b11010111);
274 /// assert_eq!(byte.count_primes(), 6);
275 /// ```
276 pub fn count_primes(&self) -> u64 {
277 self.byte.count_ones() as u64
278 }
279
280 /// Counts the number of primes it has as long as their k-values fall within the range
281 ///
282 /// If you wish to count all primes, see [`PrimeByte::count_primes`]
283 ///
284 /// # Examples
285 ///
286 /// ```
287 /// use prime_data::PrimeByte;
288 /// let byte = PrimeByte::from(0b11010111);
289 /// assert_eq!(byte.count_primes_in_range(0..=30), 6);
290 /// assert_eq!(byte.count_primes_in_range(2..=30), 5);
291 /// assert_eq!(byte.count_primes_in_range(8..=12), 0);
292 /// ```
293 pub fn count_primes_in_range(&self, range: RangeInclusive<u8>) -> u64 {
294 self.as_boolean_array().iter()
295 .zip(K_VALUES.iter())
296 .filter(|(&is_prime, k_value)| is_prime && range.contains(k_value))
297 .count() as u64
298 }
299
300 /// Converts byte into a u8
301 ///
302 /// This has the same effect as calling `u8::from()`. It's meant to be an alternative way
303 /// of converting into a u8, having the byte be written on the left instead of right.
304 ///
305 /// # Examples
306 ///
307 /// ```
308 /// use prime_data::PrimeByte;
309 /// let byte = PrimeByte::new();
310 /// assert_eq!(byte.as_u8(), u8::from(byte))
311 /// ```
312 pub fn as_u8(&self) -> u8 {
313 self.byte
314 }
315
316 /// Compares two bytes to see if their bits match in the given k-value range
317 ///
318 /// Range is expected to be within (0..=30), but it will not return an error or panic, if given
319 /// anything above 30. If you pass it some range like (30..=199), since none of the bits fall in
320 /// that range, none will be compared, and hence the function will trivially return true.
321 ///
322 /// There is no `Self::matches` method (without a range restriction) because that's the same as
323 /// verifying if the two bytes are equal. PrimeByte implements [`Eq`].
324 ///
325 /// # Examples
326 ///
327 /// ```
328 /// use prime_data::PrimeByte;
329 /// let byte = PrimeByte::from(0b10111010);
330 /// let other = PrimeByte::from(0b10110111);
331 /// assert!( byte.matches_in_range(other, 0..=14));
332 /// assert!( byte.matches_in_range(other, 23..=23));
333 /// assert!(!byte.matches_in_range(other, 16..=17));
334 /// assert!( byte.matches_in_range(other, 30..=255));
335 /// ```
336 pub fn matches_in_range(&self, other: PrimeByte, range: RangeInclusive<u8>) -> bool {
337 self.as_boolean_array().iter()
338 .zip(other.as_boolean_array().iter())
339 .zip(K_VALUES.iter())
340 .filter(|(_, k_value)| range.contains(k_value))
341 .fold(true, |acc, (cur, _)| acc && (cur.0 == cur.1))
342 }
343
344 fn is_one(bit: u8) -> bool {
345 bit % 2 == 1
346 }
347}
348
349impl From<u8> for PrimeByte {
350 fn from(byte: u8) -> PrimeByte {
351 PrimeByte { byte }
352 }
353}
354
355impl From<PrimeByte> for u8 {
356 fn from(byte: PrimeByte) -> u8 {
357 byte.byte
358 }
359}
360
361use std::fmt;
362impl fmt::Display for PrimeByte {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 write!(f, "|{:08b}|", self.byte)
365 }
366}
367
368impl fmt::Debug for PrimeByte {
369 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370 fmt::Display::fmt(self, f)
371 }
372}