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}