brainfoamkit_lib/
nybble.rs

1// SPDX-FileCopyrightText: 2023 - 2024 Ali Sajid Imami
2//
3// SPDX-License-Identifier: Apache-2.0
4// SPDX-License-Identifier: MIT
5
6use std::{
7    fmt::{
8        self,
9        Display,
10        Formatter,
11    },
12    ops::{
13        BitAnd,
14        BitAndAssign,
15        BitOr,
16        BitOrAssign,
17        BitXor,
18        BitXorAssign,
19        Not,
20    },
21};
22
23use crate::{
24    Bit,
25    IterableNybble,
26};
27
28/// A Nybble is a 4-bit unsigned integer (u4).
29///
30/// This is a wrapper around four Bit instances. The least significant bit is
31/// `bit_0` and the most significant bit is `bit_3`. This struct is used to
32/// conveniently manipulate 4-bit values.
33///
34/// Note that bit instances are stored in reverse (LSB is first, MSB is last)
35/// order, so the least significant bit is `bit_0` and the most significant bit
36/// is `bit_3`. However, the [`new`](#method.new) method takes the bits in the
37/// correct (MSB is first, LSB is last) order.
38///
39///
40///
41/// # Examples
42///
43/// ## Create a Nybble from primitive Bit values
44///
45/// ```
46/// use brainfoamkit_lib::{
47///     Bit,
48///     Nybble,
49/// };
50///
51/// let nybble = Nybble::new(Bit::One, Bit::Zero, Bit::One, Bit::Zero);
52/// assert_eq!(u8::from(&nybble), 0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
53/// assert_eq!(nybble.to_string(), "0xA");
54/// ```
55///
56/// ## Create a Nybble from a u8 value
57///
58/// ```
59/// use brainfoamkit_lib::Nybble;
60///
61/// let nybble = Nybble::from(0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
62/// assert_eq!(u8::from(&nybble), 0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
63/// assert_eq!(nybble.to_string(), "0xA");
64/// ```
65///
66/// ## Set and Unset bits to generate the desired Nybble
67///
68/// ```
69/// use brainfoamkit_lib::Nybble;
70///
71/// let mut nybble = Nybble::default();
72/// nybble.set_bit(0); // Nybble: 0b0001; Dec: 1; Hex: 0x1; Oct: 0o1
73/// nybble.set_bit(2); // Nybble: 0b0101; Dec: 5; Hex: 0x5; Oct: 0o5
74///
75/// assert_eq!(u8::from(&nybble), 0b0101); // Dec: 5; Hex: 0x5; Oct: 0o5
76/// assert_eq!(nybble.to_string(), "0x5");
77/// ```
78///
79/// ## Flip the bits at a given index
80///
81/// ```
82/// use brainfoamkit_lib::Nybble;
83///
84/// let mut nybble = Nybble::from(0b0101); // Dec: 5; Hex: 0x5; Oct: 0o5
85/// nybble.flip_bit(0); // Nybble: 0b0100; Dec: 4; Hex: 0x4; Oct: 0o4
86/// nybble.flip_bit(1); // Nybble: 0b0110; Dec: 6; Hex: 0x6; Oct: 0o6
87///
88/// assert_eq!(u8::from(&nybble), 0b0110); // Dec: 6; Hex: 0x6; Oct: 0o6
89/// assert_eq!(nybble.to_string(), "0x6");
90/// ```
91///
92/// # Panics
93///
94/// The methods [`set_bit()`](#method.set_bit),
95/// [`unset_bit()`](#method.unset_bit) and [`get_bit()`](#method.get_bit) will
96/// panic if the index is out of bounds.
97///
98/// # See Also
99///
100/// * [`Bit`](crate::Bit): The building block of a Nybble.
101/// * [`Byte`](crate::Byte): A Byte is a collection of eight Bits.
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub struct Nybble {
104    /// The least significant bit.
105    bit_0: Bit,
106    /// The second least significant bit.
107    bit_1: Bit,
108    /// The second most significant bit.
109    bit_2: Bit,
110    /// The most significant bit.
111    bit_3: Bit,
112}
113
114impl Nybble {
115    /// Creates a new Nybble instance with the specified Bit values.
116    ///
117    /// This method takes four Bit instances as arguments.
118    /// The least significant bit is `bit_0` and the most significant bit is
119    /// `bit_3`.
120    ///
121    /// # Arguments
122    ///
123    /// * `first` - The most significant bit.
124    /// * `second` - The second most significant bit.
125    /// * `third` - The second least significant bit.
126    /// * `fourth` - The least significant bit.
127    ///
128    /// # Examples
129    ///
130    /// ```
131    /// use brainfoamkit_lib::{
132    ///     Bit,
133    ///     Nybble,
134    /// };
135    ///
136    /// let nybble = Nybble::new(Bit::One, Bit::Zero, Bit::One, Bit::Zero);
137    /// assert_eq!(u8::from(&nybble), 10);
138    /// assert_eq!(nybble.to_string(), "0xA");
139    /// ```
140    ///
141    /// # Returns
142    ///
143    /// A new Nybble with the specified Bit values.
144    ///
145    /// # See Also
146    ///
147    /// * [`from_u8()`](#method.from_u8): Creates a new Nybble from a u8 value.
148    /// * [`default()`](#method.default): Creates a new Nybble with default (all
149    ///   [`Bit::Zero`](crate::Bit::Zero)) Bit values.
150    #[must_use]
151    pub const fn new(first: Bit, second: Bit, third: Bit, fourth: Bit) -> Self {
152        Self {
153            bit_0: fourth, // Least significant bit
154            bit_1: third,
155            bit_2: second,
156            bit_3: first, // Most Significant Bit
157        }
158    }
159
160    /// Sets the Bit value at the specified index.
161    ///
162    /// This method is used "Set" the bit value at a given index.
163    /// This means that that bit value is set to 1.
164    ///
165    /// The index is zero-based, so the least significant bit is at index 0 and
166    /// the most significant bit is at index 3.
167    ///
168    /// # Arguments
169    ///
170    /// * `index` - The index of the Bit value to set.
171    ///
172    /// # Examples
173    ///
174    /// ```
175    /// use brainfoamkit_lib::{
176    ///     Bit,
177    ///     Nybble,
178    /// };
179    ///
180    /// let mut nybble = Nybble::default();
181    /// nybble.set_bit(0);
182    /// nybble.set_bit(2);
183    /// assert_eq!(u8::from(&nybble), 0b0101); // Dec: 5; Hex: 0x5; Oct: 0o5
184    /// assert_eq!(nybble.to_string(), "0x5");
185    /// ```
186    ///
187    /// # Side Effects
188    ///
189    /// This method will [set](crate::Bit#method.set) the Bit value at the
190    /// specified index.
191    ///
192    /// # Panics
193    ///
194    /// This method will panic if the index is out of bounds.
195    ///
196    /// # See Also
197    ///
198    /// * [`unset_bit()`](#method.unset_bit): Unsets the Bit value at the
199    ///   specified index.
200    /// * [`get_bit()`](#method.get_bit): Gets the Bit value at the specified
201    ///   index.
202    /// * [`flip_bit()`](#method.flip_bit): Flips the Bit value at the specified
203    ///   index.
204    pub fn set_bit(&mut self, index: u8) {
205        match index {
206            0 => self.bit_0.set(),
207            1 => self.bit_1.set(),
208            2 => self.bit_2.set(),
209            3 => self.bit_3.set(),
210            _ => panic!("Index out of bounds"),
211        }
212    }
213
214    /// Unsets the Bit value at the specified index.
215    ///
216    /// This method is used "Unset" the bit value at a given index.
217    /// This means that that bit value is set to 0.
218    ///
219    /// The index is zero-based, so the least significant bit is at index 0 and
220    /// the most significant bit is at index 3.
221    ///
222    /// # Arguments
223    ///
224    /// * `index` - The index of the Bit value to unset.
225    ///
226    /// # Examples
227    ///
228    /// ```
229    /// use brainfoamkit_lib::Nybble;
230    /// use brainfoamkit_lib::Bit;
231    ///
232    /// let mut nybble = Nybble::default(); // Nybble: 0b0000; Dec: 0; Hex: 0x0; Oct: 0o0
233    /// nybble.set_bit(0); // Nybble: 0b0001; Dec: 1; Hex: 0x1; Oct: 0o1
234    /// nybble.set_bit(2); // Nybble: 0b0101; Dec: 5; Hex: 0x5; Oct: 0o5
235    /// assert_eq!(u8::from(&nybble), 0b0101); // Dec: 5; Hex: 0x5; Oct: 0o5
236    /// assert_eq!(nybble.to_string(), "0x5");
237    /// nybble.unset_bit(0); // Nybble: 0b0100; Dec: 4; Hex: 0x4; Oct: 0o4
238    /// assert_eq!(u8::from(&nybble), 4); // Dec: 4; Hex: 0x4; Oct: 0o4
239    /// assert_eq!(nybble.to_string(), "0x4");
240    /// ```
241    ///
242    /// # Side Effects
243    ///
244    /// This method will [unset](crate::Bit#method.unset) the Bit value at the
245    /// specified index.
246    ///
247    /// # Panics
248    ///
249    /// This method will panic if the index is out of bounds.
250    ///
251    /// # See Also
252    ///
253    /// * [`set_bit()`](#method.set_bit): Sets the Bit value at the specified
254    ///   index.
255    /// * [`get_bit()`](#method.get_bit): Gets the Bit value at the specified
256    ///   index.
257    /// * [`flip_bit()`](#method.flip_bit): Flips the Bit value at the specified
258    ///   index.
259    pub fn unset_bit(&mut self, index: u8) {
260        match index {
261            0 => self.bit_0.unset(),
262            1 => self.bit_1.unset(),
263            2 => self.bit_2.unset(),
264            3 => self.bit_3.unset(),
265            _ => panic!("Index out of bounds"),
266        }
267    }
268
269    /// Get the Bit value at the specified index.
270    ///
271    /// This method is used to get the bit value at a given index.
272    ///
273    /// The index is zero-based, so the least significant bit is at index 0 and
274    /// the most significant bit is at index 3.
275    ///
276    /// # Arguments
277    ///
278    /// * `index` - The index of the Bit value to get.
279    ///
280    /// # Examples
281    ///
282    /// ```
283    /// use brainfoamkit_lib::Nybble;
284    /// use brainfoamkit_lib::Bit;
285    ///
286    /// let nybble = Nybble::new(Bit::One, Bit::Zero, Bit::One, Bit::Zero); // Dec: 10; Hex: 0xA; Oct: 0o12
287    /// assert_eq!(nybble.get_bit(0), Bit::Zero);
288    /// assert_eq!(nybble.get_bit(1), Bit::One);
289    /// assert_eq!(nybble.get_bit(2), Bit::Zero);
290    /// assert_eq!(nybble.get_bit(3), Bit::One);
291    /// ```
292    ///
293    /// # Panics
294    ///
295    /// This method will panic if the index is out of bounds.
296    ///
297    /// # Returns
298    ///
299    /// The Bit value at the specified index.
300    ///
301    /// # See Also
302    ///
303    /// * [`set_bit()`](#method.set_bit): Sets the Bit value at the specified
304    ///   index.
305    /// * [`unset_bit()`](#method.unset_bit): Unsets the Bit value at the
306    ///   specified index.
307    /// * [`flip_bit()`](#method.flip_bit): Flips the Bit value at the specified
308    ///   index.
309    #[must_use]
310    pub fn get_bit(&self, index: u8) -> Bit {
311        match index {
312            0 => self.bit_0,
313            1 => self.bit_1,
314            2 => self.bit_2,
315            3 => self.bit_3,
316            _ => panic!("Index out of bounds"),
317        }
318    }
319
320    /// Get a reference to the Bit value at the specified index.
321    ///
322    /// This method is used to get a reference to the bit value at a given
323    /// index.
324    ///
325    /// The index is zero-based, so the least significant bit is at index 0 and
326    /// the most significant bit is at index 3.
327    ///
328    /// # Arguments
329    ///
330    /// * `index` - The index of the Bit value to get.
331    ///
332    /// # Examples
333    ///
334    /// ```
335    /// use brainfoamkit_lib::Nybble;
336    /// use brainfoamkit_lib::Bit;
337    ///
338    /// let one = Bit::one();
339    /// let zero = Bit::zero();
340    ///
341    /// let nybble = Nybble::new(Bit::One, Bit::Zero, Bit::One, Bit::Zero); // Dec: 10; Hex: 0xA; Oct: 0o12
342    /// assert_eq!(nybble.get_bit_ref(0), &zero);
343    /// assert_eq!(nybble.get_bit_ref(1), &one);
344    /// assert_eq!(nybble.get_bit_ref(2), &zero);
345    /// assert_eq!(nybble.get_bit_ref(3), &one);
346    /// ```
347    ///
348    /// # Panics
349    ///
350    /// This method will panic if the index is out of bounds.
351    ///
352    /// # Returns
353    ///
354    /// A reference to the Bit value at the specified index.
355    ///
356    /// # See Also
357    ///
358    /// * [`set_bit()`](#method.set_bit): Sets the Bit value at the specified
359    ///   index.
360    /// * [`unset_bit()`](#method.unset_bit): Unsets the Bit value at the
361    ///   specified index.
362    /// * [`flip_bit()`](#method.flip_bit): Flips the Bit value at the specified
363    ///   index.
364    #[must_use]
365    pub fn get_bit_ref(&self, index: u8) -> &Bit {
366        match index {
367            0 => &self.bit_0,
368            1 => &self.bit_1,
369            2 => &self.bit_2,
370            3 => &self.bit_3,
371            _ => panic!("Index out of bounds"),
372        }
373    }
374
375    /// Flips the Bit value at the specified index.
376    ///
377    /// This method is used to flip the bit value at a given index.
378    /// This means that that bit value is set to the opposite of its current
379    /// value.
380    ///
381    /// The index is zero-based, so the least significant bit is at index 0 and
382    /// the most significant bit is at index 3.
383    ///
384    /// # Arguments
385    ///
386    /// * `index` - The index of the Bit value to flip.
387    ///
388    /// # Examples
389    ///
390    /// ```
391    /// use brainfoamkit_lib::Nybble;
392    /// use brainfoamkit_lib::Bit;
393    ///
394    /// let mut nybble = Nybble::default(); // Nybble: 0b0000; Dec: 0; Hex: 0x0; Oct: 0o0
395    /// nybble.set_bit(0); // Nybble: 0b0001; Dec: 1; Hex: 0x1; Oct: 0o1
396    /// nybble.set_bit(2); // Nybble: 0b0101; Dec: 5; Hex: 0x5; Oct: 0o5
397    ///
398    /// assert_eq!(u8::from(&nybble), 0b0101); // Dec: 5; Hex: 0x5; Oct: 0o5
399    /// assert_eq!(nybble.to_string(), "0x5");
400    ///
401    /// nybble.flip_bit(0); // Nybble: 0b0100; Dec: 4; Hex: 0x4; Oct: 0o4
402    /// nybble.flip_bit(1); // Nybble: 0b0110; Dec: 6; Hex: 0x6; Oct: 0o6
403    /// nybble.flip_bit(2); // Nybble: 0b0010; Dec: 2; Hex: 0x2; Oct: 0o2
404    /// nybble.flip_bit(3); // Nybble: 0b1010; Dec: 10; Hex: 0xA; Oct: 0o12
405    ///
406    /// assert_eq!(u8::from(&nybble), 10);
407    /// assert_eq!(nybble.to_string(), "0xA");
408    /// ```
409    ///
410    /// # Panics
411    ///
412    /// This method will panic if the index is out of bounds.
413    ///
414    /// # Side Effects
415    ///
416    /// This method will [flip](crate::Bit#method.flip) the Bit value at the
417    /// specified index.
418    ///
419    /// # See Also
420    ///
421    /// * [`set_bit()`](#method.set_bit): Sets the Bit value at the specified
422    ///   index.
423    /// * [`unset_bit()`](#method.unset_bit): Unsets the Bit value at the
424    ///   specified index.
425    /// * [`get_bit()`](#method.get_bit): Gets the Bit value at the specified
426    ///   index.
427    pub fn flip_bit(&mut self, index: u8) {
428        match index {
429            0 => self.bit_0.flip(),
430            1 => self.bit_1.flip(),
431            2 => self.bit_2.flip(),
432            3 => self.bit_3.flip(),
433            _ => panic!("Index out of bounds"),
434        }
435    }
436
437    /// Flips all of the Bit values in the Nybble.
438    ///
439    /// This method is used to flip all of the bit values in the Nybble.
440    /// This means that all of the bit values are set to the opposite of their
441    /// current values. This can be used to find the two's complement of a
442    /// Nybble.
443    ///
444    /// # Examples
445    ///
446    /// ```
447    /// use brainfoamkit_lib::Nybble;
448    /// use brainfoamkit_lib::Bit;
449    ///
450    /// let mut nybble = Nybble::default(); // Nybble: 0b0000; Dec: 0; Hex: 0x0; Oct: 0o0
451    ///
452    /// nybble.set_bit(0); // Nybble: 0b0001; Dec: 1; Hex: 0x1; Oct: 0o1
453    /// nybble.set_bit(2); // Nybble: 0b0101; Dec: 5; Hex: 0x5; Oct: 0o5
454    ///
455    /// assert_eq!(u8::from(&nybble), 0b0101); // Dec: 5; Hex: 0x5; Oct: 0o5
456    /// assert_eq!(nybble.to_string(), "0x5");
457    ///
458    /// nybble.flip(); // Nybble: 0b1010; Dec: 10; Hex: 0xA; Oct: 0o12
459    ///
460    /// assert_eq!(u8::from(&nybble), 0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
461    /// assert_eq!(nybble.to_string(), "0xA");
462    /// ```
463    ///
464    /// # Side Effects
465    ///
466    /// This method will [flip](crate::Bit#method.flip) all of the Bit values in
467    /// the Nybble.
468    ///
469    /// # See Also
470    ///
471    /// * [`flip_bit()`](#method.flip_bit): Flips the Bit value at the specified
472    ///   index.
473    pub fn flip(&mut self) {
474        self.bit_0.flip();
475        self.bit_1.flip();
476        self.bit_2.flip();
477        self.bit_3.flip();
478    }
479
480    /// Increment the Nybble with rollover overflow
481    ///
482    /// This method increments the value stored in the Nybble.
483    /// This has a rollover for overflow. This means that if we increment past
484    /// the maximum value (15), we will go back to 0.
485    ///
486    /// # Examples
487    ///
488    /// ## Regular Use
489    ///
490    /// ```
491    /// use brainfoamkit_lib::Nybble;
492    ///
493    /// let mut nybble = Nybble::default(); // Nybble: 0b0000; Dec: 0; Hex: 0x0; Oct: 0o0
494    ///
495    /// nybble.increment();
496    /// assert_eq!(u8::from(&nybble), 1);
497    /// assert_eq!(nybble.to_string(), "0x1");
498    ///
499    /// nybble.increment();
500    /// assert_eq!(u8::from(&nybble), 2);
501    /// assert_eq!(nybble.to_string(), "0x2");
502    /// ```
503    ///
504    /// ## Overflow Use
505    ///
506    /// ```
507    /// use brainfoamkit_lib::Nybble;
508    ///
509    /// let mut nybble = Nybble::from(15); // Nybble: 0b1111; Dec: 15; Hex: 0xF; Oct: 0o17
510    ///
511    /// nybble.increment();
512    /// assert_eq!(u8::from(&nybble), 0);
513    /// assert_eq!(nybble.to_string(), "0x0");
514    /// ```
515    ///
516    /// # Side Effects
517    ///
518    /// This method increments the value stored in the Nybble.
519    ///
520    /// # See Also
521    ///
522    /// * [`decrement()`](#method.decrement): Decrements the value stored in the
523    ///   Nybble.
524    /// * [`flip()`](#method.flip): Flips all of the Bit values in the Nybble.
525    #[allow(clippy::cast_possible_truncation)]
526    pub fn increment(&mut self) {
527        // Find the first Bit::Zero from the right
528        let zero = self.iter().position(|bit| bit == Bit::Zero);
529
530        if let Some(index) = zero {
531            for i in 0..=index as u8 {
532                self.flip_bit(i);
533            }
534        } else {
535            self.flip();
536        }
537    }
538
539    /// Decrement the Nybble with no rollover
540    ///
541    /// This method decrements the value stored in the Nybble.
542    /// This has no rollover for underflow. This means that if we decrement past
543    /// the minimum value (0), we will stay at 0.
544    ///
545    /// # Examples
546    ///
547    /// ## Regular Use
548    ///
549    /// ```
550    /// use brainfoamkit_lib::Nybble;
551    ///
552    /// let mut nybble = Nybble::from(2); // Nybble: 0b0010; Dec: 2; Hex: 0x2; Oct: 0o2
553    ///
554    /// nybble.decrement();
555    /// assert_eq!(u8::from(&nybble), 1);
556    /// assert_eq!(nybble.to_string(), "0x1");
557    ///
558    /// nybble.decrement();
559    /// assert_eq!(u8::from(&nybble), 0);
560    /// assert_eq!(nybble.to_string(), "0x0");
561    /// ```
562    ///
563    /// ## Underflow Use
564    ///
565    /// ```
566    /// use brainfoamkit_lib::Nybble;
567    ///
568    /// let mut nybble = Nybble::default(); // Nybble: 0b0000; Dec: 0; Hex: 0x0; Oct: 0o0
569    ///
570    /// nybble.decrement();
571    /// assert_eq!(u8::from(&nybble), 0);
572    /// assert_eq!(nybble.to_string(), "0x0");
573    /// ```
574    ///
575    /// # Side Effects
576    ///
577    /// This method decrements the value stored in the Nybble.
578    ///
579    /// # See Also
580    ///
581    /// * [`increment()`](#method.increment): Increments the value stored in the
582    ///   Nybble.
583    /// * [`flip()`](#method.flip): Flips all of the Bit values in the Nybble.
584    #[allow(clippy::cast_possible_truncation)]
585    pub fn decrement(&mut self) {
586        // Find the first Bit::One bit from the right
587        let one = self.iter().position(|bit| bit == Bit::One);
588
589        if let Some(index) = one {
590            for i in 0..=index as u8 {
591                self.flip_bit(i);
592            }
593        }
594    }
595
596    /// Create an iterator over the Nybble.
597    /// This allows the use of the `for` loop on the Nybble.
598    ///
599    /// # Examples
600    ///
601    /// ```
602    /// use brainfoamkit_lib::Nybble;
603    ///
604    /// let nybble = Nybble::from(0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
605    ///
606    /// for bit in nybble.iter() {
607    ///     println!("{}", bit);
608    /// }
609    /// ```
610    #[must_use]
611    pub const fn iter(&self) -> IterableNybble {
612        IterableNybble::new(self)
613    }
614}
615
616impl Display for Nybble {
617    /// Converts the Nybble to a string.
618    ///
619    /// This method converts the Nybble to a string.
620    ///
621    /// # Examples
622    ///
623    /// ```
624    /// use brainfoamkit_lib::Nybble;
625    ///
626    /// let nybble = Nybble::from(0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
627    ///
628    /// assert_eq!(nybble.to_string(), "0xA");
629    /// ```
630    ///
631    /// # Returns
632    ///
633    /// The Nybble as a string.
634    ///
635    /// # See Also
636    ///
637    /// * [`to_u8()`](#method.to_u8): Converts the Nybble to an 8-bit unsigned
638    ///   integer (u8).
639    /// * [`from_u8()`](#method.from_u8): Creates a new Nybble from a u8 value.
640    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
641        let number: u8 = self.into();
642        write!(f, "{number:#03X}")
643    }
644}
645
646impl Default for Nybble {
647    /// Create a _default_ (empty) Nybble.
648    ///
649    /// Creates a new Nybble with default (all [`Bit::Zero`](crate::Bit::Zero))
650    /// Bit values.
651    ///
652    /// # Examples
653    ///
654    /// ```
655    /// use brainfoamkit_lib::Nybble;
656    ///
657    /// let nybble = Nybble::default();
658    ///
659    /// assert_eq!(u8::from(&nybble), 0b0000); // Nybble: 0b0000; Dec: 0; Hex: 0x0; Oct: 0o0
660    ///
661    /// assert_eq!(nybble.to_string(), "0x0");
662    /// ```
663    ///
664    /// # Returns
665    ///
666    /// A new Nybble with default (all [`Bit::Zero`](crate::Bit::Zero)) Bit
667    /// values.
668    ///
669    /// # See Also
670    ///
671    /// * [`new()`](#method.new): Creates a new Nybble with the specified Bit
672    ///   values.
673    /// * [`from_u8()`](#method.from_u8): Creates a new Nybble from a u8 value.
674    /// * [`to_u8()`](#method.to_u8): Converts the Nybble to an 8-bit unsigned
675    ///   integer (u8).
676    fn default() -> Self {
677        Self::new(Bit::zero(), Bit::zero(), Bit::zero(), Bit::zero())
678    }
679}
680
681impl From<u8> for Nybble {
682    /// Creates a new Nybble from a u8 value.
683    ///
684    /// This method takes a u8 value as an argument and creates a new Nybble
685    /// truncating to only the least significant four bits.
686    ///
687    /// # Arguments
688    ///
689    /// * `n` - The u8 value to create the Nybble from.
690    ///
691    /// # Examples
692    ///
693    /// ## A valid value for a Nybble
694    ///
695    /// ```
696    /// use brainfoamkit_lib::Nybble;
697    ///
698    /// let nybble = Nybble::from(5);
699    /// assert_eq!(u8::from(&nybble), 5);
700    /// assert_eq!(nybble.to_string(), "0x5");
701    /// ```
702    ///
703    /// ## A value too large for a Nybble
704    ///
705    /// ```
706    /// use brainfoamkit_lib::Nybble;
707    ///
708    /// let nybble = Nybble::from(16);
709    /// assert_eq!(u8::from(&nybble), 0);
710    /// assert_eq!(nybble.to_string(), "0x0");
711    /// ```
712    ///
713    /// # Returns
714    ///
715    /// A new Nybble from the specified u8 value, or an all
716    /// [`Bit::One`](crate::Bit::One) Nybble if the value is larger than 15.
717    ///
718    /// # See Also
719    ///
720    /// * [`new()`](#method.new): Creates a new Nybble with the specified Bit
721    ///   values.
722    /// * [`default()`](#method.default): Creates a new Nybble with default (all
723    ///   [`Bit::Zero`](crate::Bit::Zero)) Bit values.
724    fn from(n: u8) -> Self {
725        let n = n & 0b0000_1111;
726
727        // Create a new Nybble instance with default Bit values
728        let mut nybble = Self::default();
729
730        if n & 0b0001 != 0 {
731            nybble.bit_0.set();
732        };
733        if n & 0b0010 != 0 {
734            nybble.bit_1.set();
735        };
736        if n & 0b0100 != 0 {
737            nybble.bit_2.set();
738        };
739        if n & 0b1000 != 0 {
740            nybble.bit_3.set();
741        };
742
743        nybble
744    }
745}
746
747impl From<&Nybble> for u8 {
748    /// Converts the Nybble to an 8-bit unsigned integer (u8).
749    ///
750    /// This method converts the Nybble to an 8-bit unsigned integer (u8).
751    ///
752    /// # Examples
753    ///
754    /// ```
755    /// use brainfoamkit_lib::Nybble;
756    /// use brainfoamkit_lib::Bit;
757    ///
758    /// let nybble = Nybble::new(Bit::One, Bit::Zero, Bit::One, Bit::Zero); // Dec: 10; Hex: 0xA; Oct: 0o12
759    /// let result = u8::from(&nybble); // Dec: 10; Hex: 0xA; Oct: 0o12
760    /// assert_eq!(result, 0b1010);
761    /// ```
762    /// # Returns
763    ///
764    /// The Nybble as an 8-bit unsigned integer (u8).
765    ///
766    /// # See Also
767    ///
768    /// * [`from_u8()`](#method.from_u8): Creates a new Nybble from a u8 value.
769    /// * [`to_string()`](#method.to_string): Converts the Nybble to a string.
770    fn from(nybble: &Nybble) -> Self {
771        let mut n = 0;
772
773        for i in 0..4 {
774            if nybble.get_bit(i) == Bit::One {
775                n |= 1 << i;
776            }
777        }
778
779        n
780    }
781}
782
783impl Not for Nybble {
784    // The output type of Not is Nybble as the operation is symmetric
785    type Output = Self;
786
787    /// Perform the Not operation on the Nybble.
788    ///
789    /// This method performs the Not operation on the Nybble.
790    /// This also allows the use of the `!` operator on the Nybble.
791    ///
792    /// # Examples
793    ///
794    /// ```
795    /// use brainfoamkit_lib::Nybble;
796    ///
797    /// let nybble = Nybble::from(0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
798    ///
799    /// assert_eq!(u8::from(&nybble), 0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
800    /// assert_eq!(nybble.to_string(), "0xA");
801    ///
802    /// let nybble = !nybble;
803    ///
804    /// assert_eq!(u8::from(&nybble), 0b0101); // Dec: 5; Hex: 0x5; Oct: 0o5
805    /// assert_eq!(nybble.to_string(), "0x5");
806    /// ```
807    ///
808    /// # Returns
809    ///
810    /// A new Nybble with the Bit values flipped.
811    ///
812    /// # See Also
813    ///
814    /// * [`flip()`](#method.flip): Flips all of the Bit values in the Nybble.
815    /// * [`flip_bit()`](#method.flip_bit): Flips the Bit value at the specified
816    ///   index.
817    /// * [`bitand()`](#method.bitand): Performs the Bitwise And operation on
818    ///   two Nybbles.
819    /// * [`bitor()`](#method.bitor): Performs the Bitwise Or operation on two
820    ///   Nybbles.
821    /// * [`bitxor()`](#method.bitxor): Performs the Bitwise Xor operation on
822    ///   two Nybbles.
823    /// * [`bitand_assign()`](#method.bitand_assign): Performs the Bitwise And
824    ///   operation on two Nybbles and assigns the result to the first Nybble.
825    /// * [`bitor_assign()`](#method.bitor_assign): Performs the Bitwise Or
826    ///   operation on two Nybbles and assigns the result to the first Nybble.
827    /// * [`bitxor_assign()`](#method.bitxor_assign): Performs the Bitwise Xor
828    ///   operation on two Nybbles and assigns the result to the first Nybble.
829    fn not(self) -> Self::Output {
830        let mut nybble = self;
831        nybble.flip();
832        nybble
833    }
834}
835
836impl BitAnd for Nybble {
837    // The output type of BitAnd is Nybble as the operation is symmetric
838    type Output = Self;
839
840    /// Perform the Bitwise And operation on two Nybbles.
841    ///
842    /// This method performs the Bitwise And operation on two Nybbles.
843    /// This also allows the use of the `&` operator on two Nybbles.
844    ///
845    /// # Arguments
846    ///
847    /// * `rhs` - The right hand side of the Bitwise And operation.
848    ///
849    /// # Examples
850    ///
851    /// ```
852    /// use brainfoamkit_lib::Nybble;
853    ///
854    /// let nybble_1 = Nybble::from(0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
855    /// let nybble_2 = Nybble::from(0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
856    ///
857    /// assert_eq!(u8::from(&nybble_1), 0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
858    /// assert_eq!(nybble_1.to_string(), "0xA");
859    ///
860    /// assert_eq!(u8::from(&nybble_2), 0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
861    /// assert_eq!(nybble_2.to_string(), "0xC");
862    ///
863    /// let nybble = nybble_1 & nybble_2;
864    ///
865    /// assert_eq!(u8::from(&nybble), 0b1000); // Dec: 8; Hex: 0x8; Oct: 0o10
866    /// assert_eq!(nybble.to_string(), "0x8");
867    /// ```
868    ///
869    /// # Returns
870    ///
871    /// A new Nybble with the Bitwise And operation performed on the two
872    /// Nybbles.
873    ///
874    /// # See Also
875    ///
876    /// * [`bitor()`](#method.bitor): Performs the Bitwise Or operation on two
877    ///   Nybbles.
878    /// * [`bitxor()`](#method.bitxor): Performs the Bitwise Xor operation on
879    ///   two Nybbles.
880    /// * [`bitand_assign()`](#method.bitand_assign): Performs the Bitwise And
881    ///   operation on two Nybbles and assigns the result to the first Nybble.
882    /// * [`bitor_assign()`](#method.bitor_assign): Performs the Bitwise Or
883    ///   operation on two Nybbles and assigns the result to the first Nybble.
884    /// * [`bitxor_assign()`](#method.bitxor_assign): Performs the Bitwise Xor
885    ///   operation on two Nybbles and assigns the result to the first Nybble.
886    fn bitand(self, rhs: Self) -> Self::Output {
887        let mut nybble = self;
888        nybble.bit_0 &= rhs.bit_0;
889        nybble.bit_1 &= rhs.bit_1;
890        nybble.bit_2 &= rhs.bit_2;
891        nybble.bit_3 &= rhs.bit_3;
892        nybble
893    }
894}
895
896impl BitAndAssign for Nybble {
897    /// Perform the Bitwise And operation on two Nybbles and assigns the result
898    /// to the first Nybble.
899    ///
900    /// This method performs the Bitwise And operation on two Nybbles and
901    /// assigns the result to the first Nybble.
902    ///
903    /// # Arguments
904    ///
905    /// * `rhs` - The right hand side of the Bitwise And operation.
906    ///
907    /// # Examples
908    ///
909    /// ```
910    /// use brainfoamkit_lib::Nybble;
911    ///
912    /// let mut nybble_1 = Nybble::from(0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
913    /// let nybble_2 = Nybble::from(0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
914    ///
915    /// assert_eq!(u8::from(&nybble_1), 0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
916    /// assert_eq!(nybble_1.to_string(), "0xA");
917    ///
918    /// assert_eq!(u8::from(&nybble_2), 0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
919    /// assert_eq!(nybble_2.to_string(), "0xC");
920    ///
921    /// nybble_1 &= nybble_2;
922    ///
923    /// assert_eq!(u8::from(&nybble_1), 0b1000); // Dec: 8; Hex: 0x8; Oct: 0o10
924    /// assert_eq!(nybble_1.to_string(), "0x8");
925    /// ```
926    ///
927    /// # Side Effects
928    ///
929    /// This method will perform the Bitwise And operation on two Nybbles and
930    /// assign the result to the first Nybble.
931    ///
932    /// # See Also
933    ///
934    /// * [`bitand()`](#method.bitand): Performs the Bitwise And operation on
935    ///   two Nybbles.
936    /// * [`bitor()`](#method.bitor): Performs the Bitwise Or operation on two
937    ///   Nybbles.
938    /// * [`bitxor()`](#method.bitxor): Performs the Bitwise Xor operation on
939    ///   two Nybbles.
940    /// * [`bitor_assign()`](#method.bitor_assign): Performs the Bitwise Or
941    ///   operation on two Nybbles and assigns the result to the first Nybble.
942    /// * [`bitxor_assign()`](#method.bitxor_assign): Performs the Bitwise Xor
943    ///   operation on two Nybbles and assigns the result to the first Nybble.
944    fn bitand_assign(&mut self, rhs: Self) {
945        self.bit_0 &= rhs.bit_0;
946        self.bit_1 &= rhs.bit_1;
947        self.bit_2 &= rhs.bit_2;
948        self.bit_3 &= rhs.bit_3;
949    }
950}
951
952impl BitOr for Nybble {
953    // The output type of BitOr is Nybble as the operation is symmetric
954    type Output = Self;
955
956    /// Perform the Bitwise Or operation on two Nybbles.
957    ///
958    /// This method performs the Bitwise Or operation on two Nybbles.
959    /// This also allows the use of the `|` operator on two Nybbles.
960    ///
961    /// # Arguments
962    ///
963    /// * `rhs` - The right hand side of the Bitwise Or operation.
964    ///
965    /// # Examples
966    ///
967    /// ```
968    /// use brainfoamkit_lib::Nybble;
969    ///
970    /// let nybble_1 = Nybble::from(0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
971    /// let nybble_2 = Nybble::from(0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
972    ///
973    /// assert_eq!(u8::from(&nybble_1), 0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
974    /// assert_eq!(nybble_1.to_string(), "0xA");
975    ///
976    /// assert_eq!(u8::from(&nybble_2), 0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
977    ///
978    /// let nybble = nybble_1 | nybble_2;
979    ///
980    /// assert_eq!(u8::from(&nybble), 0b1110); // Dec: 14; Hex: 0xE; Oct: 0o16
981    /// assert_eq!(nybble.to_string(), "0xE");
982    /// ```
983    ///
984    /// # Returns
985    ///
986    /// A new Nybble with the Bitwise Or operation performed on the two Nybbles.
987    ///
988    /// # See Also
989    ///
990    /// * [`bitand()`](#method.bitand): Performs the Bitwise And operation on
991    ///   two Nybbles.
992    /// * [`bitxor()`](#method.bitxor): Performs the Bitwise Xor operation on
993    ///   two Nybbles.
994    /// * [`bitand_assign()`](#method.bitand_assign): Performs the Bitwise And
995    ///   operation on two Nybbles and assigns the result to the first Nybble.
996    /// * [`bitor_assign()`](#method.bitor_assign): Performs the Bitwise Or
997    ///   operation on two Nybbles and assigns the result to the first Nybble.
998    /// * [`bitxor_assign()`](#method.bitxor_assign): Performs the Bitwise Xor
999    ///   operation on two Nybbles and assigns the result to the first Nybble.
1000    fn bitor(self, rhs: Self) -> Self::Output {
1001        let mut nybble = self;
1002        nybble.bit_0 |= rhs.bit_0;
1003        nybble.bit_1 |= rhs.bit_1;
1004        nybble.bit_2 |= rhs.bit_2;
1005        nybble.bit_3 |= rhs.bit_3;
1006        nybble
1007    }
1008}
1009
1010impl BitOrAssign for Nybble {
1011    /// Perform the Bitwise Or operation on two Nybbles and assigns the result
1012    /// to the first Nybble.
1013    ///
1014    /// This method performs the Bitwise Or operation on two Nybbles and assigns
1015    /// the result to the first Nybble. This also allows the use of the `|=`
1016    /// operator on two Nybbles.
1017    ///
1018    /// # Arguments
1019    ///
1020    /// * `rhs` - The right hand side of the Bitwise Or operation.
1021    ///
1022    /// # Examples
1023    ///
1024    /// ```
1025    /// use brainfoamkit_lib::Nybble;
1026    ///
1027    /// let mut nybble_1 = Nybble::from(0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
1028    /// let nybble_2 = Nybble::from(0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
1029    ///
1030    /// assert_eq!(u8::from(&nybble_1), 0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
1031    /// assert_eq!(nybble_1.to_string(), "0xA");
1032    ///
1033    /// assert_eq!(u8::from(&nybble_2), 0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
1034    /// assert_eq!(nybble_2.to_string(), "0xC");
1035    ///
1036    /// nybble_1 |= nybble_2;
1037    ///
1038    /// assert_eq!(u8::from(&nybble_1), 0b1110); // Dec: 14; Hex: 0xE; Oct: 0o16
1039    /// ```
1040    ///
1041    /// # Side Effects
1042    ///
1043    /// This method will perform the Bitwise Or operation on two Nybbles and
1044    /// assign the result to the first Nybble.
1045    ///
1046    /// # See Also
1047    ///
1048    /// * [`bitand()`](#method.bitand): Performs the Bitwise And operation on
1049    ///   two Nybbles.
1050    /// * [`bitor()`](#method.bitor): Performs the Bitwise Or operation on two
1051    ///   Nybbles.
1052    /// * [`bitxor()`](#method.bitxor): Performs the Bitwise Xor operation on
1053    ///   two Nybbles.
1054    /// * [`bitand_assign()`](#method.bitand_assign): Performs the Bitwise And
1055    ///   operation on two Nybbles and assigns the result to the first Nybble.
1056    /// * [`bitxor_assign()`](#method.bitxor_assign): Performs the Bitwise Xor
1057    ///   operation on two Nybbles and assigns the result to the first Nybble.
1058    fn bitor_assign(&mut self, rhs: Self) {
1059        self.bit_0 |= rhs.bit_0;
1060        self.bit_1 |= rhs.bit_1;
1061        self.bit_2 |= rhs.bit_2;
1062        self.bit_3 |= rhs.bit_3;
1063    }
1064}
1065
1066impl BitXor for Nybble {
1067    // The output type of BitXor is Nybble as the operation is symmetric
1068    type Output = Self;
1069
1070    /// Perform the Bitwise Xor operation on two Nybbles.
1071    ///
1072    /// This method performs the Bitwise Xor operation on two Nybbles.
1073    /// This also allows the use of the `^` operator on two Nybbles.
1074    ///
1075    /// # Arguments
1076    ///
1077    /// * `rhs` - The right hand side of the Bitwise Xor operation.
1078    ///
1079    /// # Examples
1080    ///
1081    /// ```
1082    /// use brainfoamkit_lib::Nybble;
1083    ///
1084    /// let nybble_1 = Nybble::from(0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
1085    /// let nybble_2 = Nybble::from(0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
1086    ///
1087    /// assert_eq!(u8::from(&nybble_1), 0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
1088    /// assert_eq!(nybble_1.to_string(), "0xA");
1089    ///
1090    /// assert_eq!(u8::from(&nybble_2), 0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
1091    ///
1092    /// let nybble = nybble_1 ^ nybble_2;
1093    ///
1094    /// assert_eq!(u8::from(&nybble), 0b0110); // Dec: 6; Hex: 0x6; Oct: 0o6
1095    /// ```
1096    ///
1097    /// # Returns
1098    ///
1099    /// A new Nybble with the Bitwise Xor operation performed on the two
1100    /// Nybbles.
1101    ///
1102    /// # See Also
1103    ///
1104    /// * [`bitand()`](#method.bitand): Performs the Bitwise And operation on
1105    ///   two Nybbles.
1106    /// * [`bitor()`](#method.bitor): Performs the Bitwise Or operation on two
1107    ///   Nybbles.
1108    /// * [`bitand_assign()`](#method.bitand_assign): Performs the Bitwise And
1109    ///   operation on two Nybbles and assigns the result to the first Nybble.
1110    /// * [`bitor_assign()`](#method.bitor_assign): Performs the Bitwise Or
1111    ///   operation on two Nybbles and assigns the result to the first Nybble.
1112    /// * [`bitxor_assign()`](#method.bitxor_assign): Performs the Bitwise Xor
1113    ///   operation on two Nybbles and assigns the result to the first Nybble.
1114    fn bitxor(self, rhs: Self) -> Self::Output {
1115        let mut nybble = self;
1116        nybble.bit_0 ^= rhs.bit_0;
1117        nybble.bit_1 ^= rhs.bit_1;
1118        nybble.bit_2 ^= rhs.bit_2;
1119        nybble.bit_3 ^= rhs.bit_3;
1120        nybble
1121    }
1122}
1123
1124impl BitXorAssign for Nybble {
1125    /// Perform the Bitwise Xor operation on two Nybbles and assigns the result
1126    /// to the first Nybble.
1127    ///
1128    /// This method performs the Bitwise Xor operation on two Nybbles and
1129    /// assigns the result to the first Nybble. This also allows the use of
1130    /// the `^=` operator on two Nybbles.
1131    ///
1132    /// # Arguments
1133    ///
1134    /// * `rhs` - The right hand side of the Bitwise Xor operation.
1135    ///
1136    /// # Examples
1137    ///
1138    /// ```
1139    /// use brainfoamkit_lib::Nybble;
1140    ///
1141    /// let mut nybble_1 = Nybble::from(0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
1142    /// let nybble_2 = Nybble::from(0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
1143    ///
1144    /// assert_eq!(u8::from(&nybble_1), 0b1010); // Dec: 10; Hex: 0xA; Oct: 0o12
1145    /// assert_eq!(nybble_1.to_string(), "0xA");
1146    ///
1147    /// assert_eq!(u8::from(&nybble_2), 0b1100); // Dec: 12; Hex: 0xC; Oct: 0o14
1148    /// assert_eq!(nybble_2.to_string(), "0xC");
1149    ///
1150    /// nybble_1 ^= nybble_2;
1151    ///
1152    /// assert_eq!(u8::from(&nybble_1), 0b0110); // Dec: 6; Hex: 0x6; Oct: 0o6
1153    /// ```
1154    ///
1155    /// # Side Effects
1156    ///
1157    /// This method will perform the Bitwise Xor operation on two Nybbles and
1158    /// assign the result to the first Nybble.
1159    ///
1160    /// # See Also
1161    ///
1162    /// * [`bitand()`](#method.bitand): Performs the Bitwise And operation on
1163    ///   two Nybbles.
1164    /// * [`bitor()`](#method.bitor): Performs the Bitwise Or operation on two
1165    ///   Nybbles.
1166    /// * [`bitxor()`](#method.bitxor): Performs the Bitwise Xor operation on
1167    ///   two Nybbles.
1168    /// * [`bitand_assign()`](#method.bitand_assign): Performs the Bitwise And
1169    ///   operation on two Nybbles and assigns the result to the first Nybble.
1170    /// * [`bitor_assign()`](#method.bitor_assign): Performs the Bitwise Or
1171    ///   operation on two Nybbles and assigns the result to the first Nybble.
1172    fn bitxor_assign(&mut self, rhs: Self) {
1173        self.bit_0 ^= rhs.bit_0;
1174        self.bit_1 ^= rhs.bit_1;
1175        self.bit_2 ^= rhs.bit_2;
1176        self.bit_3 ^= rhs.bit_3;
1177    }
1178}
1179
1180/// `IntoIterator` implementation for a reference to a `Nybble`.
1181///
1182/// This implementation allows a `Nybble` reference to be converted into an
1183/// iterator. The iterator will yield `Bit` items.
1184impl<'a> IntoIterator for &'a Nybble {
1185    /// The type of the iterator that will be returned. It's an `IterableNybble`
1186    /// with the same lifetime as the `Nybble` reference.
1187    type IntoIter = IterableNybble<'a>;
1188    /// The type of the items that will be returned when iterating over the
1189    /// `Nybble` reference. In this case, it's a `Bit`.
1190    type Item = Bit;
1191
1192    /// Converts the `Nybble` reference into an `IterableNybble` iterator.
1193    ///
1194    /// # Returns
1195    ///
1196    /// An `IterableNybble` iterator with the same lifetime as the `Nybble`
1197    /// reference.
1198    fn into_iter(self) -> Self::IntoIter {
1199        self.iter()
1200    }
1201}
1202
1203#[cfg(test)]
1204mod tests {
1205    use super::*;
1206
1207    #[test]
1208    fn test_from_u8() {
1209        let nybble = Nybble::from(10);
1210        assert_eq!(u8::from(&nybble), 0b1010);
1211    }
1212
1213    #[test]
1214    fn test_from_u8_zero() {
1215        let nybble = Nybble::from(0);
1216        assert_eq!(u8::from(&nybble), 0);
1217    }
1218
1219    #[test]
1220    fn test_from_u8_all_ones() {
1221        let nybble = Nybble::from(0b1111);
1222        assert_eq!(u8::from(&nybble), 0b1111);
1223    }
1224
1225    #[test]
1226    fn test_from_u8_high_bits() {
1227        let nybble = Nybble::from(0b10101010);
1228        assert_eq!(u8::from(&nybble), 0b1010);
1229    }
1230
1231    #[test]
1232    fn test_get_bit() {
1233        let nybble = Nybble::from(12);
1234        assert_eq!(nybble.get_bit(0), Bit::zero());
1235        assert_eq!(nybble.get_bit(1), Bit::zero());
1236        assert_eq!(nybble.get_bit(2), Bit::one());
1237        assert_eq!(nybble.get_bit(3), Bit::one());
1238    }
1239
1240    #[test]
1241    #[allow(unused_variables)]
1242    #[should_panic(expected = "Index out of bounds")]
1243    fn test_get_bit_oob() {
1244        let nybble = Nybble::from(12);
1245        let p = nybble.get_bit(4);
1246    }
1247
1248    #[test]
1249    fn test_set_bit() {
1250        let mut nybble = Nybble::default();
1251        nybble.set_bit(0);
1252        nybble.set_bit(1);
1253        nybble.set_bit(2);
1254        nybble.set_bit(3);
1255        assert_eq!(u8::from(&nybble), 15);
1256        assert_eq!(nybble.to_string(), "0xF");
1257    }
1258
1259    #[test]
1260    #[should_panic(expected = "Index out of bounds")]
1261    fn test_set_bit_oob() {
1262        let mut nybble = Nybble::from(12);
1263        nybble.set_bit(4);
1264    }
1265
1266    #[test]
1267    fn test_unset_bit() {
1268        let mut nybble = Nybble::from(15);
1269        nybble.unset_bit(0);
1270        nybble.unset_bit(1);
1271        nybble.unset_bit(2);
1272        nybble.unset_bit(3);
1273        assert_eq!(u8::from(&nybble), 0);
1274        assert_eq!(nybble.to_string(), "0x0");
1275    }
1276
1277    #[test]
1278    #[should_panic(expected = "Index out of bounds")]
1279    fn test_unset_bit_oob() {
1280        let mut nybble = Nybble::from(12);
1281        nybble.unset_bit(4);
1282    }
1283
1284    #[test]
1285    fn test_flip_bit() {
1286        let mut nybble = Nybble::from(15);
1287        nybble.flip_bit(0);
1288        nybble.flip_bit(1);
1289        nybble.flip_bit(2);
1290        nybble.flip_bit(3);
1291        assert_eq!(u8::from(&nybble), 0);
1292        assert_eq!(nybble.to_string(), "0x0");
1293    }
1294
1295    #[test]
1296    #[should_panic(expected = "Index out of bounds")]
1297    fn test_flip_bit_oob() {
1298        let mut nybble = Nybble::from(12);
1299        nybble.flip_bit(4);
1300    }
1301
1302    #[test]
1303    fn test_flip() {
1304        let mut nybble = Nybble::from(15);
1305        nybble.flip();
1306        assert_eq!(u8::from(&nybble), 0);
1307        assert_eq!(nybble.to_string(), "0x0");
1308    }
1309
1310    #[test]
1311    fn test_not() {
1312        let nybble = Nybble::from(15);
1313        let nybble_not = !nybble;
1314        assert_eq!(u8::from(&nybble_not), 0);
1315        assert_eq!(nybble_not.to_string(), "0x0");
1316    }
1317
1318    #[test]
1319    fn test_and() {
1320        let nybble_1 = Nybble::from(0b1010);
1321        let nybble_2 = Nybble::from(0b1100);
1322        let nybble_3 = nybble_1 & nybble_2;
1323        assert_eq!(u8::from(&nybble_3), 0b1000);
1324        assert_eq!(nybble_3.to_string(), "0x8");
1325    }
1326
1327    #[test]
1328    fn test_and_assign() {
1329        let mut nybble_1 = Nybble::from(0b1010);
1330        let nybble_2 = Nybble::from(0b1100);
1331        nybble_1 &= nybble_2;
1332        assert_eq!(u8::from(&nybble_1), 0b1000);
1333        assert_eq!(nybble_1.to_string(), "0x8");
1334    }
1335
1336    #[test]
1337    fn test_or() {
1338        let nybble_1 = Nybble::from(0b1010);
1339        let nybble_2 = Nybble::from(0b1100);
1340        let nybble_3 = nybble_1 | nybble_2;
1341        assert_eq!(u8::from(&nybble_3), 0b1110);
1342        assert_eq!(nybble_3.to_string(), "0xE");
1343    }
1344
1345    #[test]
1346    fn test_or_assign() {
1347        let mut nybble_1 = Nybble::from(0b1010);
1348        let nybble_2 = Nybble::from(0b1100);
1349        nybble_1 |= nybble_2;
1350        assert_eq!(u8::from(&nybble_1), 0b1110);
1351        assert_eq!(nybble_1.to_string(), "0xE");
1352    }
1353
1354    #[test]
1355    fn test_xor() {
1356        let nybble_1 = Nybble::from(0b1010);
1357        let nybble_2 = Nybble::from(0b1100);
1358        let nybble_3 = nybble_1 ^ nybble_2;
1359        assert_eq!(u8::from(&nybble_3), 0b0110);
1360        assert_eq!(nybble_3.to_string(), "0x6");
1361    }
1362
1363    #[test]
1364    fn test_xor_assign() {
1365        let mut nybble_1 = Nybble::from(0b1010);
1366        let nybble_2 = Nybble::from(0b1100);
1367        nybble_1 ^= nybble_2;
1368        assert_eq!(u8::from(&nybble_1), 0b0110);
1369        assert_eq!(nybble_1.to_string(), "0x6");
1370    }
1371
1372    #[test]
1373    fn test_display() {
1374        let nybble = Nybble::from(10);
1375        assert_eq!(format!("{}", nybble), "0xA");
1376    }
1377
1378    #[test]
1379    fn test_iterator() {
1380        let nybble = Nybble::from(10);
1381        let mut iter = nybble.iter();
1382        assert_eq!(iter.next(), Some(Bit::zero()));
1383        assert_eq!(iter.next(), Some(Bit::one()));
1384        assert_eq!(iter.next(), Some(Bit::zero()));
1385        assert_eq!(iter.next(), Some(Bit::one()));
1386        assert_eq!(iter.next(), None);
1387    }
1388
1389    #[test]
1390    fn test_increment() {
1391        let mut nybble = Nybble::from(10);
1392        nybble.increment();
1393        assert_eq!(u8::from(&nybble), 11);
1394        assert_eq!(nybble.to_string(), "0xB");
1395    }
1396
1397    #[test]
1398    fn test_decrement() {
1399        let mut nybble = Nybble::from(10);
1400        nybble.decrement();
1401        assert_eq!(u8::from(&nybble), 9);
1402        assert_eq!(nybble.to_string(), "0x9");
1403    }
1404
1405    #[test]
1406    fn test_increment_boundary() {
1407        let mut nybble = Nybble::from(15);
1408        nybble.increment();
1409        assert_eq!(u8::from(&nybble), 0);
1410        assert_eq!(nybble.to_string(), "0x0");
1411    }
1412
1413    #[test]
1414    fn test_decrement_boundary() {
1415        let mut nybble = Nybble::from(0);
1416        nybble.decrement();
1417        assert_eq!(u8::from(&nybble), 0);
1418        assert_eq!(nybble.to_string(), "0x0");
1419    }
1420
1421    #[test]
1422    fn test_into_iter() {
1423        let byte = Nybble::from(0b1010); // Assuming Byte::from exists
1424        let mut iter = (&byte).into_iter();
1425
1426        // Assuming Bit is an enum with variants Zero and One
1427        assert_eq!(iter.next(), Some(Bit::Zero));
1428        assert_eq!(iter.next(), Some(Bit::One));
1429        assert_eq!(iter.next(), Some(Bit::Zero));
1430        assert_eq!(iter.next(), Some(Bit::One));
1431        assert_eq!(iter.next(), None); // Ensure the iterator is exhausted
1432    }
1433
1434    #[test]
1435    fn test_into_iter_empty_byte() {
1436        let byte = Nybble::from(0b0000); // Assuming Byte::from exists
1437        let mut iter = (&byte).into_iter();
1438
1439        // Assuming Bit is an enum with variants Zero and One
1440        assert_eq!(iter.next(), Some(Bit::Zero));
1441        assert_eq!(iter.next(), Some(Bit::Zero));
1442        assert_eq!(iter.next(), Some(Bit::Zero));
1443        assert_eq!(iter.next(), Some(Bit::Zero));
1444        assert_eq!(iter.next(), None); // Ensure the iterator is exhausted
1445    }
1446
1447    #[test]
1448    fn test_get_bit_ref() {
1449        let nybble = Nybble::new(Bit::One, Bit::Zero, Bit::One, Bit::Zero); // Dec: 10; Hex: 0xA; Oct: 0o12
1450
1451        // Test that the 'get_bit_ref' method returns the correct Bit reference for a
1452        // given index
1453        assert_eq!(
1454            nybble.get_bit_ref(0),
1455            &Bit::Zero,
1456            "Bit at index 0 should be Zero"
1457        );
1458        assert_eq!(
1459            nybble.get_bit_ref(1),
1460            &Bit::One,
1461            "Bit at index 1 should be One"
1462        );
1463        assert_eq!(
1464            nybble.get_bit_ref(2),
1465            &Bit::Zero,
1466            "Bit at index 2 should be Zero"
1467        );
1468        assert_eq!(
1469            nybble.get_bit_ref(3),
1470            &Bit::One,
1471            "Bit at index 3 should be One"
1472        );
1473    }
1474
1475    #[test]
1476    #[should_panic(expected = "Index out of bounds")]
1477    fn test_get_bit_ref_out_of_bounds() {
1478        let nybble = Nybble::new(Bit::One, Bit::Zero, Bit::One, Bit::Zero); // Dec: 10; Hex: 0xA; Oct: 0o12
1479        let _ = nybble.get_bit_ref(4); // This should panic
1480    }
1481}