-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove some useless BufReader wrappers around stdin #1307
Conversation
stdin() is already buffered. stdin().read_line() calls stdin().lock() behind the hood (see https://doc.rust-lang.org/src/std/io/stdio.rs.html#274) Here we are reading user input, prompting them to confirm their action: it seems useless to handle mutex locking/unlocking explicitely and beforehand to avoid its overhead. This commit is related to issue #1103.
stdin() is already buffered. Locking upfront explicitely avoid the overhead of mutex locking/unlocking everytime a new line is read. See https://stackoverflow.com/a/17546731 and https://www.reddit.com/r/rust/comments/3rj54u/how_can_i_read_char_by_char_from_stdin/cwpojn1/ The code cannot be simplified to “for line in stdin().lock().lines()” until non-lexical lifetimes are implemented. The compiler complains at the moment about a temporary value not living long enough/being dropped while still borrowed. See rust-lang/rust#33520 This commit is related to issue #1103.
One way to fix the fn uumain(/* args */) -> /* return */ {
// ... snip ...
if matches.free.is_empty() || &matches.free[0][..] == "-" {
let stdin_raw = stdin();
do_stuff(stdin_raw.lock());
} else {
let path = Path::new(matches.free[0].as_str());
let file_buf = safe_unwrap!(File::open(&path));
do_stuff(BufReader::new(file_buf));
}
0
}
fn do_stuff<R: Read>(input: R) {
// blah
} Another way is what you suggested, which is also fine but requires allocation (the current code does too). IIRC the problem with By the way, the issue you referenced will get closed if I merged this as-is, because you wrote "fixes" right next to the issue number, so it'd probably be better if you change the wording. |
I have edited the original PR message so that you can merge it as-is, without closing #1103. You are right, in let is_decode = matches.opt_present("decode");
let ignore_garbage = matches.opt_present("ignore-garbage");
[…]
if matches.free.is_empty() || &matches.free[0][..] == "-" {
let stdin = stdin();
do_it(stdin.lock(), is_decode, ignore_garbage, line_wrap);
} else {
let path = Path::new(matches.free[0].as_str());
let file_buf = safe_unwrap!(File::open(&path));
do_it(BufReader::new(file_buf), is_decode, ignore_garbage, line_wrap);
};
[…]
fn do_it<R: Read>(input: R, is_decode: bool, ignore_garbage: bool, line_wrap: usize) {
let mut data = Data::new(input, Format::Base32);
if is_decode {
match data.ignore_garbage(ignore_garbage).decode() {
Ok(s) => print!("{}", String::from_utf8(s).unwrap()),
Err(_) => crash!(1, "invalid input"),
}
} else {
wrap_print(line_wrap, data.encode());
}
} But then the same thing would have to be repeated in The code of
|
I've combined the |
Oh, great! Thank you from all programmers that will have to touch this code in the future 😃 The main point was that the code was hard to follow. Performance was a minor concern, more like a side-effect (“the key to performance is elegance”). Though if
A quick look at the disassembly ( But assuming that, in general, the compiler is sufficiently smart is hazardous. See e.g. http://proebsting.cs.arizona.edu/law.html https://cr.yp.to/talks/2015.04.16/slides-djb-20150416-a4.pdf |
This fixes, in part only, #1103.
I’m willing to remove the other useless
BufReader
wrappers, but I am too much of a Rust newbie to know how to do that properly. I need some help.In, for instance,
base32.rs
, it’d be easy to do:This compiles. But then some repetitive hence excessive mutex locking/unlocking is going to take place.
base32.rs
delegates todecode()/encode()
inencoding.rs
. There,read_to_end()
is called.If I understand https://doc.rust-lang.org/src/std/io/mod.rs.html#365-394 correctly,
read_to_end()
calls
read()
, potentially several times. And each time, the mutex has to be taken then released.See https://www.reddit.com/r/rust/comments/3rj54u/how_can_i_read_char_by_char_from_stdin/cwpojn1/
So it’d be better to acquire the mutex lock explicitely beforehand, doing something like:
This compiles, but this is ugly (the stupid
std_input
upfront declaration).Ugly is one thing, losing the fight with the borrow checker is another.
Take
cat.rs
. It does not explicitely lock either (but it should). But then if you do:The compiler is not happy, and I don’t know to please it.
Maybe it’d be better just to wait for non-lexical lifetimes to be implemented?
See rust-lang/rust#33520 rust-lang/rfcs#811 rust-lang/rust#43234
Please let me know what you think.