Multiple mutable references for StdinLock

I am trying to build a function which takes standard input the same way C++'s std::cin >> does, keeping the code as simple as possible.

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 available = guard.fill_buf().unwrap();
        match available.iter().position(|&b| !(b as char).is_whitespace()) {
            Some(i) => {
                available = &available[i..];
				guard.consume(i);
            }
            None => {
                guard.consume(available.len());
                continue;
            }
        }
        match available.iter().position(|&b| (b as char).is_whitespace()) {
            Some(i) => unsafe {
				available = &available[..i];
				guard.consume(i);
				x.as_mut_vec().extend_from_slice(available);
				break;
            }
            None => {
				guard.consume(available.len());
				continue;
            }
        }
    }
    T::from_str(&x)
}

The lint tells me that the StdinLock has multiple mutable references, whereas I see only one, that is guard. What am I missing?

Since available is a reference into guard, it will immutably borrow guard until its last use. The reason for this is that consume might turn your available pointer into a dangling reference. Instead of modifying available to be a sub-slice, you should call fill_buf again after calling consume. If you wish to use sub-slicing, you must postpone the call to consume.

Additionally you must extract the length in a separate variable before calling consume(available.len()). This is due to how function calls are desugared.

Additionally your unsafe block will cause undefined behavior if available contains invalid utf-8. You should do this instead:

x.push_str(std::str::from_utf8(available).unwrap());

A version that compiles can be found here.

Thanks, @alice.

It looks like you mistook &available[..i] for &available[i..] in the second match block and I have a few things myself which could do with some improvement. So I have edited your answer a bit.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.