@@ -89,7 +89,7 @@ static INCREMENT_VALUES: [U256; 65] = {
8989#[ derive( Default , Clone , Copy , Eq ) ]
9090pub struct Nibbles {
9191 /// Nibbles length.
92- pub ( crate ) length : usize ,
92+ pub ( crate ) len : usize ,
9393 /// The nibbles themselves,
9494 /// stored as a 256-bit unsigned integer with most significant bits set first.
9595 pub ( crate ) nibbles : U256 ,
@@ -117,7 +117,7 @@ impl PartialEq for Nibbles {
117117 {
118118 arr == other_arr
119119 } else {
120- self . length == other. length && self . nibbles == other. nibbles
120+ self . len == other. len && self . nibbles == other. nibbles
121121 }
122122 }
123123}
@@ -128,7 +128,7 @@ impl core::hash::Hash for Nibbles {
128128 if let Some ( arr) = self . as_array ( ) {
129129 arr. hash ( state) ;
130130 } else {
131- self . length . hash ( state) ;
131+ self . len . hash ( state) ;
132132 self . nibbles . hash ( state) ;
133133 }
134134 }
@@ -295,7 +295,7 @@ impl Nibbles {
295295 /// ```
296296 #[ inline]
297297 pub const fn new ( ) -> Self {
298- Self { length : 0 , nibbles : U256 :: ZERO }
298+ Self { len : 0 , nibbles : U256 :: ZERO }
299299 }
300300
301301 /// Creates a new [`Nibbles`] instance from the given iterator over nibbles, without checking
@@ -422,8 +422,8 @@ impl Nibbles {
422422 /// assert_eq!(nibbles.to_vec(), vec![0x0A, 0x0B, 0x0C, 0x0D]);
423423 /// ```
424424 pub unsafe fn unpack_unchecked ( data : & [ u8 ] ) -> Self {
425- let length = data. len ( ) * 2 ;
426- debug_assert ! ( length <= NIBBLES ) ;
425+ let len = data. len ( ) * 2 ;
426+ debug_assert ! ( len <= NIBBLES ) ;
427427
428428 cfg_if ! {
429429 if #[ cfg( target_endian = "little" ) ] {
@@ -454,15 +454,15 @@ impl Nibbles {
454454 }
455455 }
456456
457- Self { length , nibbles }
457+ Self { len , nibbles }
458458 }
459459
460460 /// Converts a fixed 32 byte array into a [`Nibbles`] instance. Similar to [`Nibbles::unpack`],
461461 /// but is not `unsafe`.
462462 #[ inline]
463463 pub const fn unpack_array ( data : & [ u8 ; 32 ] ) -> Self {
464464 let nibbles = U256 :: from_be_bytes ( * data) ;
465- Self { length : 64 , nibbles }
465+ Self { len : NIBBLES , nibbles }
466466 }
467467
468468 /// Packs the nibbles into the given slice.
@@ -841,9 +841,9 @@ impl Nibbles {
841841 /// Returns the total number of nibbles in this [`Nibbles`].
842842 #[ inline]
843843 pub const fn len ( & self ) -> usize {
844- let len = self . length ;
845- debug_assert ! ( len <= 64 ) ;
846- unsafe { core:: hint:: assert_unchecked ( len <= 64 ) } ;
844+ let len = self . len ;
845+ debug_assert ! ( len <= NIBBLES ) ;
846+ unsafe { core:: hint:: assert_unchecked ( len <= NIBBLES ) } ;
847847 len
848848 }
849849
@@ -885,8 +885,8 @@ impl Nibbles {
885885 let result = self . increment ( ) ?;
886886
887887 // truncate to position of last non-zero Nibble
888- let length = NIBBLES - ( result. nibbles . trailing_zeros ( ) / 4 ) ;
889- Some ( Self { length , nibbles : result. nibbles } )
888+ let len = NIBBLES - ( result. nibbles . trailing_zeros ( ) / 4 ) ;
889+ Some ( Self { len , nibbles : result. nibbles } )
890890 }
891891
892892 /// Creates new nibbles containing the nibbles in the specified range `[start, end)`
@@ -898,36 +898,22 @@ impl Nibbles {
898898 /// The caller must ensure that `start <= end` and `end <= self.len()`.
899899 #[ inline]
900900 pub fn slice_unchecked ( & self , start : usize , end : usize ) -> Self {
901- // Fast path for empty slice
902- if end == 0 || end <= start {
901+ #[ cfg( debug_assertions) ]
902+ self . slice_check ( start, end) ;
903+ let len = end - start;
904+ if len == 0 {
903905 return Self :: new ( ) ;
904906 }
905-
906- // Fast path for full slice
907- let slice_to_end = end == self . len ( ) ;
908- if start == 0 && slice_to_end {
907+ if len == self . len ( ) {
909908 return * self ;
910909 }
911-
912- let nibble_len = end - start;
913-
914- // Optimize for common case where start == 0
915- let nibbles = if start == 0 {
916- // When slicing from the beginning, we can just apply the mask and avoid XORing
917- self . nibbles & SLICE_MASKS [ end]
918- } else {
919- // For middle and to_end cases, always shift first
920- let shifted = self . nibbles << ( start * 4 ) ;
921- if slice_to_end {
922- // When slicing to the end, no mask needed after shift
923- shifted
924- } else {
925- // For middle slices, apply end mask after shift
926- shifted & SLICE_MASKS [ end - start]
927- }
928- } ;
929-
930- Self { length : nibble_len, nibbles }
910+ let mask = SLICE_MASKS [ len] ;
911+ let mut nibbles = self . nibbles ;
912+ if start != 0 {
913+ nibbles <<= start * 4 ;
914+ }
915+ nibbles &= mask;
916+ Self { len, nibbles }
931917 }
932918
933919 /// Creates new nibbles containing the nibbles in the specified range.
@@ -947,15 +933,22 @@ impl Nibbles {
947933 Bound :: Excluded ( & idx) => idx,
948934 Bound :: Unbounded => self . len ( ) ,
949935 } ;
950- assert ! ( start <= end, "Cannot slice with a start index greater than the end index" ) ;
951- assert ! (
952- end <= self . len( ) ,
953- "Cannot slice with an end index greater than the length of the nibbles"
954- ) ;
936+ self . slice_check ( start, end) ;
937+ // Extra hint to remove the bounds check in `slice_unchecked`.
938+ // SAFETY: `start <= end <= self.len() <= NIBBLES`
939+ unsafe { core:: hint:: assert_unchecked ( end - start <= NIBBLES ) } ;
955940
956941 self . slice_unchecked ( start, end)
957942 }
958943
944+ #[ inline]
945+ #[ cfg_attr( debug_assertions, track_caller) ]
946+ const fn slice_check ( & self , start : usize , end : usize ) {
947+ if !( start <= end && end <= self . len ( ) ) {
948+ panic_invalid_slice ( start, end, self . len ( ) ) ;
949+ }
950+ }
951+
959952 /// Join two nibble sequences together.
960953 #[ inline]
961954 pub fn join ( & self , other : & Self ) -> Self {
@@ -983,7 +976,7 @@ impl Nibbles {
983976 #[ inline]
984977 pub const fn push_unchecked ( & mut self , nibble : u8 ) {
985978 let len = self . len ( ) ;
986- self . length = len + 1 ;
979+ self . len = len + 1 ;
987980 let _ = self . len ( ) ; // Assert invariant.
988981
989982 let nibble_val = ( nibble & 0x0F ) as u64 ;
@@ -1028,7 +1021,7 @@ impl Nibbles {
10281021 }
10291022 }
10301023
1031- self . length -= 1 ;
1024+ self . len -= 1 ;
10321025 Some ( nibble)
10331026 }
10341027
@@ -1040,7 +1033,7 @@ impl Nibbles {
10401033 }
10411034
10421035 self . nibbles |= other. nibbles >> self . bit_len ( ) ;
1043- self . length += other. length ;
1036+ self . len += other. len ;
10441037 }
10451038
10461039 /// Extend the current nibbles with another byte slice.
@@ -1050,6 +1043,7 @@ impl Nibbles {
10501043 }
10511044
10521045 #[ inline]
1046+ #[ cfg_attr( debug_assertions, track_caller) ]
10531047 fn extend_check ( & self , other_len : usize ) {
10541048 assert ! (
10551049 self . len( ) + other_len <= NIBBLES ,
@@ -1074,7 +1068,7 @@ impl Nibbles {
10741068 other <<= ( U256 :: BYTES - len_bytes) * 8 ;
10751069 }
10761070 self . nibbles |= other >> self . bit_len ( ) ;
1077- self . length += len_bytes * 2 ;
1071+ self . len += len_bytes * 2 ;
10781072 }
10791073
10801074 /// Truncates the current nibbles to the given length.
@@ -1249,6 +1243,15 @@ fn panic_invalid_index(len: usize, i: usize) -> ! {
12491243 panic ! ( "index out of bounds: {i} for nibbles of length {len}" ) ;
12501244}
12511245
1246+ #[ cold]
1247+ #[ inline( never) ]
1248+ #[ cfg_attr( debug_assertions, track_caller) ]
1249+ const fn panic_invalid_slice ( start : usize , end : usize , len : usize ) -> ! {
1250+ assert ! ( start <= end, "Cannot slice with a start index greater than the end index" ) ;
1251+ assert ! ( end <= len, "Cannot slice with an end index greater than the length of the nibbles" ) ;
1252+ unreachable ! ( )
1253+ }
1254+
12521255/// Internal container for owned/borrowed byte slices.
12531256enum ByteContainer < ' a , const N : usize > {
12541257 /// Borrowed variant holds a reference to a slice of bytes.
0 commit comments