Wie kann ich die Ausgabe eines untergeordneten Prozesses lesen, ohne Rust zu blockieren?

Ich mache eine kleine Ncurses-Anwendung in Rust, die mit einem untergeordneten Prozess kommunizieren muss. Ich habe bereits einen Prototyp in Common Lisp geschrieben. das gifHie wird hoffentlich zeigen, was ich tun möchte. Ich versuche, es umzuschreiben, weil CL für ein so kleines Tool sehr viel Speicher benötigt.

Ich habe noch nie Rust (oder andere niedrigstufige Sprachen) verwendet, und ich habe einige Probleme, herauszufinden, wie ich mit dem Unterprozess umgehen soll.

Was ich gerade mache, ist ungefähr so:

Erstelle den Prozess:

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

Übergeben Sie es an eine Endlosschleife (bis der Benutzer das Programm beendet), die Eingaben liest und verarbeitet und auf diese Weise auf Ausgaben wartet (und sie auf den Bildschirm schreibt):

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

Der Anruf anread_to_string blockiert jedoch das Programm, bis der Prozess beendet wird. Von dem, was ich sehen kannread_to_end undread scheint auch zu blockieren. Wenn ich versuche, so etwas wiels, das sofort beendet wird, funktioniert, aber mit etwas, das nicht beendet wird, wiepython odersbcl es wird erst fortgesetzt, wenn ich den Unterprozess manuell beendet habe.

Bearbeiten

Beyogen aufdiese Antwort, Ich habe den Code geändert, um @ zu verwendBufReader:

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

Aber das Problem bleibt immer noch das gleiche. Es werden alle verfügbaren Zeilen gelesen und dann blockiert. Da das Tool mit jedem Programm arbeiten soll, ist es nicht möglich zu erraten, wann die Ausgabe enden wird, bevor versucht wird, sie zu lesen. Es scheint keine Möglichkeit zu geben, eine Zeitüberschreitung für @ festzulegeBufReader entweder

Antworten auf die Frage(2)

Ihre Antwort auf die Frage