title: How do I read the output of a child process without blocking in Rust?
body: <p>I'm making a small ncurses application in Rust that needs to communicate with a child process. I already have a prototype written in Common Lisp. I'm trying to rewrite it because CL uses a huge amount of memory for such a small tool.</p>
  
  <p>I'm having some trouble figuring out how to interact with the sub-process. </p>
  
  <p>What I'm currently doing is roughly this:</p>
  
  <ol>
  <li><p>Create the process:</p>
  
  <pre><code>let mut program = match Command::new(command)
      .args(arguments)
      .stdin(Stdio::piped())
      .stdout(Stdio::piped())
      .stderr(Stdio::piped())
      .spawn()
  {
      Ok(child) =&gt; child,
      Err(_) =&gt; {
          println!("Cannot run program '{}'.", command);
          return;
      }
  };
  </code></pre></li>
  <li><p>Pass it to an infinite (until user exits) loop, which reads and handles input and listens for output like this (and writes it to the screen):</p>
  
  <pre><code>fn listen_for_output(program: &amp;mut Child, output_viewer: &amp;TextViewer) {
      match program.stdout {
          Some(ref mut out) =&gt; {
              let mut buf_string = String::new();
              match out.read_to_string(&amp;mut buf_string) {
                  Ok(_) =&gt; output_viewer.append_string(buf_string),
                  Err(_) =&gt; return,
              };
          }
          None =&gt; return,
      };
  }
  </code></pre></li>
  </ol>
  
  <p>The call to <code>read_to_string</code> however blocks the program until the process exits. From what I can see <code>read_to_end</code> and <code>read</code> also seem to block. If I try running something like <code>ls</code> which exits right away, it works, but with something that doesn't exit like <code>python</code> or <code>sbcl</code> it only continues once I kill the subprocess manually.</p>
  
  <p>Based on <a href="https://stackoverflow.com/a/31577297/155423">this answer</a>, I changed the code to use <code>BufReader</code>:</p>
  
  <pre><code>    fn listen_for_output(program: &amp;mut Child, output_viewer: &amp;TextViewer) {
          match program.stdout.as_mut() {
              Some(out) =&gt; {
                  let buf_reader = BufReader::new(out);
                  for line in buf_reader.lines() {
                      match line {
                          Ok(l) =&gt; {
                              output_viewer.append_string(l);
                          }
                          Err(_) =&gt; return,
                      };
                  }
              }
              None =&gt; return,
          }
      }
  </code></pre>
  
  <p>However, the problem still remains the same. It will read all lines that are available, and then block. Since the tool is supposed to work with any program, there is no way to guess out when the output will end, before trying to read. There doesn't appear to be a way to set a timeout for <code>BufReader</code> either.</p>