nybbles/
nibbles.rs

1use cfg_if::cfg_if;
2use core::{
3    cmp::{self, Ordering},
4    fmt,
5    mem::MaybeUninit,
6    ops::{Bound, Deref, RangeBounds},
7    slice,
8};
9use ruint::aliases::U256;
10use smallvec::SmallVec;
11
12#[cfg(not(feature = "nightly"))]
13#[allow(unused_imports)]
14use core::convert::{identity as likely, identity as unlikely};
15#[cfg(feature = "nightly")]
16#[allow(unused_imports)]
17use core::intrinsics::{likely, unlikely};
18
19#[cfg(not(feature = "std"))]
20use alloc::vec::Vec;
21
22/// The size of [`U256`] in nibbles.
23const NIBBLES: usize = 64;
24
25/// This array contains 65 bitmasks used in [`Nibbles::slice`].
26///
27/// Each mask is a [`U256`] where:
28/// - Index 0 is just 0 (no bits set)
29/// - Index 1 has the highest 4 bits set (one nibble)
30/// - Index 2 has the highest 8 bits set (two nibbles)
31/// - ...and so on
32/// - Index 64 has all bits set ([`U256::MAX`])
33static SLICE_MASKS: [U256; 65] = {
34    let mut masks = [U256::ZERO; 65];
35    let mut i = 0;
36    while i <= NIBBLES {
37        masks[i] = if i == 0 { U256::ZERO } else { U256::MAX.wrapping_shl((NIBBLES - i) * 4) };
38        i += 1;
39    }
40    masks
41};
42
43/// This array contains 65 values to add that are used in [`Nibbles::increment`].
44///
45/// Each value is a [`U256`] equal to `1 << ((64 - i) * 4)`.
46static INCREMENT_VALUES: [U256; 65] = {
47    let mut masks = [U256::ZERO; 65];
48    let mut i = 0;
49    while i <= NIBBLES {
50        masks[i] = U256::ONE.wrapping_shl((NIBBLES - i) * 4);
51        i += 1;
52    }
53    masks
54};
55
56/// Structure representing a sequence of nibbles.
57///
58/// A nibble is a 4-bit value, and this structure is used to store the nibble sequence representing
59/// the keys in a Merkle Patricia Trie (MPT).
60/// Using nibbles simplifies trie operations and enables consistent key representation in the MPT.
61///
62/// # Internal representation
63///
64/// The internal representation is currently a [`U256`] that stores two nibbles per byte. Nibbles
65/// are stored inline (on the stack), and can be up to a length of 64 nibbles, or 32 unpacked bytes.
66///
67/// Additionally, a separate `length` field is stored to track the actual length of the nibble
68/// sequence. When the [`U256`] is modified directly, the `length` field must be updated
69/// accordingly. Otherwise, the behavior is undefined.
70///
71/// Nibbles are stored with most significant bits set first, meaning that a nibble sequence `0x101`
72/// will be stored as `0x101...0`, and not `0x0...101`.
73///
74/// # Examples
75///
76/// ```
77/// use nybbles::Nibbles;
78///
79/// let bytes = [0xAB, 0xCD];
80/// let nibbles = Nibbles::unpack(&bytes);
81/// assert_eq!(nibbles, Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C, 0x0D]));
82/// assert_eq!(nibbles.to_vec(), vec![0x0A, 0x0B, 0x0C, 0x0D]);
83///
84/// let packed = nibbles.pack();
85/// assert_eq!(&packed[..], &bytes[..]);
86/// ```
87#[repr(C)] // We want to preserve the order of fields in the memory layout.
88#[derive(Default, Clone, Copy, Hash, PartialEq, Eq)]
89pub struct Nibbles {
90    /// Nibbles length.
91    // This field goes first, because the derived implementation of `PartialEq` compares the fields
92    // in order, so we can short-circuit the comparison if the `length` field differs.
93    pub(crate) length: usize,
94    /// The nibbles themselves, stored as a 256-bit unsigned integer with most significant bits set
95    /// first.
96    pub(crate) nibbles: U256,
97}
98
99impl fmt::Debug for Nibbles {
100    #[inline]
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        if self.is_empty() {
103            write!(f, "Nibbles(0x)")
104        } else {
105            let shifted = self.nibbles >> ((NIBBLES - self.len()) * 4);
106            write!(f, "Nibbles(0x{:0width$x})", shifted, width = self.len())
107        }
108    }
109}
110
111#[cfg(feature = "arbitrary")]
112impl<'a> arbitrary::Arbitrary<'a> for Nibbles {
113    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
114        let length = u.int_in_range(0..=NIBBLES)?;
115        let nibbles = Nibbles::from_nibbles_unchecked(
116            (0..length).map(|_| u.int_in_range(0..=0xf)).collect::<Result<Vec<_>, _>>()?,
117        );
118        Ok(nibbles)
119    }
120}
121
122// Deriving [`Ord`] for [`Nibbles`] is not correct, because they will be compared as unsigned
123// integers without accounting for length. This is incorrect, because `0x1` should be considered
124// greater than `0x02`.
125impl Ord for Nibbles {
126    #[inline]
127    fn cmp(&self, other: &Self) -> Ordering {
128        let self_len = self.len().div_ceil(2);
129        let other_len = other.len().div_ceil(2);
130        let l = cmp::min(self_len, other_len);
131
132        // Slice to the loop iteration range to enable bound check
133        // elimination in the compiler
134        let lhs = &as_le_slice(&self.nibbles)[U256::BYTES - l..];
135        let rhs = &as_le_slice(&other.nibbles)[U256::BYTES - l..];
136
137        for i in (0..l).rev() {
138            match lhs[i].cmp(&rhs[i]) {
139                Ordering::Equal => (),
140                non_eq => return non_eq,
141            }
142        }
143
144        self.len().cmp(&other.len())
145    }
146}
147
148impl PartialOrd for Nibbles {
149    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
150        Some(self.cmp(other))
151    }
152}
153
154impl FromIterator<u8> for Nibbles {
155    fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
156        let mut nibbles = Self::default();
157        for n in iter {
158            nibbles.push(n);
159        }
160        nibbles
161    }
162}
163
164#[cfg(feature = "rlp")]
165impl alloy_rlp::Encodable for Nibbles {
166    #[inline]
167    fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
168        alloy_rlp::Header { list: true, payload_length: self.len() }.encode(out);
169        for i in 0..self.len() {
170            self.get_unchecked(i).encode(out);
171        }
172    }
173
174    #[inline]
175    fn length(&self) -> usize {
176        let payload_length = self.len();
177        payload_length + alloy_rlp::length_of_length(payload_length)
178    }
179}
180
181#[cfg(feature = "arbitrary")]
182impl proptest::arbitrary::Arbitrary for Nibbles {
183    type Parameters = proptest::collection::SizeRange;
184    type Strategy = proptest::strategy::Map<
185        proptest::collection::VecStrategy<core::ops::RangeInclusive<u8>>,
186        fn(Vec<u8>) -> Self,
187    >;
188
189    #[inline]
190    fn arbitrary_with(size: proptest::collection::SizeRange) -> Self::Strategy {
191        use proptest::prelude::*;
192        proptest::collection::vec(0x0..=0xf, size).prop_map(Self::from_nibbles_unchecked)
193    }
194}
195
196#[cfg(feature = "serde")]
197impl serde::Serialize for Nibbles {
198    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
199    where
200        S: serde::Serializer,
201    {
202        if self.is_empty() {
203            serializer.serialize_str("0x")
204        } else {
205            let shifted = self.nibbles >> ((NIBBLES - self.len()) * 4);
206            let hex_str = format!("0x{:0width$x}", shifted, width = self.len());
207            serializer.serialize_str(&hex_str)
208        }
209    }
210}
211
212#[cfg(feature = "serde")]
213impl<'de> serde::Deserialize<'de> for Nibbles {
214    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
215    where
216        D: serde::Deserializer<'de>,
217    {
218        let s = alloc::borrow::Cow::<str>::deserialize(deserializer)?;
219
220        // Check if string starts with "0x"
221        let hex_str =
222            s.strip_prefix("0x").ok_or_else(|| serde::de::Error::custom("missing 0x prefix"))?;
223
224        // Empty case
225        if hex_str.is_empty() {
226            return Ok(Self::new());
227        }
228
229        // Check length
230        if hex_str.len() > NIBBLES {
231            return Err(serde::de::Error::custom("hex string too long"));
232        }
233
234        // Check that all characters are valid hex characters. We do this once ahead of time so we
235        // can pass an iter into [`Self::from_iter_unchecked`], saving a Vec alloc.
236        for ch in hex_str.chars() {
237            let _ =
238                ch.to_digit(16).ok_or_else(|| serde::de::Error::custom("invalid hex character"))?;
239        }
240
241        let iter = hex_str.chars().map(|ch| ch.to_digit(16).expect("already validated") as u8);
242        Ok(Self::from_iter_unchecked(iter))
243    }
244}
245
246impl Nibbles {
247    /// Creates a new empty [`Nibbles`] instance.
248    ///
249    /// # Examples
250    ///
251    /// ```
252    /// # use nybbles::Nibbles;
253    /// let nibbles = Nibbles::new();
254    /// assert_eq!(nibbles.len(), 0);
255    /// ```
256    #[inline]
257    pub const fn new() -> Self {
258        Self { length: 0, nibbles: U256::ZERO }
259    }
260
261    /// Creates a new [`Nibbles`] instance from the given iterator over nibbles, without checking
262    /// their validity.
263    ///
264    /// Note that only the low nibble of every byte will be stored as a nibble, i.e. for `0x12` we
265    /// will store a nibble `2`.
266    ///
267    /// For checked version, use the [`FromIterator`] implementation.
268    ///
269    /// # Examples
270    ///
271    /// ```
272    /// # use nybbles::Nibbles;
273    /// let nibbles = Nibbles::from_iter_unchecked([0x0A, 0x0B, 0x0C, 0x0D]);
274    /// assert_eq!(nibbles.to_vec(), vec![0x0A, 0x0B, 0x0C, 0x0D]);
275    pub fn from_iter_unchecked<I>(iter: I) -> Self
276    where
277        I: IntoIterator<Item = u8>,
278    {
279        let mut packed = Self::default();
280        for n in iter {
281            packed.push_unchecked(n);
282        }
283        packed
284    }
285
286    /// Creates a new [`Nibbles`] instance from the given nibbles.
287    ///
288    /// # Panics
289    ///
290    /// Panics if the any of the bytes is not a valid nibble (`0..=0x0f`).
291    ///
292    /// # Examples
293    ///
294    /// ```
295    /// # use nybbles::Nibbles;
296    /// let nibbles = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C, 0x0D]);
297    /// assert_eq!(nibbles.to_vec(), vec![0x0A, 0x0B, 0x0C, 0x0D]);
298    /// ```
299    ///
300    /// Invalid values will cause panics:
301    ///
302    /// ```should_panic
303    /// # use nybbles::Nibbles;
304    /// let nibbles = Nibbles::from_nibbles(&[0xFF]);
305    /// ```
306    #[inline]
307    #[track_caller]
308    pub fn from_nibbles<T: AsRef<[u8]>>(nibbles: T) -> Self {
309        let bytes = nibbles.as_ref();
310        check_nibbles(bytes);
311        Self::from_iter_unchecked(bytes.iter().copied())
312    }
313
314    /// Creates a new [`Nibbles`] instance from the given nibbles.
315    ///
316    /// Note that only the low nibble of every byte will be stored as a nibble, i.e. for `0x12` we
317    /// will store a nibble `2`.
318    ///
319    /// For checked version, use [`Nibbles::from_nibbles`].
320    ///
321    /// # Examples
322    ///
323    /// ```
324    /// # use nybbles::Nibbles;
325    /// let nibbles = Nibbles::from_nibbles_unchecked(&[0x0A, 0x0B, 0x0C, 0x0D]);
326    /// assert_eq!(nibbles.to_vec(), vec![0x0A, 0x0B, 0x0C, 0x0D]);
327    /// ```
328    ///
329    /// Invalid values will not cause panics:
330    ///
331    /// ```
332    /// # use nybbles::Nibbles;
333    /// let nibbles = Nibbles::from_nibbles_unchecked(&[0xFF]);
334    /// assert_eq!(nibbles.to_vec(), vec![0x0F]);
335    /// ```
336    #[inline]
337    pub fn from_nibbles_unchecked<T: AsRef<[u8]>>(nibbles: T) -> Self {
338        Self::from_iter_unchecked(nibbles.as_ref().iter().copied())
339    }
340
341    /// Converts a byte slice into a [`Nibbles`] instance containing the nibbles (half-bytes or 4
342    /// bits) that make up the input byte data.
343    ///
344    /// # Panics
345    ///
346    /// Panics if the length of the input is greater than 32 bytes.
347    ///
348    /// # Examples
349    ///
350    /// ```
351    /// # use nybbles::Nibbles;
352    /// let nibbles = Nibbles::unpack(&[0xAB, 0xCD]);
353    /// assert_eq!(nibbles.to_vec(), vec![0x0A, 0x0B, 0x0C, 0x0D]);
354    /// ```
355    ///
356    /// ```should_panic
357    /// # use nybbles::Nibbles;
358    /// let nibbles = Nibbles::unpack(&[0xAB; 33]);
359    /// ```
360    #[inline]
361    #[track_caller]
362    pub fn unpack(data: impl AsRef<[u8]>) -> Self {
363        assert!(data.as_ref().len() <= U256::BYTES);
364        // SAFETY: we checked that the length is less than or equal to the size of U256
365        unsafe { Self::unpack_unchecked(data.as_ref()) }
366    }
367
368    /// Converts a byte slice into a [`Nibbles`] instance containing the nibbles (half-bytes or 4
369    /// bits) that make up the input byte data.
370    ///
371    /// # Safety
372    ///
373    /// The caller must ensure that the length of the input is less than or equal to the size of
374    /// U256, which is 32 bytes.
375    ///
376    /// # Examples
377    ///
378    /// ```
379    /// # use nybbles::Nibbles;
380    /// // SAFETY: the length of the input is less than 32 bytes.
381    /// let nibbles = unsafe { Nibbles::unpack_unchecked(&[0xAB, 0xCD]) };
382    /// assert_eq!(nibbles.to_vec(), vec![0x0A, 0x0B, 0x0C, 0x0D]);
383    /// ```
384    pub unsafe fn unpack_unchecked(data: &[u8]) -> Self {
385        let length = data.len() * 2;
386        debug_assert!(length <= NIBBLES);
387
388        cfg_if! {
389            if #[cfg(target_endian = "little")] {
390                let mut nibbles = U256::ZERO;
391                let nibbles_slice = nibbles.as_le_slice_mut();
392            } else {
393                let mut nibbles_slice = [0u8; 32];
394            }
395        }
396
397        // Source pointer is at the beginning
398        let mut src = data.as_ptr().cast::<u8>();
399        // Move destination pointer to the end of the little endian slice
400        let mut dst = nibbles_slice.as_mut_ptr().add(U256::BYTES);
401        // On each iteration, decrement the destination pointer by one, set the destination
402        // byte, and increment the source pointer by one
403        for _ in 0..data.len() {
404            dst = dst.sub(1);
405            *dst = *src;
406            src = src.add(1);
407        }
408
409        cfg_if! {
410            if #[cfg(target_endian = "big")] {
411                let nibbles = U256::from_le_bytes(nibbles_slice);
412            }
413        }
414
415        Self { length, nibbles }
416    }
417
418    /// Packs the nibbles into the given slice.
419    ///
420    /// This method combines each pair of consecutive nibbles into a single byte,
421    /// effectively reducing the size of the data by a factor of two.
422    ///
423    /// If the number of nibbles is odd, the last nibble is shifted left by 4 bits and
424    /// added to the packed byte vector.
425    ///
426    /// # Examples
427    ///
428    /// ```
429    /// # use nybbles::Nibbles;
430    /// let nibbles = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C]);
431    /// assert_eq!(nibbles.pack()[..], [0xAB, 0xC0]);
432    /// ```
433    #[inline]
434    pub fn pack(&self) -> SmallVec<[u8; 32]> {
435        let packed_len = self.len().div_ceil(2);
436        unsafe { smallvec_with(packed_len, |out| self.pack_to_slice_unchecked(out)) }
437    }
438
439    /// Packs the nibbles into the given slice.
440    ///
441    /// See [`pack`](Self::pack) for more information.
442    ///
443    /// # Panics
444    ///
445    /// Panics if the slice is not at least `(self.len() + 1) / 2` bytes long.
446    ///
447    /// # Examples
448    ///
449    /// ```
450    /// # use nybbles::Nibbles;
451    /// let nibbles = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C]);
452    /// let mut packed = [0; 2];
453    /// nibbles.pack_to(&mut packed);
454    /// assert_eq!(packed[..], [0xAB, 0xC0]);
455    /// ```
456    #[inline]
457    #[track_caller]
458    pub fn pack_to(&self, out: &mut [u8]) {
459        assert!(out.len() >= self.len().div_ceil(2));
460        // SAFETY: asserted length.
461        unsafe { self.pack_to_unchecked(out.as_mut_ptr()) }
462    }
463
464    /// Packs the nibbles into the given pointer.
465    ///
466    /// See [`pack`](Self::pack) for more information.
467    ///
468    /// # Safety
469    ///
470    /// `ptr` must be valid for at least `(self.len() + 1) / 2` bytes.
471    ///
472    /// # Examples
473    ///
474    /// ```
475    /// # use nybbles::Nibbles;
476    /// let nibbles = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C, 0x0D]);
477    /// let mut packed = [0; 2];
478    /// // SAFETY: enough capacity.
479    /// unsafe { nibbles.pack_to_unchecked(packed.as_mut_ptr()) };
480    /// assert_eq!(packed[..], [0xAB, 0xCD]);
481    /// ```
482    #[inline]
483    pub unsafe fn pack_to_unchecked(&self, ptr: *mut u8) {
484        let slice = slice::from_raw_parts_mut(ptr.cast(), self.len().div_ceil(2));
485        pack_to_unchecked(self, slice);
486    }
487
488    /// Packs the nibbles into the given slice without checking its length.
489    ///
490    /// See [`pack`](Self::pack) for more information.
491    ///
492    /// # Safety
493    ///
494    /// `out` must be valid for at least `(self.len() + 1) / 2` bytes.
495    #[inline]
496    pub unsafe fn pack_to_slice_unchecked(&self, out: &mut [MaybeUninit<u8>]) {
497        pack_to_unchecked(self, out)
498    }
499
500    /// Converts the nibbles into a vector of nibbles.
501    ///
502    /// # Examples
503    ///
504    /// ```
505    /// # use nybbles::Nibbles;
506    /// let nibbles = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C, 0x0D]);
507    /// assert_eq!(nibbles.to_vec(), vec![0x0A, 0x0B, 0x0C, 0x0D]);
508    /// ```
509    pub fn to_vec(&self) -> Vec<u8> {
510        self.iter().collect()
511    }
512
513    /// Returns an iterator over the nibbles.
514    ///
515    /// # Examples
516    ///
517    /// ```
518    /// # use nybbles::Nibbles;
519    /// let nibbles = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C, 0x0D]);
520    /// let collected: Vec<u8> = nibbles.iter().collect();
521    /// assert_eq!(collected, vec![0x0A, 0x0B, 0x0C, 0x0D]);
522    /// ```
523    #[inline]
524    pub const fn iter(&self) -> NibblesIter<'_> {
525        NibblesIter { current: 0, nibbles: self }
526    }
527
528    /// Gets the byte at the given index by combining two consecutive nibbles.
529    ///
530    /// # Examples
531    ///
532    /// ```
533    /// # use nybbles::Nibbles;
534    /// let nibbles = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C, 0x0D]);
535    /// assert_eq!(nibbles.get_byte(0), Some(0xAB));
536    /// assert_eq!(nibbles.get_byte(1), Some(0xBC));
537    /// assert_eq!(nibbles.get_byte(2), Some(0xCD));
538    /// assert_eq!(nibbles.get_byte(3), None);
539    /// ```
540    pub fn get_byte(&self, i: usize) -> Option<u8> {
541        if likely((i < usize::MAX) & self.check_index(i.wrapping_add(1))) {
542            Some(self.get_byte_unchecked(i))
543        } else {
544            None
545        }
546    }
547
548    /// Gets the byte at the given index by combining two consecutive nibbles.
549    ///
550    /// # Panics
551    ///
552    /// Panics if `i..i + 1` is out of bounds.
553    ///
554    /// # Examples
555    ///
556    /// ```
557    /// # use nybbles::Nibbles;
558    /// let nibbles = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C, 0x0D]);
559    /// // SAFETY: in range.
560    /// unsafe {
561    ///     assert_eq!(nibbles.get_byte_unchecked(0), 0xAB);
562    ///     assert_eq!(nibbles.get_byte_unchecked(1), 0xBC);
563    ///     assert_eq!(nibbles.get_byte_unchecked(2), 0xCD);
564    /// }
565    /// ```
566    #[inline]
567    #[track_caller]
568    pub fn get_byte_unchecked(&self, i: usize) -> u8 {
569        self.assert_index(i);
570        if i % 2 == 0 {
571            as_le_slice(&self.nibbles)[U256::BYTES - i / 2 - 1]
572        } else {
573            self.get_unchecked(i) << 4 | self.get_unchecked(i + 1)
574        }
575    }
576
577    /// Increments the nibble sequence by one.
578    #[inline]
579    pub fn increment(&self) -> Option<Self> {
580        if self.is_empty() || self.nibbles == SLICE_MASKS[self.len()] {
581            return None;
582        }
583
584        let mut incremented = *self;
585        let add = INCREMENT_VALUES[self.len()];
586        incremented.nibbles += add;
587        Some(incremented)
588    }
589
590    /// The last element of the hex vector is used to determine whether the nibble sequence
591    /// represents a leaf or an extension node. If the last element is 0x10 (16), then it's a leaf.
592    #[inline]
593    pub fn is_leaf(&self) -> bool {
594        self.last() == Some(16)
595    }
596
597    /// Returns `true` if this nibble sequence starts with the given prefix.
598    pub fn starts_with(&self, other: &Self) -> bool {
599        // Fast path: if lengths don't allow prefix, return false
600        if other.len() > self.len() {
601            return false;
602        }
603
604        // Fast path: empty prefix always matches
605        if other.is_empty() {
606            return true;
607        }
608
609        // Direct comparison using masks
610        let mask = SLICE_MASKS[other.len()];
611        (self.nibbles & mask) == other.nibbles
612    }
613
614    /// Returns `true` if this nibble sequence ends with the given suffix.
615    pub fn ends_with(&self, other: &Self) -> bool {
616        // If other is empty, it's a suffix of any sequence
617        if other.is_empty() {
618            return true;
619        }
620
621        // If other is longer than self, it can't be a suffix
622        if other.len() > self.len() {
623            return false;
624        }
625
626        // Fast path for even-even and odd-odd sequences
627        if self.len() % 2 == other.len() % 2 {
628            return as_le_slice(&self.nibbles)
629                [(NIBBLES - self.len()) / 2..(NIBBLES - self.len() + other.len()) / 2]
630                == as_le_slice(&other.nibbles)[(NIBBLES - other.len()) / 2..];
631        }
632
633        let mut i = 0;
634        while i < other.len() {
635            if self.get_unchecked(self.len() - i - 1) != other.get_unchecked(other.len() - i - 1) {
636                return false;
637            }
638            i += 1;
639        }
640
641        true
642    }
643
644    /// Returns the nibble at the given index.
645    #[inline]
646    pub fn get(&self, i: usize) -> Option<u8> {
647        if self.check_index(i) {
648            Some(self.get_unchecked(i))
649        } else {
650            None
651        }
652    }
653
654    /// Returns the nibble at the given index.
655    ///
656    /// # Panics
657    ///
658    /// Panics if the index is out of bounds.
659    #[inline]
660    #[track_caller]
661    pub fn get_unchecked(&self, i: usize) -> u8 {
662        self.assert_index(i);
663        let byte = as_le_slice(&self.nibbles)[U256::BYTES - i / 2 - 1];
664        if i % 2 == 0 {
665            byte >> 4
666        } else {
667            byte & 0x0F
668        }
669    }
670
671    /// Sets the nibble at the given index.
672    ///
673    /// # Panics
674    ///
675    /// Panics if the index is out of bounds, or if `value` is not a valid nibble (`0..=0x0f`).
676    #[inline]
677    #[track_caller]
678    pub fn set_at(&mut self, i: usize, value: u8) {
679        assert!(self.check_index(i) && value <= 0xf);
680        // SAFETY: index is checked above
681        unsafe { self.set_at_unchecked(i, value) };
682    }
683
684    /// Sets the nibble at the given index, without checking its validity.
685    ///
686    /// # Safety
687    ///
688    /// The caller must ensure that the index is within bounds.
689    #[inline]
690    pub unsafe fn set_at_unchecked(&mut self, i: usize, value: u8) {
691        let byte_index = U256::BYTES - i / 2 - 1;
692
693        // SAFETY: index checked above
694        cfg_if! {
695            if #[cfg(target_endian = "little")] {
696                let byte = unsafe { &mut self.nibbles.as_le_slice_mut()[byte_index] };
697            } else {
698                // Big-endian targets must first copy the nibbles to a little-endian slice.
699                // Underneath the hood, `as_le_slice` will perform a stack copy, and we
700                // replace the underlying `nibbles` after we've updated the given nibble.
701                let mut le_copy = as_le_slice(&self.nibbles);
702                let byte = &mut le_copy.to_mut()[byte_index];
703            }
704        }
705
706        if i % 2 == 0 {
707            *byte = *byte & 0x0f | value << 4;
708        } else {
709            *byte = *byte & 0xf0 | value;
710        }
711
712        // For big-endian targets, replace the underlying U256 with the mutated LE slice.
713        #[cfg(target_endian = "big")]
714        {
715            self.nibbles = U256::from_le_slice(&le_copy);
716        }
717    }
718
719    /// Returns the first nibble of this nibble sequence.
720    #[inline]
721    pub fn first(&self) -> Option<u8> {
722        self.get(0)
723    }
724
725    /// Returns the last nibble of this nibble sequence.
726    #[inline]
727    pub fn last(&self) -> Option<u8> {
728        let len = self.len();
729        if len == 0 {
730            None
731        } else {
732            Some(self.get_unchecked(len - 1))
733        }
734    }
735
736    /// Returns the length of the common prefix between this nibble sequence and the given.
737    ///
738    /// # Examples
739    ///
740    /// ```
741    /// # use nybbles::Nibbles;
742    /// let a = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]);
743    /// let b = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C, 0x0E]);
744    /// assert_eq!(a.common_prefix_length(&b), 3);
745    /// ```
746    pub fn common_prefix_length(&self, other: &Self) -> usize {
747        // Handle empty cases
748        if self.is_empty() || other.is_empty() {
749            return 0;
750        }
751
752        let min_nibble_len = self.len().min(other.len());
753
754        // Fast path for small sequences that fit in one u64 limb
755        if min_nibble_len <= 16 {
756            // Extract the highest u64 limb which contains all the nibbles
757            let self_limb = self.nibbles.as_limbs()[3];
758            let other_limb = other.nibbles.as_limbs()[3];
759
760            // Create mask for the nibbles we care about
761            let mask = u64::MAX << ((16 - min_nibble_len) * 4);
762            let xor = (self_limb ^ other_limb) & mask;
763
764            if xor == 0 {
765                return min_nibble_len;
766            } else {
767                return xor.leading_zeros() as usize / 4;
768            }
769        }
770
771        let xor = if min_nibble_len == NIBBLES && self.len() == other.len() {
772            // No need to mask for 64 nibble sequences, just XOR
773            self.nibbles ^ other.nibbles
774        } else {
775            // For other lengths, mask the nibbles we care about, and then XOR
776            let mask = SLICE_MASKS[min_nibble_len];
777            (self.nibbles ^ other.nibbles) & mask
778        };
779
780        if xor == U256::ZERO {
781            min_nibble_len
782        } else {
783            xor.leading_zeros() / 4
784        }
785    }
786
787    /// Returns the total number of bits in this [`Nibbles`].
788    #[inline]
789    const fn bit_len(&self) -> usize {
790        self.len() * 4
791    }
792
793    /// Returns `true` if this [`Nibbles`] is empty.
794    #[inline]
795    pub const fn is_empty(&self) -> bool {
796        self.len() == 0
797    }
798
799    /// Returns the total number of nibbles in this [`Nibbles`].
800    #[inline]
801    pub const fn len(&self) -> usize {
802        let len = self.length;
803        debug_assert!(len <= 64);
804        unsafe { core::hint::assert_unchecked(len <= 64) };
805        len
806    }
807
808    /// Returns a mutable reference to the underlying [`U256`].
809    ///
810    /// Note that it is possible to create invalid [`Nibbles`] instances using this method. See
811    /// [the type docs](Self) for more details.
812    #[inline]
813    pub fn as_mut_uint_unchecked(&mut self) -> &mut U256 {
814        &mut self.nibbles
815    }
816
817    /// Creates new nibbles containing the nibbles in the specified range `[start, end)`
818    /// without checking bounds.
819    ///
820    /// # Safety
821    ///
822    /// This method does not verify that the provided range is valid for this nibble sequence.
823    /// The caller must ensure that `start <= end` and `end <= self.len()`.
824    #[inline]
825    pub fn slice_unchecked(&self, start: usize, end: usize) -> Self {
826        // Fast path for empty slice
827        if end == 0 || end <= start {
828            return Self::new();
829        }
830
831        // Fast path for full slice
832        let slice_to_end = end == self.len();
833        if start == 0 && slice_to_end {
834            return *self;
835        }
836
837        let nibble_len = end - start;
838
839        // Optimize for common case where start == 0
840        let nibbles = if start == 0 {
841            // When slicing from the beginning, we can just apply the mask and avoid XORing
842            self.nibbles & SLICE_MASKS[end]
843        } else {
844            // For middle and to_end cases, always shift first
845            let shifted = self.nibbles << (start * 4);
846            if slice_to_end {
847                // When slicing to the end, no mask needed after shift
848                shifted
849            } else {
850                // For middle slices, apply end mask after shift
851                shifted & SLICE_MASKS[end - start]
852            }
853        };
854
855        Self { length: nibble_len, nibbles }
856    }
857
858    /// Creates new nibbles containing the nibbles in the specified range.
859    ///
860    /// # Panics
861    ///
862    /// This method will panic if the range is out of bounds for this nibble sequence.
863    pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
864        // Determine the start and end nibble indices from the range bounds
865        let start = match range.start_bound() {
866            Bound::Included(&idx) => idx,
867            Bound::Excluded(&idx) => idx + 1,
868            Bound::Unbounded => 0,
869        };
870        let end = match range.end_bound() {
871            Bound::Included(&idx) => idx + 1,
872            Bound::Excluded(&idx) => idx,
873            Bound::Unbounded => self.len(),
874        };
875        assert!(start <= end, "Cannot slice with a start index greater than the end index");
876        assert!(
877            end <= self.len(),
878            "Cannot slice with an end index greater than the length of the nibbles"
879        );
880
881        self.slice_unchecked(start, end)
882    }
883
884    /// Join two nibble sequences together.
885    #[inline]
886    pub fn join(&self, other: &Self) -> Self {
887        let mut new = *self;
888        new.extend(other);
889        new
890    }
891
892    /// Pushes a nibble to the end of the current nibbles.
893    ///
894    /// # Panics
895    ///
896    /// Panics if the nibble is not a valid nibble (`0..=0x0f`).
897    #[inline]
898    #[track_caller]
899    pub fn push(&mut self, nibble: u8) {
900        assert!(nibble <= 0xf);
901        self.push_unchecked(nibble);
902    }
903
904    /// Pushes a nibble to the end of the current nibbles without checking its validity.
905    ///
906    /// Note that only the low nibble of the byte is used. For example, for byte `0x12`, only the
907    /// nibble `0x2` is pushed.
908    #[inline]
909    pub fn push_unchecked(&mut self, nibble: u8) {
910        let nibble_val = (nibble & 0x0F) as u64;
911        if nibble_val == 0 {
912            // Nothing to do, limb nibbles are already set to zero by default
913            self.length += 1;
914            return;
915        }
916
917        let bit_pos = (NIBBLES - self.len() - 1) * 4;
918        let limb_idx = bit_pos / 64;
919        let shift_in_limb = bit_pos % 64;
920
921        // SAFETY: limb_idx is always valid because bit_pos < 256
922        unsafe {
923            let limbs = self.nibbles.as_limbs_mut();
924            limbs[limb_idx] |= nibble_val << shift_in_limb;
925        }
926
927        self.length += 1;
928    }
929
930    /// Pops a nibble from the end of the current nibbles.
931    pub fn pop(&mut self) -> Option<u8> {
932        if self.is_empty() {
933            return None;
934        }
935
936        // The last nibble is at bit position (64 - length) * 4 from the MSB
937        let shift = (NIBBLES - self.len()) * 4;
938
939        // Extract the nibble - after shifting right, it's in the lowest bits of limb 0
940        let nibble = (self.nibbles >> shift).as_limbs()[0] as u8 & 0xF;
941
942        // Clear the nibble using a more efficient mask creation
943        // Instead of U256::from(0xF_u8) << shift, we can create the mask directly
944        let mask_limb_idx = shift / 64;
945        let mask_shift = shift % 64;
946
947        if mask_limb_idx < 4 {
948            // SAFETY: We know the limb index is valid
949            unsafe {
950                let limbs = self.nibbles.as_limbs_mut();
951                limbs[mask_limb_idx] &= !(0xF << mask_shift);
952            }
953        }
954
955        self.length -= 1;
956        Some(nibble)
957    }
958
959    /// Extend the current nibbles with another nibbles.
960    pub fn extend(&mut self, other: &Nibbles) {
961        if other.is_empty() {
962            return;
963        }
964
965        self.nibbles |= other.nibbles >> self.bit_len();
966        self.length += other.length;
967    }
968
969    /// Extend the current nibbles with another byte slice.
970    pub fn extend_from_slice(&mut self, other: &[u8]) {
971        assert!(
972            self.length + other.len() * 2 <= NIBBLES,
973            "Cannot extend: resulting length would exceed maximum capacity"
974        );
975        self.extend_from_slice_unchecked(other);
976    }
977
978    /// Extend the current nibbles with another byte slice.
979    ///
980    /// # Caution
981    ///
982    /// This method does not check if the resulting length would exceed the maximum capacity of
983    /// [`Nibbles`].
984    pub fn extend_from_slice_unchecked(&mut self, other: &[u8]) {
985        if other.is_empty() {
986            return;
987        }
988
989        let len_bytes = other.len();
990        let mut other = U256::from_be_slice(other);
991        if len_bytes > 0 {
992            other <<= (U256::BYTES - len_bytes) * 8;
993        }
994        self.nibbles |= other >> self.bit_len();
995        self.length += len_bytes * 2;
996    }
997
998    /// Truncates the current nibbles to the given length.
999    #[inline]
1000    pub fn truncate(&mut self, new_len: usize) {
1001        assert!(
1002            new_len <= self.len(),
1003            "Cannot truncate to a length greater than the current length"
1004        );
1005        *self = self.slice_unchecked(0, new_len);
1006    }
1007
1008    /// Clears the current nibbles.
1009    #[inline]
1010    pub fn clear(&mut self) {
1011        *self = Self::new();
1012    }
1013
1014    /// Checks if the given index is within the bounds of the current nibbles.
1015    #[inline]
1016    const fn check_index(&self, i: usize) -> bool {
1017        i < self.len()
1018    }
1019
1020    /// Panics if the given index is out of bounds of the current nibbles.
1021    #[inline]
1022    fn assert_index(&self, i: usize) {
1023        let len = self.len();
1024        if i >= len {
1025            panic_invalid_index(len, i);
1026        }
1027    }
1028}
1029
1030/// Iterator over individual nibbles within a [`Nibbles`] structure.
1031///
1032/// This iterator provides efficient access to each nibble in sequence,
1033/// using unchecked access for performance.
1034///
1035/// # Examples
1036///
1037/// ```
1038/// # use nybbles::Nibbles;
1039/// let nibbles = Nibbles::from_nibbles(&[0x0A, 0x0B, 0x0C, 0x0D]);
1040/// let collected: Vec<u8> = nibbles.iter().collect();
1041/// assert_eq!(collected, vec![0x0A, 0x0B, 0x0C, 0x0D]);
1042/// ```
1043#[derive(Debug, Clone)]
1044pub struct NibblesIter<'a> {
1045    /// Current position in the iteration.
1046    current: usize,
1047    /// Reference to the nibbles being iterated over.
1048    nibbles: &'a Nibbles,
1049}
1050
1051impl<'a> Iterator for NibblesIter<'a> {
1052    type Item = u8;
1053
1054    #[inline]
1055    fn next(&mut self) -> Option<Self::Item> {
1056        self.nibbles.get(self.current).inspect(|_| self.current += 1)
1057    }
1058
1059    #[inline]
1060    fn size_hint(&self) -> (usize, Option<usize>) {
1061        let len = self.len();
1062        (len, Some(len))
1063    }
1064}
1065
1066impl<'a> ExactSizeIterator for NibblesIter<'a> {
1067    #[inline]
1068    fn len(&self) -> usize {
1069        self.nibbles.len() - self.current
1070    }
1071}
1072
1073/// Packs the nibbles into the given slice without checking its length.
1074///
1075/// # Safety
1076///
1077/// `out` must be valid for at least `(self.len() + 1) / 2` bytes.
1078#[inline]
1079unsafe fn pack_to_unchecked(nibbles: &Nibbles, out: &mut [MaybeUninit<u8>]) {
1080    let byte_len = nibbles.len().div_ceil(2);
1081    debug_assert!(out.len() >= byte_len);
1082    // Move source pointer to the end of the little endian slice
1083    let sl = as_le_slice(&nibbles.nibbles);
1084    let mut src = sl.as_ptr().add(U256::BYTES);
1085    // Destination pointer is at the beginning of the output slice
1086    let mut dst = out.as_mut_ptr().cast::<u8>();
1087    // On each iteration, decrement the source pointer by one, set the destination byte, and
1088    // increment the destination pointer by one
1089    for _ in 0..byte_len {
1090        src = src.sub(1);
1091        *dst = *src;
1092        dst = dst.add(1);
1093    }
1094}
1095
1096/// Initializes a smallvec with the given length and a closure that initializes the buffer.
1097///
1098/// Optimized version of `SmallVec::with_capacity` + `f()` + `.set_len`.
1099///
1100/// # Safety
1101///
1102/// The closure must fully initialize the buffer with the given length.
1103#[inline]
1104pub unsafe fn smallvec_with<const N: usize>(
1105    len: usize,
1106    f: impl FnOnce(&mut [MaybeUninit<u8>]),
1107) -> SmallVec<[u8; N]> {
1108    let mut buf = smallvec_with_len::<N>(len);
1109    f(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr().cast(), len) });
1110    buf
1111}
1112
1113#[inline]
1114#[allow(clippy::uninit_vec)]
1115unsafe fn smallvec_with_len<const N: usize>(len: usize) -> SmallVec<[u8; N]> {
1116    if likely(len <= N) {
1117        SmallVec::from_buf_and_len_unchecked(MaybeUninit::<[u8; N]>::uninit(), len)
1118    } else {
1119        let mut vec = Vec::with_capacity(len);
1120        unsafe { vec.set_len(len) };
1121        SmallVec::from_vec(vec)
1122    }
1123}
1124
1125#[inline]
1126#[track_caller]
1127fn check_nibbles(nibbles: &[u8]) {
1128    if !valid_nibbles(nibbles) {
1129        panic_invalid_nibbles();
1130    }
1131}
1132
1133fn valid_nibbles(nibbles: &[u8]) -> bool {
1134    nibbles.iter().all(|&nibble| nibble <= 0xf)
1135}
1136
1137#[cold]
1138#[inline(never)]
1139#[cfg_attr(debug_assertions, track_caller)]
1140const fn panic_invalid_nibbles() -> ! {
1141    panic!("attempted to create invalid nibbles");
1142}
1143
1144#[cold]
1145#[inline(never)]
1146#[cfg_attr(debug_assertions, track_caller)]
1147fn panic_invalid_index(len: usize, i: usize) -> ! {
1148    panic!("index out of bounds: {i} for nibbles of length {len}");
1149}
1150
1151/// Internal container for owned/borrowed byte slices.
1152enum ByteContainer<'a, const N: usize> {
1153    /// Borrowed variant holds a reference to a slice of bytes.
1154    #[cfg_attr(target_endian = "big", allow(unused))]
1155    Borrowed(&'a [u8]),
1156    /// Owned variant holds a fixed-size array of bytes.
1157    #[cfg_attr(target_endian = "little", allow(unused))]
1158    Owned([u8; N]),
1159}
1160
1161impl<'a, const N: usize> ByteContainer<'a, N> {
1162    /// Returns a mutable reference to the underlying byte array, converting from borrowed to owned
1163    /// if necessary.
1164    ///
1165    /// ## Panics
1166    /// Panics if the current variant is `Borrowed` and the slice length is less than `N`.
1167    #[cfg_attr(target_endian = "little", allow(unused))]
1168    pub(crate) fn to_mut(&mut self) -> &mut [u8; N] {
1169        match self {
1170            ByteContainer::Borrowed(slice) => {
1171                let mut array = [0u8; N];
1172                array[..N].copy_from_slice(&slice[..N]);
1173                *self = ByteContainer::Owned(array);
1174                self.to_mut()
1175            }
1176            ByteContainer::Owned(ref mut array) => array,
1177        }
1178    }
1179}
1180
1181impl<'a, const N: usize> Deref for ByteContainer<'a, N> {
1182    type Target = [u8];
1183
1184    fn deref(&self) -> &Self::Target {
1185        match self {
1186            ByteContainer::Borrowed(slice) => slice,
1187            ByteContainer::Owned(array) => array.as_slice(),
1188        }
1189    }
1190}
1191
1192/// Returns a little-endian byte slice representation of the given [`U256`] value.
1193#[inline]
1194const fn as_le_slice(x: &U256) -> ByteContainer<'_, { U256::BYTES }> {
1195    cfg_if! {
1196        if #[cfg(target_endian = "little")] {
1197            ByteContainer::Borrowed(x.as_le_slice())
1198        } else {
1199            ByteContainer::Owned(x.to_le_bytes())
1200        }
1201    }
1202}
1203
1204#[cfg(test)]
1205mod tests {
1206    use super::*;
1207
1208    #[test]
1209    fn pack() {
1210        let tests = [
1211            (&[][..], &[][..]),
1212            (&[0xa], &[0xa0]),
1213            (&[0xa, 0x0], &[0xa0]),
1214            (&[0xa, 0xb], &[0xab]),
1215            (&[0xa, 0xb, 0x2], &[0xab, 0x20]),
1216            (&[0xa, 0xb, 0x2, 0x0], &[0xab, 0x20]),
1217            (&[0xa, 0xb, 0x2, 0x7], &[0xab, 0x27]),
1218        ];
1219        for (input, expected) in tests {
1220            assert!(valid_nibbles(input));
1221            let nibbles = Nibbles::from_nibbles(input);
1222            let encoded = nibbles.pack();
1223            assert_eq!(
1224                &encoded[..],
1225                expected,
1226                "input: {input:x?}, expected: {expected:x?}, got: {encoded:x?}",
1227            );
1228        }
1229    }
1230
1231    #[test]
1232    fn get_unchecked() {
1233        for len in 0..NIBBLES {
1234            let raw = (0..16).cycle().take(len).collect::<Vec<u8>>();
1235            let nibbles = Nibbles::from_nibbles(&raw);
1236            for (i, raw_nibble) in raw.into_iter().enumerate() {
1237                assert_eq!(nibbles.get_unchecked(i), raw_nibble);
1238            }
1239        }
1240    }
1241
1242    #[test]
1243    fn set_at_unchecked() {
1244        for len in 0..=NIBBLES {
1245            let raw = (0..16).cycle().take(len).collect::<Vec<u8>>();
1246            let mut nibbles = Nibbles::from_nibbles(&raw);
1247            for (i, raw_nibble) in raw.iter().enumerate() {
1248                let new_nibble = (raw_nibble + 1) % 16;
1249                unsafe { nibbles.set_at_unchecked(i, new_nibble) };
1250
1251                let mut new_raw_nibbles = nibbles.clone().to_vec();
1252                new_raw_nibbles[i] = new_nibble;
1253                let new_nibbles = Nibbles::from_nibbles(&new_raw_nibbles);
1254                assert_eq!(nibbles, new_nibbles,);
1255            }
1256        }
1257    }
1258
1259    #[test]
1260    fn push_pop() {
1261        let mut nibbles = Nibbles::new();
1262        nibbles.push(0x0A);
1263        assert_eq!(nibbles.get_unchecked(0), 0x0A);
1264        assert_eq!(nibbles.len(), 1);
1265
1266        assert_eq!(nibbles.pop(), Some(0x0A));
1267        assert_eq!(nibbles.len(), 0);
1268    }
1269
1270    #[test]
1271    fn get_byte() {
1272        let nibbles = Nibbles::from_nibbles([0x0A, 0x0B, 0x0C, 0x0D]);
1273        assert_eq!(nibbles.get_byte(0), Some(0xAB));
1274        assert_eq!(nibbles.get_byte(1), Some(0xBC));
1275        assert_eq!(nibbles.get_byte(2), Some(0xCD));
1276        assert_eq!(nibbles.get_byte(3), None);
1277        assert_eq!(nibbles.get_byte(usize::MAX), None);
1278    }
1279
1280    #[test]
1281    fn get_byte_unchecked() {
1282        let nibbles = Nibbles::from_nibbles([0x0A, 0x0B, 0x0C, 0x0D]);
1283        assert_eq!(nibbles.get_byte_unchecked(0), 0xAB);
1284        assert_eq!(nibbles.get_byte_unchecked(1), 0xBC);
1285        assert_eq!(nibbles.get_byte_unchecked(2), 0xCD);
1286    }
1287
1288    #[test]
1289    fn clone() {
1290        let a = Nibbles::from_nibbles([1, 2, 3]);
1291        #[allow(clippy::redundant_clone)]
1292        let b = a;
1293        assert_eq!(a, b);
1294    }
1295
1296    #[test]
1297    fn ord() {
1298        // Test empty nibbles
1299        let nibbles1 = Nibbles::default();
1300        let nibbles2 = Nibbles::default();
1301        assert_eq!(nibbles1.cmp(&nibbles2), Ordering::Equal);
1302
1303        // Test with one empty
1304        let nibbles1 = Nibbles::default();
1305        let nibbles2 = Nibbles::from_nibbles([0]);
1306        assert_eq!(nibbles2.cmp(&nibbles1), Ordering::Greater);
1307
1308        // Test with same nibbles
1309        let nibbles1 = Nibbles::unpack([0x12, 0x34]);
1310        let nibbles2 = Nibbles::unpack([0x12, 0x34]);
1311        assert_eq!(nibbles1.cmp(&nibbles2), Ordering::Equal);
1312
1313        // Test with different lengths
1314        let short = Nibbles::unpack([0x12]);
1315        let long = Nibbles::unpack([0x12, 0x34]);
1316        assert_eq!(short.cmp(&long), Ordering::Less);
1317
1318        // Test with common prefix but different values
1319        let nibbles1 = Nibbles::unpack([0x12, 0x34]);
1320        let nibbles2 = Nibbles::unpack([0x12, 0x35]);
1321        assert_eq!(nibbles1.cmp(&nibbles2), Ordering::Less);
1322
1323        // Test with differing first byte
1324        let nibbles1 = Nibbles::unpack([0x12, 0x34]);
1325        let nibbles2 = Nibbles::unpack([0x13, 0x34]);
1326        assert_eq!(nibbles1.cmp(&nibbles2), Ordering::Less);
1327
1328        // Test with odd length nibbles
1329        let nibbles1 = Nibbles::unpack([0x1]);
1330        let nibbles2 = Nibbles::unpack([0x2]);
1331        assert_eq!(nibbles1.cmp(&nibbles2), Ordering::Less);
1332
1333        // Test with odd and even length nibbles
1334        let odd = Nibbles::unpack([0x1]);
1335        let even = Nibbles::unpack([0x12]);
1336        assert_eq!(odd.cmp(&even), Ordering::Less);
1337
1338        // Test with longer sequences
1339        let nibbles1 = Nibbles::unpack([0x12, 0x34, 0x56, 0x78]);
1340        let nibbles2 = Nibbles::unpack([0x12, 0x34, 0x56, 0x79]);
1341        assert_eq!(nibbles1.cmp(&nibbles2), Ordering::Less);
1342
1343        let nibbles1 = Nibbles::from_nibbles([0x0, 0x0]);
1344        let nibbles2 = Nibbles::from_nibbles([0x1]);
1345        assert_eq!(nibbles1.cmp(&nibbles2), Ordering::Less);
1346
1347        let nibbles1 = Nibbles::from_nibbles([0x1]);
1348        let nibbles2 = Nibbles::from_nibbles([0x0, 0x2]);
1349        assert_eq!(nibbles1.cmp(&nibbles2), Ordering::Greater);
1350
1351        let nibbles1 = Nibbles::from_nibbles([vec![0; 61], vec![1; 1], vec![0; 1]].concat());
1352        let nibbles2 = Nibbles::from_nibbles([vec![0; 61], vec![1; 1], vec![0; 2]].concat());
1353        assert_eq!(nibbles1.cmp(&nibbles2), Ordering::Less);
1354    }
1355
1356    #[test]
1357    fn starts_with() {
1358        let nibbles = Nibbles::from_nibbles([1, 2, 3, 4]);
1359
1360        // Test empty nibbles
1361        let empty = Nibbles::default();
1362        assert!(nibbles.starts_with(&empty));
1363        assert!(empty.starts_with(&empty));
1364        assert!(!empty.starts_with(&nibbles));
1365
1366        // Test with same nibbles
1367        assert!(nibbles.starts_with(&nibbles));
1368
1369        // Test with prefix
1370        let prefix = Nibbles::from_nibbles([1, 2]);
1371        assert!(nibbles.starts_with(&prefix));
1372        assert!(!prefix.starts_with(&nibbles));
1373
1374        // Test with different first nibble
1375        let different = Nibbles::from_nibbles([2, 2, 3, 4]);
1376        assert!(!nibbles.starts_with(&different));
1377
1378        // Test with longer sequence
1379        let longer = Nibbles::from_nibbles([1, 2, 3, 4, 5, 6]);
1380        assert!(!nibbles.starts_with(&longer));
1381
1382        // Test with even nibbles and odd prefix
1383        let even_nibbles = Nibbles::from_nibbles([1, 2, 3, 4]);
1384        let odd_prefix = Nibbles::from_nibbles([1, 2, 3]);
1385        assert!(even_nibbles.starts_with(&odd_prefix));
1386
1387        // Test with odd nibbles and even prefix
1388        let odd_nibbles = Nibbles::from_nibbles([1, 2, 3]);
1389        let even_prefix = Nibbles::from_nibbles([1, 2]);
1390        assert!(odd_nibbles.starts_with(&even_prefix));
1391    }
1392
1393    #[test]
1394    fn ends_with() {
1395        let nibbles = Nibbles::from_nibbles([1, 2, 3, 4]);
1396
1397        // Test empty nibbles
1398        let empty = Nibbles::default();
1399        assert!(nibbles.ends_with(&empty));
1400        assert!(empty.ends_with(&empty));
1401        assert!(!empty.ends_with(&nibbles));
1402
1403        // Test with same nibbles
1404        assert!(nibbles.ends_with(&nibbles));
1405
1406        // Test with suffix
1407        let suffix = Nibbles::from_nibbles([3, 4]);
1408        assert!(nibbles.ends_with(&suffix));
1409        assert!(!suffix.ends_with(&nibbles));
1410
1411        // Test with different last nibble
1412        let different = Nibbles::from_nibbles([2, 3, 5]);
1413        assert!(!nibbles.ends_with(&different));
1414
1415        // Test with longer sequence
1416        let longer = Nibbles::from_nibbles([2, 3, 4, 5, 6]);
1417        assert!(!nibbles.ends_with(&longer));
1418
1419        // Test with even nibbles and odd suffix
1420        let even_nibbles = Nibbles::from_nibbles([1, 2, 3, 4]);
1421        let odd_suffix = Nibbles::from_nibbles([2, 3, 4]);
1422        assert!(even_nibbles.ends_with(&odd_suffix));
1423
1424        // Test with odd nibbles and even suffix
1425        let odd_nibbles = Nibbles::from_nibbles([1, 2, 3]);
1426        let even_suffix = Nibbles::from_nibbles([2, 3]);
1427        assert!(odd_nibbles.ends_with(&even_suffix));
1428    }
1429
1430    #[test]
1431    fn slice() {
1432        // Test with empty nibbles
1433        let empty = Nibbles::default();
1434        assert_eq!(empty.slice(..), empty);
1435
1436        // Test with even number of nibbles
1437        let even = Nibbles::from_nibbles([0, 1, 2, 3, 4, 5]);
1438
1439        // Full slice
1440        assert_eq!(even.slice(..), even);
1441        assert_eq!(even.slice(0..6), even);
1442
1443        // Empty slice
1444        assert_eq!(even.slice(3..3), Nibbles::default());
1445
1446        // Beginning slices (even start)
1447        assert_eq!(even.slice(0..2), Nibbles::from_iter(0..2));
1448
1449        // Middle slices (even start, even end)
1450        assert_eq!(even.slice(2..4), Nibbles::from_iter(2..4));
1451
1452        // End slices (even start)
1453        assert_eq!(even.slice(4..6), Nibbles::from_iter(4..6));
1454
1455        // Test with odd number of nibbles
1456        let odd = Nibbles::from_iter(0..5);
1457
1458        // Full slice
1459        assert_eq!(odd.slice(..), odd);
1460        assert_eq!(odd.slice(0..5), odd);
1461
1462        // Beginning slices (odd length)
1463        assert_eq!(odd.slice(0..3), Nibbles::from_iter(0..3));
1464
1465        // Middle slices with odd start
1466        assert_eq!(odd.slice(1..4), Nibbles::from_iter(1..4));
1467
1468        // Middle slices with odd end
1469        assert_eq!(odd.slice(1..3), Nibbles::from_iter(1..3));
1470
1471        // End slices (odd start)
1472        assert_eq!(odd.slice(2..5), Nibbles::from_iter(2..5));
1473
1474        // Special cases - both odd start and end
1475        assert_eq!(odd.slice(1..4), Nibbles::from_iter(1..4));
1476
1477        // Single nibble slices
1478        assert_eq!(even.slice(2..3), Nibbles::from_iter(2..3));
1479
1480        assert_eq!(even.slice(3..4), Nibbles::from_iter(3..4));
1481
1482        // Test with alternate syntax
1483        assert_eq!(even.slice(2..), Nibbles::from_iter(2..6));
1484        assert_eq!(even.slice(..4), Nibbles::from_iter(0..4));
1485        assert_eq!(even.slice(..=3), Nibbles::from_iter(0..4));
1486
1487        // More complex test case with the max length array sliced at the end
1488        assert_eq!(
1489            Nibbles::from_iter((0..16).cycle().take(64)).slice(1..),
1490            Nibbles::from_iter((0..16).cycle().take(64).skip(1))
1491        );
1492    }
1493
1494    #[test]
1495    fn common_prefix_length() {
1496        // Test with empty nibbles
1497        let empty = Nibbles::default();
1498        assert_eq!(empty.common_prefix_length(&empty), 0);
1499
1500        // Test with same nibbles
1501        let nibbles1 = Nibbles::from_nibbles([1, 2, 3, 4]);
1502        let nibbles2 = Nibbles::from_nibbles([1, 2, 3, 4]);
1503        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 4);
1504        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 4);
1505
1506        // Test with partial common prefix (byte aligned)
1507        let nibbles1 = Nibbles::from_nibbles([1, 2, 3, 4]);
1508        let nibbles2 = Nibbles::from_nibbles([1, 2, 5, 6]);
1509        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 2);
1510        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 2);
1511
1512        // Test with partial common prefix (half-byte aligned)
1513        let nibbles1 = Nibbles::from_nibbles([1, 2, 3, 4]);
1514        let nibbles2 = Nibbles::from_nibbles([1, 2, 3, 7]);
1515        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 3);
1516        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 3);
1517
1518        // Test with no common prefix
1519        let nibbles1 = Nibbles::from_nibbles([5, 6, 7, 8]);
1520        let nibbles2 = Nibbles::from_nibbles([1, 2, 3, 4]);
1521        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 0);
1522        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 0);
1523
1524        // Test with different lengths but common prefix
1525        let nibbles1 = Nibbles::from_nibbles([1, 2, 3, 4, 5, 6]);
1526        let nibbles2 = Nibbles::from_nibbles([1, 2, 3]);
1527        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 3);
1528        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 3);
1529
1530        // Test with odd number of nibbles
1531        let nibbles1 = Nibbles::from_nibbles([1, 2, 3]);
1532        let nibbles2 = Nibbles::from_nibbles([1, 2, 7]);
1533        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 2);
1534        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 2);
1535
1536        // Test with half-byte difference in first byte
1537        let nibbles1 = Nibbles::from_nibbles([1, 2, 3, 4]);
1538        let nibbles2 = Nibbles::from_nibbles([5, 2, 3, 4]);
1539        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 0);
1540        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 0);
1541
1542        // Test with one empty and one non-empty
1543        let nibbles1 = Nibbles::from_nibbles([1, 2, 3, 4]);
1544        assert_eq!(nibbles1.common_prefix_length(&empty), 0);
1545        assert_eq!(empty.common_prefix_length(&nibbles1), 0);
1546
1547        // Test with longer sequences (16 nibbles)
1548        let nibbles1 =
1549            Nibbles::from_nibbles([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]);
1550        let nibbles2 =
1551            Nibbles::from_nibbles([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1]);
1552        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 15);
1553        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 15);
1554
1555        // Test with different lengths but same prefix (32 vs 16 nibbles)
1556        let nibbles1 =
1557            Nibbles::from_nibbles([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]);
1558        let nibbles2 = Nibbles::from_nibbles([
1559            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1560            11, 12, 13, 14, 15, 0,
1561        ]);
1562        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 16);
1563        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 16);
1564
1565        // Test with very long sequences (32 nibbles) with different endings
1566        let nibbles1 = Nibbles::from_nibbles([
1567            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1568            11, 12, 13, 14, 15, 0,
1569        ]);
1570        let nibbles2 = Nibbles::from_nibbles([
1571            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1572            11, 12, 13, 14, 15, 1,
1573        ]);
1574        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 31);
1575        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 31);
1576
1577        // Test with 48 nibbles with different endings
1578        let nibbles1 = Nibbles::from_nibbles([
1579            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1580            11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0,
1581        ]);
1582        let nibbles2 = Nibbles::from_nibbles([
1583            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1584            11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1,
1585        ]);
1586        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 47);
1587        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 47);
1588
1589        // Test with 64 nibbles with different endings
1590        let nibbles1 = Nibbles::from_nibbles([
1591            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1592            11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3,
1593            4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0,
1594        ]);
1595        let nibbles2 = Nibbles::from_nibbles([
1596            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1597            11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3,
1598            4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1,
1599        ]);
1600        assert_eq!(nibbles1.common_prefix_length(&nibbles2), 63);
1601        assert_eq!(nibbles2.common_prefix_length(&nibbles1), 63);
1602
1603        let current = Nibbles::from_nibbles([0u8; 64]);
1604        let path = Nibbles::from_nibbles([vec![0u8; 63], vec![2u8]].concat());
1605        assert_eq!(current.common_prefix_length(&path), 63);
1606
1607        let current = Nibbles::from_nibbles([0u8; 63]);
1608        let path = Nibbles::from_nibbles([vec![0u8; 62], vec![1u8], vec![0u8]].concat());
1609        assert_eq!(current.common_prefix_length(&path), 62);
1610    }
1611
1612    #[test]
1613    fn truncate() {
1614        // Test truncating empty nibbles
1615        let mut nibbles = Nibbles::default();
1616        nibbles.truncate(0);
1617        assert_eq!(nibbles, Nibbles::default());
1618
1619        // Test truncating to zero length
1620        let mut nibbles = Nibbles::from_nibbles([1, 2, 3, 4]);
1621        nibbles.truncate(0);
1622        assert_eq!(nibbles, Nibbles::default());
1623
1624        // Test truncating to same length (should be no-op)
1625        let mut nibbles = Nibbles::from_nibbles([1, 2, 3, 4]);
1626        nibbles.truncate(4);
1627        assert_eq!(nibbles, Nibbles::from_nibbles([1, 2, 3, 4]));
1628
1629        // Individual nibble test with a simple 2-nibble truncation
1630        let mut nibbles = Nibbles::from_nibbles([1, 2, 3, 4]);
1631        nibbles.truncate(2);
1632        assert_eq!(nibbles, Nibbles::from_nibbles([1, 2]));
1633
1634        // Test simple truncation
1635        let mut nibbles = Nibbles::from_nibbles([1, 2, 3, 4]);
1636        nibbles.truncate(2);
1637        assert_eq!(nibbles, Nibbles::from_nibbles([1, 2]));
1638
1639        // Test truncating to single nibble
1640        let mut nibbles = Nibbles::from_nibbles([5, 6, 7, 8]);
1641        nibbles.truncate(1);
1642        assert_eq!(nibbles, Nibbles::from_nibbles([5]));
1643    }
1644
1645    #[test]
1646    fn push_unchecked() {
1647        // Test pushing to empty nibbles
1648        let mut nibbles = Nibbles::default();
1649        nibbles.push_unchecked(0x5);
1650        assert_eq!(nibbles, Nibbles::from_nibbles([0x5]));
1651
1652        // Test pushing a second nibble
1653        nibbles.push_unchecked(0xA);
1654        assert_eq!(nibbles, Nibbles::from_nibbles([0x5, 0xA]));
1655
1656        // Test pushing multiple nibbles to build a sequence
1657        let mut nibbles = Nibbles::default();
1658        for nibble in [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8] {
1659            nibbles.push_unchecked(nibble);
1660        }
1661        assert_eq!(nibbles, Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]));
1662
1663        // Test pushing nibbles with values that exceed 4 bits (should be masked to 0x0F)
1664        let mut nibbles = Nibbles::default();
1665        nibbles.push_unchecked(0xFF); // Should become 0xF
1666        nibbles.push_unchecked(0x1A); // Should become 0xA
1667        nibbles.push_unchecked(0x25); // Should become 0x5
1668        assert_eq!(nibbles, Nibbles::from_nibbles([0xF, 0xA, 0x5]));
1669
1670        // Test pushing to existing nibbles (adding to the end)
1671        let mut nibbles = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
1672        nibbles.push_unchecked(0x4);
1673        assert_eq!(nibbles, Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]));
1674
1675        // Test boundary values (0 and 15)
1676        let mut nibbles = Nibbles::default();
1677        nibbles.push_unchecked(0x0);
1678        nibbles.push_unchecked(0xF);
1679        assert_eq!(nibbles, Nibbles::from_nibbles([0x0, 0xF]));
1680
1681        // Test pushing many nibbles to verify no overflow issues
1682        let mut nibbles = Nibbles::default();
1683        let test_sequence: Vec<u8> = (0..32).map(|i| i % 16).collect();
1684        for &nibble in &test_sequence {
1685            nibbles.push_unchecked(nibble);
1686        }
1687        assert_eq!(nibbles, Nibbles::from_nibbles(test_sequence));
1688    }
1689
1690    #[test]
1691    fn unpack() {
1692        for (test_idx, bytes) in (0..=32).map(|i| vec![0xFF; i]).enumerate() {
1693            let packed_nibbles = Nibbles::unpack(&bytes);
1694            let nibbles = Nibbles::unpack(&bytes);
1695
1696            assert_eq!(
1697                packed_nibbles.len(),
1698                nibbles.len(),
1699                "Test case {test_idx}: Length mismatch for bytes {bytes:?}",
1700            );
1701            assert_eq!(
1702                packed_nibbles.len(),
1703                bytes.len() * 2,
1704                "Test case {test_idx}: Expected length to be 2x byte length",
1705            );
1706
1707            // Compare each nibble individually
1708            for i in 0..packed_nibbles.len() {
1709                assert_eq!(
1710                    packed_nibbles.get_unchecked(i),
1711                    nibbles.get_unchecked(i),
1712                    "Test case {}: Nibble at index {} differs for bytes {:?}: Nibbles={:?}, Nibbles={:?}",
1713                    test_idx,
1714                    i,
1715                    bytes,
1716                    packed_nibbles.get_unchecked(i),
1717                    nibbles.get_unchecked(i)
1718                );
1719            }
1720        }
1721
1722        let nibbles = Nibbles::unpack([0xAB, 0xCD]);
1723        assert_eq!(nibbles.to_vec(), vec![0x0A, 0x0B, 0x0C, 0x0D]);
1724    }
1725
1726    #[test]
1727    fn increment() {
1728        // Test basic increment
1729        assert_eq!(
1730            Nibbles::from_nibbles([0x0, 0x0, 0x0]).increment().unwrap(),
1731            Nibbles::from_nibbles([0x0, 0x0, 0x1])
1732        );
1733
1734        // Test increment with carry
1735        assert_eq!(
1736            Nibbles::from_nibbles([0x0, 0x0, 0xF]).increment().unwrap(),
1737            Nibbles::from_nibbles([0x0, 0x1, 0x0])
1738        );
1739
1740        // Test multiple carries
1741        assert_eq!(
1742            Nibbles::from_nibbles([0x0, 0xF, 0xF]).increment().unwrap(),
1743            Nibbles::from_nibbles([0x1, 0x0, 0x0])
1744        );
1745
1746        // Test increment from all F's except first nibble
1747        assert_eq!(
1748            Nibbles::from_nibbles([0xE, 0xF, 0xF]).increment().unwrap(),
1749            Nibbles::from_nibbles([0xF, 0x0, 0x0])
1750        );
1751
1752        // Test overflow - all nibbles are 0xF
1753        assert_eq!(Nibbles::from_nibbles([0xF, 0xF, 0xF]).increment(), None);
1754
1755        // Test empty nibbles
1756        assert_eq!(Nibbles::new().increment(), None);
1757
1758        // Test single nibble
1759        assert_eq!(Nibbles::from_nibbles([0x5]).increment().unwrap(), Nibbles::from_nibbles([0x6]));
1760
1761        // Test single nibble at max
1762        assert_eq!(Nibbles::from_nibbles([0xF]).increment(), None);
1763
1764        // Test longer sequence
1765        assert_eq!(
1766            Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]).increment().unwrap(),
1767            Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x6])
1768        );
1769
1770        // Test longer sequence with carries
1771        assert_eq!(
1772            Nibbles::from_nibbles([0x1, 0x2, 0x3, 0xF, 0xF]).increment().unwrap(),
1773            Nibbles::from_nibbles([0x1, 0x2, 0x4, 0x0, 0x0])
1774        );
1775    }
1776
1777    #[test]
1778    fn iter() {
1779        // Test empty nibbles
1780        let empty = Nibbles::new();
1781        assert!(empty.iter().collect::<Vec<_>>().is_empty());
1782
1783        // Test basic iteration
1784        let nibbles = Nibbles::from_nibbles([0x0A, 0x0B, 0x0C, 0x0D]);
1785        let collected: Vec<u8> = nibbles.iter().collect();
1786        assert_eq!(collected, vec![0x0A, 0x0B, 0x0C, 0x0D]);
1787
1788        // Test that iter() produces same result as to_vec()
1789        assert_eq!(nibbles.iter().collect::<Vec<_>>(), nibbles.to_vec());
1790
1791        // Test single nibble
1792        let single = Nibbles::from_nibbles([0x05]);
1793        assert_eq!(single.iter().collect::<Vec<_>>(), vec![0x05]);
1794
1795        // Test odd number of nibbles
1796        let odd = Nibbles::from_nibbles([0x01, 0x02, 0x03]);
1797        assert_eq!(odd.iter().collect::<Vec<_>>(), vec![0x01, 0x02, 0x03]);
1798
1799        // Test max length nibbles
1800        let max_nibbles: Vec<u8> = (0..64).map(|i| (i % 16) as u8).collect();
1801        let max = Nibbles::from_nibbles(&max_nibbles);
1802        assert_eq!(max.iter().collect::<Vec<_>>(), max_nibbles);
1803
1804        // Test iterator size_hint and len
1805        let nibbles = Nibbles::from_nibbles([0x0A, 0x0B, 0x0C, 0x0D]);
1806        let mut iter = nibbles.iter();
1807        assert_eq!(iter.len(), 4);
1808        assert_eq!(iter.size_hint(), (4, Some(4)));
1809
1810        iter.next();
1811        assert_eq!(iter.len(), 3);
1812        assert_eq!(iter.size_hint(), (3, Some(3)));
1813
1814        iter.next();
1815        iter.next();
1816        assert_eq!(iter.len(), 1);
1817        assert_eq!(iter.size_hint(), (1, Some(1)));
1818
1819        iter.next();
1820        assert_eq!(iter.len(), 0);
1821        assert_eq!(iter.size_hint(), (0, Some(0)));
1822        assert_eq!(iter.next(), None);
1823
1824        // Test cloning iterator
1825        let nibbles = Nibbles::from_nibbles([0x01, 0x02, 0x03, 0x04]);
1826        let mut iter1 = nibbles.iter();
1827        iter1.next();
1828        let iter2 = iter1.clone();
1829
1830        assert_eq!(iter1.collect::<Vec<_>>(), vec![0x02, 0x03, 0x04]);
1831        assert_eq!(iter2.collect::<Vec<_>>(), vec![0x02, 0x03, 0x04]);
1832    }
1833
1834    #[cfg(feature = "arbitrary")]
1835    mod arbitrary {
1836        use super::*;
1837        use proptest::{collection::vec, prelude::*};
1838
1839        proptest::proptest! {
1840            #[test]
1841            #[cfg_attr(miri, ignore = "no proptest")]
1842            fn pack_unpack_roundtrip(input in vec(any::<u8>(), 0..32)) {
1843                let nibbles = Nibbles::unpack(&input);
1844                prop_assert!(valid_nibbles(&nibbles.to_vec()));
1845                let packed = nibbles.pack();
1846                prop_assert_eq!(&packed[..], input);
1847            }
1848        }
1849    }
1850
1851    #[cfg(feature = "serde")]
1852    mod serde_tests {
1853        use super::*;
1854        use crate::alloc::string::ToString;
1855
1856        #[test]
1857        fn serde_empty() {
1858            let nibbles = Nibbles::new();
1859            let serialized = serde_json::to_string(&nibbles).unwrap();
1860            assert_eq!(serialized, r#""0x""#);
1861
1862            let deserialized: Nibbles = serde_json::from_str(&serialized).unwrap();
1863            assert_eq!(deserialized, nibbles);
1864        }
1865
1866        #[test]
1867        fn serde_single_nibble() {
1868            let nibbles = Nibbles::from_nibbles([0x5]);
1869            let serialized = serde_json::to_string(&nibbles).unwrap();
1870            assert_eq!(serialized, r#""0x5""#);
1871
1872            let deserialized: Nibbles = serde_json::from_str(&serialized).unwrap();
1873            assert_eq!(deserialized, nibbles);
1874        }
1875
1876        #[test]
1877        fn serde_multiple_nibbles() {
1878            let nibbles = Nibbles::from_nibbles([0x0A, 0x0B, 0x0C, 0x0D]);
1879            let serialized = serde_json::to_string(&nibbles).unwrap();
1880            assert_eq!(serialized, r#""0xabcd""#);
1881
1882            let deserialized: Nibbles = serde_json::from_str(&serialized).unwrap();
1883            assert_eq!(deserialized, nibbles);
1884        }
1885
1886        #[test]
1887        fn serde_odd_nibbles() {
1888            let nibbles = Nibbles::from_nibbles([0x0A, 0x0B, 0x0C]);
1889            let serialized = serde_json::to_string(&nibbles).unwrap();
1890            assert_eq!(serialized, r#""0xabc""#);
1891
1892            let deserialized: Nibbles = serde_json::from_str(&serialized).unwrap();
1893            assert_eq!(deserialized, nibbles);
1894        }
1895
1896        #[test]
1897        fn serde_leading_zeros() {
1898            let nibbles = Nibbles::from_nibbles([0x0, 0x0, 0x1, 0x2]);
1899            let serialized = serde_json::to_string(&nibbles).unwrap();
1900            assert_eq!(serialized, r#""0x0012""#);
1901
1902            let deserialized: Nibbles = serde_json::from_str(&serialized).unwrap();
1903            assert_eq!(deserialized, nibbles);
1904        }
1905
1906        #[test]
1907        fn serde_max_nibbles() {
1908            let nibbles = Nibbles::from_nibbles([0xF; 64]);
1909            let serialized = serde_json::to_string(&nibbles).unwrap();
1910            assert_eq!(
1911                serialized,
1912                r#""0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff""#
1913            );
1914
1915            let deserialized: Nibbles = serde_json::from_str(&serialized).unwrap();
1916            assert_eq!(deserialized, nibbles);
1917        }
1918
1919        #[test]
1920        fn deserialize_missing_prefix() {
1921            let result: Result<Nibbles, _> = serde_json::from_str(r#""abcd""#);
1922            assert!(result.is_err());
1923            assert!(result.unwrap_err().to_string().contains("missing 0x prefix"));
1924        }
1925
1926        #[test]
1927        fn deserialize_invalid_hex() {
1928            let result: Result<Nibbles, _> = serde_json::from_str(r#""0xghij""#);
1929            assert!(result.is_err());
1930            assert!(result.unwrap_err().to_string().contains("invalid hex character"));
1931        }
1932
1933        #[test]
1934        fn deserialize_too_long() {
1935            let too_long = format!(r#""0x{}""#, "f".repeat(65));
1936            let result: Result<Nibbles, _> = serde_json::from_str(&too_long);
1937            assert!(result.is_err());
1938            assert!(result.unwrap_err().to_string().contains("hex string too long"));
1939        }
1940
1941        #[test]
1942        fn serde_from_object() {
1943            // Test deserializing when the Nibbles is embedded in an object
1944            #[derive(serde::Serialize, serde::Deserialize)]
1945            struct TestStruct {
1946                nibbles: Nibbles,
1947            }
1948
1949            let original = TestStruct { nibbles: Nibbles::from_nibbles([0x0A, 0x0B, 0x0C, 0x0D]) };
1950            let json = serde_json::to_string(&original).unwrap();
1951            let deserialized: TestStruct = serde_json::from_str(&json).unwrap();
1952            assert_eq!(deserialized.nibbles, original.nibbles);
1953        }
1954
1955        #[test]
1956        fn serde_from_parsed_value() {
1957            // Test deserializing from a pre-parsed JSON value
1958            let json_str = r#"{"nibbles": "0xabcd"}"#;
1959            let value: serde_json::Value = serde_json::from_str(json_str).unwrap();
1960            let nibbles: Nibbles = serde_json::from_value(value["nibbles"].clone()).unwrap();
1961            assert_eq!(nibbles, Nibbles::from_nibbles([0x0A, 0x0B, 0x0C, 0x0D]));
1962        }
1963    }
1964}