Как мне прочитать выходные данные дочернего процесса без блокировки в Rust?

Я делаю небольшое приложение ncurses в Rust, которое должно взаимодействовать с дочерним процессом. У меня уже есть прототип, написанный на Common Lisp; подарокВот надеюсь, покажет, что я хочу сделать. Я пытаюсь переписать его, потому что CL использует огромное количество памяти для такого маленького инструмента.

Я раньше не использовал Rust (или другие языки низкого уровня), и у меня возникли проблемы с выяснением того, как взаимодействовать с подпроцессом.

То, что я сейчас делаю, примерно так:

Создайте процесс:

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;
        },
    };

Передайте его в бесконечный (до тех пор, пока пользователь не выйдет) цикл, который читает и обрабатывает ввод и прослушивает вывод, как это (и записывает его на экран):

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,
    };
}

Призыв кread_to_string однако блокирует программу до завершения процесса. Из того, что я вижуread_to_end а такжеread также, кажется, заблокировать. Если я попробую запустить что-то вродеls который выходит сразу, это работает, но с чем-то, что не выходит, какpython или жеsbcl это продолжается только после того, как я вручную уничтожаю подпроцесс.

Редактировать:

На основеэтот ответЯ изменил код для использованияBufReader:

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,
    }
}

Однако проблема остается той же. Он будет читать все доступные строки, а затем блокировать. Поскольку инструмент должен работать с любой программой, нет способа угадать, когда закончится вывод, прежде чем пытаться читать. Кажется, не существует способа установить тайм-аут дляBufReader или.

Ответы на вопрос(1)

Ваш ответ на вопрос