in rust-csv/csv-core/src/reader.rs [626:703]
fn read_record_dfa(
&mut self,
input: &[u8],
output: &mut [u8],
ends: &mut [usize],
) -> (ReadRecordResult, usize, usize, usize) {
if input.is_empty() {
let s = self.transition_final_dfa(self.dfa_state);
let res =
self.dfa.new_read_record_result(s, true, false, false, false);
// This part is a little tricky. When reading the final record,
// the last result the caller will get is an InputEmpty, and while
// they'll have everything they need in `output`, they'll be
// missing the final end position of the final field in `ends`.
// We insert that here, but we must take care to handle the case
// where `ends` doesn't have enough space. If it doesn't have
// enough space, then we also can't transition to the next state.
return match res {
ReadRecordResult::Record => {
if ends.is_empty() {
return (ReadRecordResult::OutputEndsFull, 0, 0, 0);
}
self.dfa_state = s;
ends[0] = self.output_pos;
self.output_pos = 0;
(res, 0, 0, 1)
}
_ => {
self.dfa_state = s;
(res, 0, 0, 0)
}
};
}
if output.is_empty() {
return (ReadRecordResult::OutputFull, 0, 0, 0);
}
if ends.is_empty() {
return (ReadRecordResult::OutputEndsFull, 0, 0, 0);
}
let (mut nin, mut nout, mut nend) = (0, 0, 0);
let mut state = self.dfa_state;
while nin < input.len() && nout < output.len() && nend < ends.len() {
let (s, has_out) = self.dfa.get_output(state, input[nin]);
self.line += (input[nin] == b'\n') as u64;
state = s;
if has_out {
output[nout] = input[nin];
nout += 1;
}
nin += 1;
if state >= self.dfa.final_field {
ends[nend] = self.output_pos + nout;
nend += 1;
if state > self.dfa.final_field {
break;
}
}
if state == self.dfa.in_field || state == self.dfa.in_quoted {
self.dfa
.classes
.scan_and_copy(input, &mut nin, output, &mut nout);
}
}
let res = self.dfa.new_read_record_result(
state,
false,
nin >= input.len(),
nout >= output.len(),
nend >= ends.len(),
);
self.dfa_state = state;
if res.is_record() {
self.output_pos = 0;
} else {
self.output_pos += nout;
}
(res, nin, nout, nend)
}