The plan is to write a simple method which does exactly what std::cin >>
from the C++ standard library does. Here is what was come up with.
use std::io::BufRead;
pub fn input<T: std::str::FromStr>(handle: &std::io::Stdin) -> Result<T, T::Err> {
let mut x = String::new();
let mut guard = handle.lock();
loop {
let mut trimmed = false;
let available = guard.fill_buf().unwrap();
let l = match available.iter().position(|&b| !(b as char).is_whitespace()) {
Some(i) => {
trimmed = true;
i
}
None => available.len()
};
guard.consume(l);
if trimmed {
break;
}
}
let available = guard.fill_buf().unwrap();
let l = match available.iter().position(|&b| (b as char).is_whitespace()) {
Some(i) => i,
None => available.len()
};
x.push_str(std::str::from_utf8(&available[..l]).unwrap());
guard.consume(l);
T::from_str(&x)
}
Let me help you understand. The loop
block is meant to trim away all the whitespaces before valid input begins. The match
block outside loop is where the length of the valid input (that is, before trailing whitespaces begin or EOF
is reached) is calculated.
Here is an example using the above method.
let handle = std::io::stdin();
let x: i32 = input(&handle).unwrap();
println!("x: {}", x);
let y: String = input(&handle).unwrap();
println!("y: {}", y);
When I tried a few simple tests, the method works as intended. However, when I use this in online programming judges like the one in codeforces, sometimes I get a complaint telling that the program stays idle or that the wrong input has been taken, among other issues, which leads to suspecting that I missed a corner case or something like that. This usually happens when the input is a few hundreds of lines long.
Okay, I am asking here hoping one of you knows of an input which is going to break the method, or even better, one of you points a correction. Help me?
Edit:
Replacing the loop containing fill_buf() + consume()
with something like a single read_to_string()
or a loop containing read_line()
seems to solve the issue, but I am not certain why.