@@ -59,12 +59,18 @@ impl CStr {
5959 /// Returns the length of this string excluding `NUL`.
6060 #[ inline]
6161 pub const fn len ( & self ) -> usize {
62- self . 0 . len ( ) - 1
62+ self . len_with_nul ( ) - 1
6363 }
6464
6565 /// Returns the length of this string with `NUL`.
6666 #[ inline]
6767 pub const fn len_with_nul ( & self ) -> usize {
68+ // SAFETY: This is one of the invariant of `CStr`.
69+ // We add a `unreachable_unchecked` here to hint the optimizer that
70+ // the value returned from this function is non-zero.
71+ if self . 0 . is_empty ( ) {
72+ unsafe { core:: hint:: unreachable_unchecked ( ) } ;
73+ }
6874 self . 0 . len ( )
6975 }
7076
@@ -99,7 +105,9 @@ impl CStr {
99105 return Err ( CStrConvertError :: NotNulTerminated ) ;
100106 }
101107 let mut i = 0 ;
102- while i < bytes. len ( ) - 1 {
108+ // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
109+ // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
110+ while i + 1 < bytes. len ( ) {
103111 if bytes[ i] == 0 {
104112 return Err ( CStrConvertError :: InteriorNul ) ;
105113 }
@@ -148,7 +156,7 @@ impl CStr {
148156 /// Convert the string to a byte slice without the trailing 0 byte.
149157 #[ inline]
150158 pub fn as_bytes ( & self ) -> & [ u8 ] {
151- & self . 0 [ ..self . 0 . len ( ) - 1 ]
159+ & self . 0 [ ..self . len ( ) ]
152160 }
153161
154162 /// Convert the string to a byte slice containing the trailing 0 byte.
@@ -178,14 +186,12 @@ impl Index<ops::RangeFrom<usize>> for CStr {
178186 type Output = CStr ;
179187
180188 #[ inline]
189+ // Clippy false positive
190+ #[ allow( clippy:: unnecessary_operation) ]
181191 fn index ( & self , index : ops:: RangeFrom < usize > ) -> & Self :: Output {
182- assert ! (
183- index. start <= self . len( ) ,
184- "range start index {} out of range for slice of length {}" ,
185- index. start,
186- self . len( )
187- ) ;
188- // SAFETY: We just checked the length.
192+ // Delegate bounds checking to slice.
193+ & self . as_bytes ( ) [ index. start ..] ;
194+ // SAFETY: We just checked the bounds.
189195 unsafe { Self :: from_bytes_with_nul_unchecked ( & self . 0 [ index. start ..] ) }
190196 }
191197}
0 commit comments