Auto merge of #9586 - tmiasko:lines, r=alexcrichton

Avoid quadratic complexity when splitting output into lines

When searching for newlines in a process output keep track which part of
buffer was already examined to avoid processing the same data again and
again.
This commit is contained in:
bors 2021-06-18 20:01:46 +00:00
commit 9a3c162dc3

View file

@ -243,47 +243,54 @@ impl ProcessBuilder {
.stdin(Stdio::null()); .stdin(Stdio::null());
let mut callback_error = None; let mut callback_error = None;
let mut stdout_pos = 0;
let mut stderr_pos = 0;
let status = (|| { let status = (|| {
let mut child = cmd.spawn()?; let mut child = cmd.spawn()?;
let out = child.stdout.take().unwrap(); let out = child.stdout.take().unwrap();
let err = child.stderr.take().unwrap(); let err = child.stderr.take().unwrap();
read2(out, err, &mut |is_out, data, eof| { read2(out, err, &mut |is_out, data, eof| {
let pos = if is_out {
&mut stdout_pos
} else {
&mut stderr_pos
};
let idx = if eof { let idx = if eof {
data.len() data.len()
} else { } else {
match data.iter().rposition(|b| *b == b'\n') { match data[*pos..].iter().rposition(|b| *b == b'\n') {
Some(i) => i + 1, Some(i) => *pos + i + 1,
None => return, None => {
*pos = data.len();
return;
}
} }
}; };
{
// scope for new_lines let new_lines = &data[..idx];
let new_lines = if capture_output {
let dst = if is_out { &mut stdout } else { &mut stderr }; for line in String::from_utf8_lossy(new_lines).lines() {
let start = dst.len(); if callback_error.is_some() {
let data = data.drain(..idx); break;
dst.extend(data); }
&dst[start..] let callback_result = if is_out {
on_stdout_line(line)
} else { } else {
&data[..idx] on_stderr_line(line)
}; };
for line in String::from_utf8_lossy(new_lines).lines() { if let Err(e) = callback_result {
if callback_error.is_some() { callback_error = Some(e);
break; break;
}
let callback_result = if is_out {
on_stdout_line(line)
} else {
on_stderr_line(line)
};
if let Err(e) = callback_result {
callback_error = Some(e);
}
} }
} }
if !capture_output {
data.drain(..idx); if capture_output {
let dst = if is_out { &mut stdout } else { &mut stderr };
dst.extend(new_lines);
} }
data.drain(..idx);
*pos = 0;
})?; })?;
child.wait() child.wait()
})() })()