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}