Reading stdout of another process

Hello,
I'm trying to read stdout of another process, which is writing to stdout every second. I'd like to read each line and print it out modified on the stdout of my main process.
I used std::process:Command to do so. The rust code is this one :

use std::{error::Error, io::{BufRead, ErrorKind}, process::{Command, Stdio}};
use std::io::BufReader;

fn output() -> Result<(), Box<dyn Error>> {
    let stdout = Command::new("./test")
        .stdout(Stdio::piped())
        .spawn()?
        .stdout
        .ok_or_else(|| std::io::Error::new(ErrorKind::Other, "Could not capture standard output."))?;

    let reader = BufReader::new(stdout);
    
    reader
        .lines()
        .filter_map(|line| line.ok())
        .for_each(|line| println!("hello {}", line));

     Ok(())
}

fn main() {
    output().unwrap();
    println!("Hello, world!");
}

And the test application it runs is written in c. It looks like this :

#include <stdio.h>
#include <unistd.h>

int main(int argc, char**argv)
{
    for (int i = 0; i < 10; i++) {
        fprintf(stdout, "World! %d\n", i);
        usleep(1000000);
    }
    return 0;
}

If I run the rust code like this, I got all the output after 10seconds, as a block. it doesn't print line by line. Whereas if I add fflush(stdout) in the C code, I print line by line.

My guess is that the BufReader is filled when the application exits instead of being filled when a 0xA is received as mentioned in the documentation : BufRead in std::io - Rust

I wonder if there is a way to get the line by line behavior with my Rust code.

Thanks,
Nicolas

Has nothing to do with rust, the same thing happens when you run ./test | cat. Linux's buffer of 64k bytes probably plays a role here.

C is using one of those FILE * types, right? At least with glibc that switches between line buffering and block buffering depending on whether it's wrapping a tty or something else.

Since the processes are connected with a pipe it's probably using block buffering.

Since the buffering happens on the C side there is nothing that rust can do about it. You can either flush manually as you already did or change the buffer settings of stdout with setvbuf.

There are some process-level and LD_PRELOAD-level workarounds on Unixes at least; see for example the suggestions in these external threads.

Thanks for all your explanations and suggestions. Indeed I got the problem when i run ./test | cat
I tried faketty and running faketty ./test | cat is diplaying line by line.
I'll take look into running the test app trough faketty_lib
Thanks again !