Skip to content

Commit acde5df

Browse files
authored
Rollup merge of rust-lang#100311 - xfix:lines-fix-handling-of-bare-cr, r=joshtriplett
Fix handling of trailing bare CR in str::lines Continuing from rust-lang#91191. Fixes rust-lang#94435.
2 parents e48d983 + e537777 commit acde5df

File tree

4 files changed

+27
-14
lines changed

4 files changed

+27
-14
lines changed

library/alloc/tests/str.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -1499,13 +1499,25 @@ fn test_split_whitespace() {
14991499

15001500
#[test]
15011501
fn test_lines() {
1502-
let data = "\nMäry häd ä little lämb\n\r\nLittle lämb\n";
1503-
let lines: Vec<&str> = data.lines().collect();
1504-
assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
1505-
1506-
let data = "\r\nMäry häd ä little lämb\n\nLittle lämb"; // no trailing \n
1507-
let lines: Vec<&str> = data.lines().collect();
1508-
assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
1502+
fn t(data: &str, expected: &[&str]) {
1503+
let lines: Vec<&str> = data.lines().collect();
1504+
assert_eq!(lines, expected);
1505+
}
1506+
t("", &[]);
1507+
t("\n", &[""]);
1508+
t("\n2nd", &["", "2nd"]);
1509+
t("\r\n", &[""]);
1510+
t("bare\r", &["bare\r"]);
1511+
t("bare\rcr", &["bare\rcr"]);
1512+
t("Text\n\r", &["Text", "\r"]);
1513+
t(
1514+
"\nMäry häd ä little lämb\n\r\nLittle lämb\n",
1515+
&["", "Märy häd ä little lämb", "", "Little lämb"],
1516+
);
1517+
t(
1518+
"\r\nMäry häd ä little lämb\n\nLittle lämb",
1519+
&["", "Märy häd ä little lämb", "", "Little lämb"],
1520+
);
15091521
}
15101522

15111523
#[test]

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@
192192
#![feature(intra_doc_pointers)]
193193
#![feature(intrinsics)]
194194
#![feature(lang_items)]
195+
#![feature(let_else)]
195196
#![feature(link_llvm_intrinsics)]
196197
#![feature(macro_metavar_expr)]
197198
#![feature(min_specialization)]

library/core/src/str/iter.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use super::from_utf8_unchecked;
1313
use super::pattern::Pattern;
1414
use super::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
1515
use super::validations::{next_code_point, next_code_point_reverse};
16-
use super::LinesAnyMap;
16+
use super::LinesMap;
1717
use super::{BytesIsNotEmpty, UnsafeBytesToStr};
1818
use super::{CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode};
1919
use super::{IsAsciiWhitespace, IsNotEmpty, IsWhitespace};
@@ -1091,7 +1091,7 @@ generate_pattern_iterators! {
10911091
#[stable(feature = "rust1", since = "1.0.0")]
10921092
#[must_use = "iterators are lazy and do nothing unless consumed"]
10931093
#[derive(Clone, Debug)]
1094-
pub struct Lines<'a>(pub(super) Map<SplitTerminator<'a, char>, LinesAnyMap>);
1094+
pub struct Lines<'a>(pub(super) Map<SplitInclusive<'a, char>, LinesMap>);
10951095

10961096
#[stable(feature = "rust1", since = "1.0.0")]
10971097
impl<'a> Iterator for Lines<'a> {

library/core/src/str/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ impl str {
997997
#[stable(feature = "rust1", since = "1.0.0")]
998998
#[inline]
999999
pub fn lines(&self) -> Lines<'_> {
1000-
Lines(self.split_terminator('\n').map(LinesAnyMap))
1000+
Lines(self.split_inclusive('\n').map(LinesMap))
10011001
}
10021002

10031003
/// An iterator over the lines of a string.
@@ -2590,10 +2590,10 @@ impl Default for &mut str {
25902590
impl_fn_for_zst! {
25912591
/// A nameable, cloneable fn type
25922592
#[derive(Clone)]
2593-
struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str {
2594-
let l = line.len();
2595-
if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] }
2596-
else { line }
2593+
struct LinesMap impl<'a> Fn = |line: &'a str| -> &'a str {
2594+
let Some(line) = line.strip_suffix('\n') else { return line };
2595+
let Some(line) = line.strip_suffix('\r') else { return line };
2596+
line
25972597
};
25982598

25992599
#[derive(Clone)]

0 commit comments

Comments
 (0)