use std::io::{Read, Write};
use std::process::{Child, ChildStdin, ExitStatus};
use crate::BUFSIZ;
pub fn run<R: Read>(mut reader: R, mut children: Vec<Child>) -> std::io::Result<Vec<ExitStatus>> {
let mut stdins: Vec<Option<ChildStdin>> = children.iter_mut().map(|c| c.stdin.take()).collect();
let mut live: Vec<usize> = (0..stdins.len()).collect();
if !stdins.is_empty() {
let mut buf = vec![0u8; BUFSIZ];
'outer: loop {
let n = reader.read(&mut buf)?;
if n == 0 {
break 'outer;
}
let chunk = &buf[..n];
let mut to_drop: Vec<usize> = Vec::new();
for &idx in &live {
if let Some(handle) = stdins[idx].as_mut() {
match handle.write_all(chunk) {
Ok(()) => {}
Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => {
to_drop.push(idx);
}
Err(_) => {
to_drop.push(idx);
}
}
}
}
for idx in to_drop {
stdins[idx] = None;
live.retain(|&i| i != idx);
}
if live.is_empty() {
loop {
let m = reader.read(&mut buf)?;
if m == 0 {
break;
}
}
break 'outer;
}
}
} else {
let mut buf = vec![0u8; BUFSIZ];
loop {
let n = reader.read(&mut buf)?;
if n == 0 {
break;
}
}
}
drop(stdins);
let mut statuses: Vec<ExitStatus> = Vec::with_capacity(children.len());
for mut c in children.into_iter() {
let status = c.wait()?;
statuses.push(status);
}
Ok(statuses)
}