Skip to content

Commit 5917ef6

Browse files
committed
lazycsv: Handle trailing empty cell gracefully
1 parent 313abc3 commit 5917ef6

File tree

2 files changed

+53
-21
lines changed

2 files changed

+53
-21
lines changed

crates/lazycsv/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,15 @@ impl<'a> Iterator for Csv<'a> {
328328
else {
329329
self.state = IterState::Done;
330330
return if start < self.buf.len() {
331+
// Return the last cell if there's remaining data.
331332
Some(CsvIterItem::Cell(Cell {
332333
buf: &self.buf[start..],
333334
}))
335+
} else if !self.buf.is_empty() && self.buf.ends_with(&[self.separator]) {
336+
// Handle trailing empty cell when no trailing newline is present.
337+
Some(CsvIterItem::Cell(Cell { buf: &[] }))
334338
} else {
339+
// Gracefully reached EOF with no more data
335340
None
336341
};
337342
};

crates/lazycsv/tests/main.rs

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,51 +59,78 @@ fn basic() {
5959
assert_csv!(csv, EOF);
6060
}
6161

62+
#[cfg(feature = "alloc")]
6263
#[test]
63-
fn no_trailing_newline() {
64-
let mut csv = Csv::new(b"a,b,c\n1,2,3\n4,5,6");
64+
fn dequote() {
65+
let cell = Cell {
66+
buf: br#""Hi ""Quote"" yo""#,
67+
};
68+
assert_eq!(cell.try_as_str().unwrap(), r#"Hi "Quote" yo"#);
69+
}
6570

71+
#[test]
72+
fn check_corner_cases() {
73+
// No trailing newline
74+
let mut csv = Csv::new(b"a,b,c\n1,2,3\n4,5,6");
75+
assert_csv!(csv, position == 0);
6676
assert_csv!(csv, Cell(b"a"));
77+
assert_csv!(csv, position == 2);
6778
assert_csv!(csv, Cell(b"b"));
79+
assert_csv!(csv, position == 4);
6880
assert_csv!(csv, Cell(b"c"));
81+
assert_csv!(csv, position == 5);
6982
assert_csv!(csv, LineEnd);
83+
assert_csv!(csv, position == 6);
7084
assert_csv!(csv, Cell(b"1"));
85+
assert_csv!(csv, position == 8);
7186
assert_csv!(csv, Cell(b"2"));
87+
assert_csv!(csv, position == 10);
7288
assert_csv!(csv, Cell(b"3"));
89+
assert_csv!(csv, position == 11);
7390
assert_csv!(csv, LineEnd);
91+
assert_csv!(csv, position == 12);
7492
assert_csv!(csv, Cell(b"4"));
93+
assert_csv!(csv, position == 14);
7594
assert_csv!(csv, Cell(b"5"));
95+
assert_csv!(csv, position == 16);
7696
assert_csv!(csv, Cell(b"6"));
97+
assert_csv!(csv, position == 17);
7798
assert_csv!(csv, EOF);
78-
}
79-
80-
#[cfg(feature = "alloc")]
81-
#[test]
82-
fn dequote() {
83-
let cell = Cell {
84-
buf: br#""Hi ""Quote"" yo""#,
85-
};
86-
assert_eq!(cell.try_as_str().unwrap(), r#"Hi "Quote" yo"#);
87-
}
88-
89-
#[test]
90-
fn position() {
91-
let data = b"aaa,bbb\n100,200";
92-
let mut csv = Csv::new(data);
99+
assert_csv!(csv, position == 17);
93100

101+
// CRLF line endings
102+
let mut csv = Csv::new(b"aaa,bbb\r\n100,200\r\n");
94103
assert_csv!(csv, position == 0); // Start position
95104
assert_csv!(csv, Cell(b"aaa")); // Yields Cell('aaa')
96105
assert_csv!(csv, position == 4); // Position after 'aaa,' (start of 'b')
97106
assert_csv!(csv, Cell(b"bbb")); // Yields Cell('bbb')
98107
assert_csv!(csv, position == 7); // Position after 'bbb' (start of '\r')
99108
assert_csv!(csv, LineEnd); // Yields LineEnd
100-
assert_csv!(csv, position == 8); // Position after '\n' (start of '1')
109+
assert_csv!(csv, position == 9); // Position after '\n' (start of '1')
101110
assert_csv!(csv, Cell(b"100")); // Yields Cell('100')
102-
assert_csv!(csv, position == 12); // Position after '100,' (start of '2')
111+
assert_csv!(csv, position == 13); // Position after '100,' (start of '2')
103112
assert_csv!(csv, Cell(b"200")); // Yields Cell('200')
104-
assert_csv!(csv, position == 15); // Position after '200' (end of buffer)
113+
assert_csv!(csv, position == 16); // Position after '200' (end of buffer)
114+
assert_csv!(csv, LineEnd); // Yields LineEnd
115+
assert_csv!(csv, position == 18); // Position after '\n' (end of buffer)
105116
assert_csv!(csv, EOF); // End of iteration
106-
assert_csv!(csv, position == data.len()); // Position at the end
117+
assert_csv!(csv, position == 18); // Position at the end
118+
119+
// empty cells at line end without trailing newline
120+
let mut csv = Csv::new(b"aaa,\n100,");
121+
assert_csv!(csv, position == 0);
122+
assert_csv!(csv, Cell(b"aaa"));
123+
assert_csv!(csv, position == 4);
124+
assert_csv!(csv, Cell(b""));
125+
assert_csv!(csv, position == 4);
126+
assert_csv!(csv, LineEnd);
127+
assert_csv!(csv, position == 5);
128+
assert_csv!(csv, Cell(b"100"));
129+
assert_csv!(csv, position == 9);
130+
assert_csv!(csv, Cell(b""));
131+
assert_csv!(csv, position == 9);
132+
assert_csv!(csv, EOF);
133+
assert_csv!(csv, position == 9);
107134
}
108135

109136
#[test]

0 commit comments

Comments
 (0)