@@ -718,7 +718,7 @@ impl<'a> Iterator for Lines<'a> {
718
718
None
719
719
} else {
720
720
let line = self . string ;
721
- // SAFETY: Slicing `..0` is always valid and yields an empty slice
721
+ // SAFETY: An empty string is a valid string.
722
722
self . string = unsafe { AsciiStr :: from_ascii_unchecked ( b"" ) } ;
723
723
Some ( line)
724
724
}
@@ -732,21 +732,37 @@ impl<'a> DoubleEndedIterator for Lines<'a> {
732
732
}
733
733
734
734
// If we end with `LF` / `CR/LF`, remove them
735
- if let [ slice @ .., AsciiChar :: CarriageReturn , AsciiChar :: LineFeed ]
736
- | [ slice @ .., AsciiChar :: LineFeed ] = self . string . as_slice ( )
737
- {
738
- self . string = slice. into ( ) ;
735
+ if let Some ( AsciiChar :: LineFeed ) = self . string . last ( ) {
736
+ // SAFETY: `last()` returned `Some`, so our len is at least 1.
737
+ self . string = unsafe {
738
+ self . string
739
+ . as_slice ( )
740
+ . get_unchecked ( ..self . string . len ( ) - 1 )
741
+ . into ( )
742
+ } ;
743
+
744
+ if let Some ( AsciiChar :: CarriageReturn ) = self . string . last ( ) {
745
+ // SAFETY: `last()` returned `Some`, so our len is at least 1.
746
+ self . string = unsafe {
747
+ self . string
748
+ . as_slice ( )
749
+ . get_unchecked ( ..self . string . len ( ) - 1 )
750
+ . into ( )
751
+ } ;
752
+ }
739
753
}
740
754
741
- // SAFETY: This will never be `0`, as we remove any `LF` from the end, it is `1..len`
755
+ // Get the position of the first `LF` from the end.
742
756
let lf_rev_pos = self
743
757
. string
744
758
. chars ( )
745
759
. rev ( )
746
760
. position ( |ch| ch == AsciiChar :: LineFeed )
747
761
. unwrap_or_else ( || self . string . len ( ) ) ;
748
762
749
- // SAFETY: As per above, `self.len() - lf_rev_pos` will be in range `0..len - 1`, so both indexes are correct.
763
+ // SAFETY: `lf_rev_pos` will be in range `0..=len`, so `len - lf_rev_pos`
764
+ // will be within `0..=len`, making it correct as a start and end
765
+ // point for the strings.
750
766
let line = unsafe {
751
767
self . string
752
768
. as_slice ( )
@@ -1171,7 +1187,7 @@ mod tests {
1171
1187
let mut_arr_mut_ref: & mut [ AsciiChar ] = & mut [ AsciiChar :: A ] ;
1172
1188
let mut string = "A" . to_string ( ) ;
1173
1189
let mut string2 = "A" . to_string ( ) ;
1174
- let string_mut = string. as_mut ( ) ;
1190
+ let string_mut = string. as_mut_str ( ) ;
1175
1191
let string_mut_bytes = unsafe { string2. as_bytes_mut ( ) } ; // SAFETY: We don't modify it
1176
1192
1177
1193
// Note: This is a trick because `rustfmt` doesn't support
@@ -1427,6 +1443,15 @@ mod tests {
1427
1443
assert_eq ! ( iter. next_back( ) , Some ( "baz" . as_ascii_str( ) . unwrap( ) ) ) ;
1428
1444
assert_eq ! ( iter. next_back( ) , Some ( "" . as_ascii_str( ) . unwrap( ) ) ) ;
1429
1445
assert_eq ! ( iter. next( ) , Some ( "bar" . as_ascii_str( ) . unwrap( ) ) ) ;
1446
+
1447
+ let empty_lines = b"\n \r \n \n \r \n " ;
1448
+ let mut iter_count = 0 ;
1449
+ let ascii = AsciiStr :: from_ascii ( & empty_lines) . unwrap ( ) ;
1450
+ for line in ascii. lines ( ) . rev ( ) {
1451
+ iter_count += 1 ;
1452
+ assert ! ( line. is_empty( ) ) ;
1453
+ }
1454
+ assert_eq ! ( 4 , iter_count) ;
1430
1455
}
1431
1456
1432
1457
#[ test]
0 commit comments