@@ -718,7 +718,7 @@ impl<'a> Iterator for Lines<'a> {
718718 None
719719 } else {
720720 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.
722722 self . string = unsafe { AsciiStr :: from_ascii_unchecked ( b"" ) } ;
723723 Some ( line)
724724 }
@@ -732,21 +732,37 @@ impl<'a> DoubleEndedIterator for Lines<'a> {
732732 }
733733
734734 // 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+ }
739753 }
740754
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.
742756 let lf_rev_pos = self
743757 . string
744758 . chars ( )
745759 . rev ( )
746760 . position ( |ch| ch == AsciiChar :: LineFeed )
747761 . unwrap_or_else ( || self . string . len ( ) ) ;
748762
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.
750766 let line = unsafe {
751767 self . string
752768 . as_slice ( )
@@ -1171,7 +1187,7 @@ mod tests {
11711187 let mut_arr_mut_ref: & mut [ AsciiChar ] = & mut [ AsciiChar :: A ] ;
11721188 let mut string = "A" . to_string ( ) ;
11731189 let mut string2 = "A" . to_string ( ) ;
1174- let string_mut = string. as_mut ( ) ;
1190+ let string_mut = string. as_mut_str ( ) ;
11751191 let string_mut_bytes = unsafe { string2. as_bytes_mut ( ) } ; // SAFETY: We don't modify it
11761192
11771193 // Note: This is a trick because `rustfmt` doesn't support
@@ -1427,6 +1443,15 @@ mod tests {
14271443 assert_eq ! ( iter. next_back( ) , Some ( "baz" . as_ascii_str( ) . unwrap( ) ) ) ;
14281444 assert_eq ! ( iter. next_back( ) , Some ( "" . as_ascii_str( ) . unwrap( ) ) ) ;
14291445 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) ;
14301455 }
14311456
14321457 #[ test]
0 commit comments