Como leio a saída de um processo filho sem bloquear no Rust?
Estou fazendo um pequeno aplicativo ncurses no Rust que precisa se comunicar com um processo filho. Eu já tenho um protótipo escrito em Common Lisp; o gifaqui espero mostrar o que eu quero fazer. Estou tentando reescrevê-lo porque o CL usa uma quantidade enorme de memória para uma ferramenta tão pequena.
Eu não usei o Rust antes (ou outras linguagens de baixo nível) e estou tendo alguns problemas para descobrir como interagir com o subprocesso.
O que estou fazendo atualmente é aproximadamente isso:
Crie o processo:
let mut program = match Command::new(command)
.args(arguments)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn() {
Ok(child) => child,
Err(_) => {
println!("Cannot run program '{}'.", command);
return;
},
};
Passe-o para um loop infinito (até o usuário sair), que lê e manipula a entrada e escuta a saída como esta (e a grava na tela):
fn listen_for_output(program: &mut Child,
output_viewer: &TextViewer) {
match program.stdout {
Some(ref mut out) => {
let mut buf_string = String::new();
match out.read_to_string(&mut buf_string) {
Ok(_) => output_viewer.append_string(buf_string),
Err(_) => return,
};
},
None => return,
};
}
A chamada pararead_to_string
no entanto, bloqueia o programa até o processo terminar. Pelo que eu posso verread_to_end
eread
também parecem bloquear. Se eu tentar executar algo comols
que sai imediatamente, funciona, mas com algo que não sai comopython
ousbcl
ele só continua depois que eu mato o subprocesso manualmente.
Editar:
Baseado emesta resposta, Mudei o código para usarBufReader
:
fn listen_for_output(program: &mut Child,
output_viewer: &TextViewer) {
match program.stdout.as_mut() {
Some(out) => {
let buf_reader = BufReader::new(out);
for line in buf_reader.lines() {
match line {
Ok(l) => {
output_viewer.append_string(l);
},
Err(_) => return,
};
}
},
None => return,
}
}
No entanto, o problema ainda permanece o mesmo. Ele lerá todas as linhas disponíveis e depois bloqueará. Como a ferramenta deve funcionar com qualquer programa, não há como adivinhar quando a saída terminará antes de tentar ler. Não parece haver uma maneira de definir um tempo limite paraBufReader
ou.