Search code examples
ioruststdin

Is there a standard way of discarding input in Rust?


Reading input from stdin in Rust is pretty straightforward:

use std::io;

let mut some_string = String::new();
let _ = io::stdin().read_line(&mut some_string);

but sometimes you might want to just discard it without acknowledging it anywhere or procuring a buffer, like:

println!("Press Enter to close");
io::stdin().discard_input(); // discard_input() doesn't exist

It could read any number of characters until encountering \n, ignore it all and return nothing or io::Result. Is there a standard way of doing it or do I have to implement it myself? I traced the implementation of read_line to read_until implemented by BufRead, but I'm not sure if it's a good idea to start from there.


Solution

  • You can implement .discard_until_newline() on stdin for example like this:

    This should be a correct and efficient implementation (using a buffer to read, but not copying the read parts anywhere). It could be much simpler if you don't anticipate any long lines and just read a byte at a time, of course.

    use std::io::Stdin;
    use std::io;
    use std::io::prelude::*;
    
    pub trait DiscardUntil {
        fn discard_until_newline(&mut self) -> Result<(), io::Error>;
    }
    
    impl DiscardUntil for Stdin {
        fn discard_until_newline(&mut self) -> Result<(), io::Error> {
            let mut buffered = self.lock();
            loop {
                let (consume, done) = {
                    let data = try!(buffered.fill_buf());
                    if data.is_empty() {
                        (0, true)
                    } else if let Some(newline_pos) = data.iter().position(|b| *b == b'\n') {
                        (newline_pos + 1, true)
                    } else {
                        (data.len(), false)
                    }
                };
                buffered.consume(consume);
                if done {
                    break;
                }
            }
            Ok(())
        }
    }
    
    fn main() {
        println!("hi");
        io::stdin().discard_until_newline().unwrap();
        println!("again");
        io::stdin().discard_until_newline().unwrap();
        println!("goodbye");
    }