How can I test stdin and stdout? - testing

I'd like to write a prompt function that sends a passed-in string to stdout and then returns the string that it reads from stdin. How could I test it?
Here is an example of the function:
fn prompt(question: String) -> String {
let mut stdin = BufferedReader::new(stdin());
print!("{}", question);
match stdin.read_line() {
Ok(line) => line,
Err(e) => panic!(e),
}
}
And here is my testing attempt
#[test]
fn try_to_test_stdout() {
let writer: Vec<u8> = vec![];
set_stdout(Box::new(writer));
print!("testing");
// `writer` is now gone, can't check to see if "testing" was sent
}

Use dependency injection. Coupling it with generics and monomorphism, you don't lose any performance:
use std::io::{self, BufRead, Write};
fn prompt<R, W>(mut reader: R, mut writer: W, question: &str) -> String
where
R: BufRead,
W: Write,
{
write!(&mut writer, "{}", question).expect("Unable to write");
let mut s = String::new();
reader.read_line(&mut s).expect("Unable to read");
s
}
#[test]
fn test_with_in_memory() {
let input = b"I'm George";
let mut output = Vec::new();
let answer = prompt(&input[..], &mut output, "Who goes there?");
let output = String::from_utf8(output).expect("Not UTF-8");
assert_eq!("Who goes there?", output);
assert_eq!("I'm George", answer);
}
fn main() {
let stdio = io::stdin();
let input = stdio.lock();
let output = io::stdout();
let answer = prompt(input, output, "Who goes there?");
println!("was: {}", answer);
}
In many cases, you'd want to actually propagate the error back up to the caller instead of using expect, as IO is a very common place for failures to occur.
This can be extended beyond functions into methods:
use std::io::{self, BufRead, Write};
struct Quizzer<R, W> {
reader: R,
writer: W,
}
impl<R, W> Quizzer<R, W>
where
R: BufRead,
W: Write,
{
fn prompt(&mut self, question: &str) -> String {
write!(&mut self.writer, "{}", question).expect("Unable to write");
let mut s = String::new();
self.reader.read_line(&mut s).expect("Unable to read");
s
}
}
#[test]
fn test_with_in_memory() {
let input = b"I'm George";
let mut output = Vec::new();
let answer = {
let mut quizzer = Quizzer {
reader: &input[..],
writer: &mut output,
};
quizzer.prompt("Who goes there?")
};
let output = String::from_utf8(output).expect("Not UTF-8");
assert_eq!("Who goes there?", output);
assert_eq!("I'm George", answer);
}
fn main() {
let stdio = io::stdin();
let input = stdio.lock();
let output = io::stdout();
let mut quizzer = Quizzer {
reader: input,
writer: output,
};
let answer = quizzer.prompt("Who goes there?");
println!("was: {}", answer);
}

Related

Modified Rust Book Guessing Game Query

I modified the code from the Rust Book's Guessing Game Tutorial to make it a little shorter; for a slide. Alas, I've introduced a bug, and it no longer executes correctly: the first input works as expected, but subsequent entries now yield no feedback.
What is the best way to guard against this situation?
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
let mut guess = String::new();
loop {
io::stdin().read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
read_line will append the line to buffer, so your guess will accumulate all the inputs include newline characters! Moving let mut guess = String::new(); inside the loop solves the problem:
fn main() {
...
loop {
let mut guess = String::new();
...
}
}

Trying to iterate through a mesh structure results in "borrowed value does not live long enough"

I am trying to create a data structure that can store monitor location data.
The approach I'm taking is that each screen has references to 4 neighbors stored in a HashMap<Direction, Rc<RefCell<Screen>>>.
What I'm struggling with is how to "move"/iterate in a direction until I reach the edge of the mesh:
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Debug, Copy, Clone, Default)]
pub struct ScreenCoord {
left: i32,
right: i32,
bottom: i32,
top: i32,
}
impl ScreenCoord {
fn new_primary_from_dimensions(width: i32, height: i32) -> ScreenCoord {
ScreenCoord {
left: 0,
right: width,
top: 0,
bottom: height,
}
}
}
pub struct ScreenNetwork {
primary_screen: Rc<RefCell<Screen>>,
}
impl ScreenNetwork {
pub fn new(width: i32, height: i32) -> ScreenNetwork {
ScreenNetwork {
primary_screen: Rc::new(RefCell::new(Screen::new(
ScreenCoord::new_primary_from_dimensions(width, height),
))),
}
}
pub fn add_screen(&mut self, new_width: i32, new_height: i32, direction: Direction) {
let mut new_scrn = Screen::new(ScreenCoord::new_primary_from_dimensions(
new_width, new_height,
));
let mut original_screen = &self.primary_screen;
while let Some(next) = original_screen.borrow().neighbours.get(&direction) {
original_screen = next;
}
// Do stuff with original_screen
// new_scrn.neighbours.insert(Direction::from_u8((direction.clone() as u8) ^ 0b11).unwrap(), original_screen.clone());
// original_screen.borrow_mut().neighbours.insert(direction, Rc::new(RefCell::new(new_scrn)));
}
}
/// Screen with information about adjacent screens
#[derive(Default, Debug)]
pub struct Screen {
neighbours: HashMap<Direction, Rc<RefCell<Screen>>>,
coordinates: ScreenCoord,
}
impl Screen {
pub fn new(coord: ScreenCoord) -> Screen {
Screen {
coordinates: coord,
neighbours: HashMap::new(),
}
}
}
#[derive(Debug, PartialEq, Hash, Eq, Clone)]
pub enum Direction {
Left = 0,
Top,
Bottom,
Right,
}
fn main() {}
playground
error[E0597]: borrowed value does not live long enough
--> src/main.rs:43:32
|
43 | while let Some(next) = original_screen.borrow().neighbours.get(&direction) {
| ^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value dropped here while still borrowed
| |
| temporary value does not live long enough
...
51 | }
| - temporary value needs to live until here
I understand why the error is happening, but I have no clue as to how I can fix it. I tried to clone original_screen and next, but then the compiler complains that I am trying to set original_screen while still borrowing it.
You are using Rc, so take advantage of it. Generally speaking, taking a reference to a Rc is asking for problems.
First try: clone Rc when needed:
let mut original_screen = self.primary_screen.clone();
while let Some(next) = original_screen.borrow().neighbours.get(&direction) {
original_screen = next.clone();
}
It fails with the message:
cannot assign to original_screen because it is borrowed
True enough: having a borrow in the while condition will not let you update it, but it can be rewritten easily:
loop {
if let Some(next) = original_screen.borrow().neighbours.get(&direction) {
original_screen = next.clone()
} else {
break;
}
}
That code is equivalent, and indeed it fails with the same error message! But now we are closer to a solution:
loop {
let next = if let Some(next) = original_screen.borrow().neighbours.get(&direction) {
next.clone()
} else {
break;
};
original_screen = next;
}
Now it compiles because the assignment is done after the borrow is released.

How do I iterate over a Vec of functions returning Futures in Rust?

Is it possible to loop over a Vec, calling a method that returns a Future on each, and build a chain of Futures, to be evaluated (eventually) by the consumer? Whether to execute the later Futures would depend on the outcome of the earlier Futures in the Vec.
To clarify:
I'm working on an application that can fetch data from an arbitrary set of upstream sources.
Requesting data would check with each of the sources, in turn. If the first source had an error (Err), or did not have the data available (None), then the second source would be tried, and so on.
Each source should be tried exactly once, and no source should be tried until all of the sources before have returned their results. Errors are logged, but otherwise ignored, passing the query to the next upstream data source.
I have some working code that does this for fetching metadata:
/// Attempts to read/write data to various external sources. These are
/// nested types, because a data source may exist as both a reader and a writer
struct StoreManager {
/// Upstream data sources
readers: Vec<Rc<RefCell<StoreRead>>>,
/// Downstream data sinks
writers: Vec<Rc<RefCell<StoreWrite>>>,
}
impl StoreRead for StoreManager {
fn metadata(self: &Self, id: &Identifier) -> Box<Future<Option<Metadata>, Error>> {
Box::new(ok(self.readers
.iter()
.map(|store| {
executor::block_on(store.borrow().metadata(id)).unwrap_or_else(|err| {
error!("Error on metadata(): {:?}", err);
None
})
})
.find(Option::is_some)
.unwrap_or(None)))
}
}
Aside from my unhappiness with all of the Box and Rc/RefCell nonsense, my real concern is with the executor::block_on() call. It blocks, waiting for each Future to return a result, before continuing to the next.
Given that it's possible to call fn_returning_future().or_else(|_| other_fn()) and so on, is it possible to build up a dynamic chain like this? Or is it a requirement to fully evaluate each Future in the iterator before moving to the next?
You can use stream::unfold to convert a single value into a stream. In this case, we can use the IntoIter iterator as that single value.
use futures::{executor, stream, Stream, TryStreamExt}; // 0.3.4
type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
async fn network_request(val: i32) -> Result<i32> {
// Just for demonstration, don't do this in a real program
use std::{
thread,
time::{Duration, Instant},
};
thread::sleep(Duration::from_secs(1));
println!("Resolving {} at {:?}", val, Instant::now());
Ok(val * 100)
}
fn requests_in_sequence(vals: Vec<i32>) -> impl Stream<Item = Result<i32>> {
stream::unfold(vals.into_iter(), |mut vals| async {
let val = vals.next()?;
let response = network_request(val).await;
Some((response, vals))
})
}
fn main() {
let s = requests_in_sequence(vec![1, 2, 3]);
executor::block_on(async {
s.try_for_each(|v| async move {
println!("-> {}", v);
Ok(())
})
.await
.expect("An error occurred");
});
}
Resolving 1 at Instant { tv_sec: 6223328, tv_nsec: 294631597 }
-> 100
Resolving 2 at Instant { tv_sec: 6223329, tv_nsec: 310839993 }
-> 200
Resolving 3 at Instant { tv_sec: 6223330, tv_nsec: 311005834 }
-> 300
To ignore Err and None, you have to shuttle the Error over to the Item, making the Item type a Result<Option<T>, Error>:
use futures::{executor, stream, Stream, StreamExt}; // 0.3.4
type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
async fn network_request(val: i32) -> Result<Option<i32>> {
// Just for demonstration, don't do this in a real program
use std::{
thread,
time::{Duration, Instant},
};
thread::sleep(Duration::from_secs(1));
println!("Resolving {} at {:?}", val, Instant::now());
match val {
1 => Err("boom".into()), // An error
2 => Ok(None), // No data
_ => Ok(Some(val * 100)), // Success
}
}
fn requests_in_sequence(vals: Vec<i32>) -> impl Stream<Item = Result<Option<i32>>> {
stream::unfold(vals.into_iter(), |mut vals| async {
let val = vals.next()?;
let response = network_request(val).await;
Some((response, vals))
})
}
fn main() {
executor::block_on(async {
let s = requests_in_sequence(vec![1, 2, 3]);
let s = s.filter_map(|v| async move { v.ok() });
let s = s.filter_map(|v| async move { v });
let mut s = s.boxed_local();
match s.next().await {
Some(v) => println!("First success: {}", v),
None => println!("No successful requests"),
}
});
}
Resolving 1 at Instant { tv_sec: 6224229, tv_nsec: 727216392 }
Resolving 2 at Instant { tv_sec: 6224230, tv_nsec: 727404752 }
Resolving 3 at Instant { tv_sec: 6224231, tv_nsec: 727593740 }
First success: 300
is it possible to build up a dynamic chain like this
Yes, by leveraging async functions:
use futures::executor; // 0.3.4
type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
async fn network_request(val: i32) -> Result<Option<i32>> {
// Just for demonstration, don't do this in a real program
use std::{
thread,
time::{Duration, Instant},
};
thread::sleep(Duration::from_secs(1));
println!("Resolving {} at {:?}", val, Instant::now());
match val {
1 => Err("boom".into()), // An error
2 => Ok(None), // No data
_ => Ok(Some(val * 100)), // Success
}
}
async fn requests_in_sequence(vals: Vec<i32>) -> Result<i32> {
let mut vals = vals.into_iter().peekable();
while let Some(v) = vals.next() {
match network_request(v).await {
Ok(Some(v)) => return Ok(v),
Err(e) if vals.peek().is_none() => return Err(e),
Ok(None) | Err(_) => { /* Do nothing and try the next source */ }
}
}
Err("Ran out of sources".into())
}
fn main() {
executor::block_on(async {
match requests_in_sequence(vec![1, 2, 3]).await {
Ok(v) => println!("First success: {}", v),
Err(e) => println!("No successful requests: {}", e),
}
});
}
See also:
Creating Diesel.rs queries with a dynamic number of .and()'s
is it a requirement to fully evaluate each Future in the iterator before moving to the next
Isn't that part of your own requirements? Emphasis mine:
Requesting data would check with each of the sources, in turn. If the first source had an error (Err), or did not have the data available (None), then the second source would be tried

How to handle errors from the Read::read_to_end method?

I am reading a file and parsing the data:
fn main() {
parse_torrentfile("ubuntu-16.04.1-server-amd64.torrent");
}
fn parse_file(filename: &'static str) {
let mut f = File::open(&Path::new(filename)).unwrap();
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
}
If ubuntu-16.04.1-server-amd64.torrent is present, this works well, but if it isn't present, this error occurs:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 2, message: "No such file or directory" } }'
How can I print "Not Exist File" or "process file parsing"?
You should be matching on the Result instead of calling unwrap() or expect(). Once you've got the error, you can either print it out or look at the ErrorKind if you want to handle different errors differently.
use std::fs::File;
use std::path::Path;
use std::io::Read;
fn main() {
parse_file("doesnt_exist.txt");
}
fn parse_file(filename: &'static str) {
let mut f = match File::open(&Path::new(filename)) {
Ok(f) => f,
Err(e) => {
use std::io::ErrorKind::*;
println!("Got error: {}", e);
match e.kind() {
NotFound => {
println!("File not found");
}
k => {
println!("Error: {:?}", k);
}
}
return;
}
};
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
}
Playground
Probably the most idiomatic approach would be propagating the result outside parse_file, printing the error in main.
use std::fs::File;
use std::io::{Read, Error as IoError};
use std::path::Path;
fn main() {
match parse_file("ubuntu-16.04.1-server-amd64.torrent") {
Err(e) => println!("{}", e),
_ => {}
}
}
fn parse_file(filename: &'static str) -> Result<(), IoError> {
let mut f = File::open(&Path::new(filename))?;
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
Ok(())
}
If you want to print the error in one line and then propagating it, you could do something like this instead:
fn main() {
parse_file("ubuntu-16.04.1-server-amd64.torrent");
}
fn parse_file(filename: &'static str) -> Result<(), IoError> {
let mut f = File::open(&Path::new(filename)).map_err(|e| {
println!("{}", e);
e
})?;
let mut v: Vec<u8> = Vec::new();
let file_content = f.read_to_end(&mut v);
println!("{:?}", file_content);
Ok(())
}

Can Rust consume an iterator passed into a function?

I'm trying to implement a simple REPL calculator in Rust and I'm hitting brick walls all over the place.
I'm consuming chars while iterating over a hardcoded string. When I hit a numeric character I want to pass control over to a function that will consume the rest of the number (assuming the number has more than one digit) and return the number, converted to an Integer.
I'm having trouble with passing Chars iterator to a function. The error I'm getting is use of moved value: 'iter'.
I understand that I can't mutate something that I gave to someone else - something that had its ownership moved - but I don't know any other way of doing this, especially since the Chars iterator is non-copyable.
#[derive(Clone, Debug)]
enum Token {
Addition,
Substraction,
Multiplication,
Division,
Integer(i32),
Error,
}
fn consume_number(mut iter: std::str::Chars) -> Option<i32> {
while let Some(item) = iter.next() {
println!("{:?}", item);
}
return Some(1337);
}
fn tokenize(line: &str) -> Vec<Token> {
let mut iter = line.chars();
let mut tokens = Vec::new();
let mut token;
while let Some(c) = iter.next() {
if c.is_whitespace() { continue };
if c.is_digit(10) {
token = match consume_number(iter) {
Some(i32) => Token::Integer(i32),
None => Token::Error,
};
} else {
token = match c {
'+' => Token::Addition,
'-' => Token::Substraction,
'*' => Token::Multiplication,
'/' => Token::Division,
_ => Token::Error,
};
};
tokens.push(token);
}
return tokens;
}
fn main() {
let line = "631 * 32 + 212 - 15 / 89";
println!("{:?}", tokenize(&line));
}
The answer is yes, it's done in the FromIterator trait.
What you experience here is much more basic:
fn consume_number(mut iter: std::str::Chars) -> Option<i32> { ... }
while let Some(c) = iter.next() {
...
match_consume_number(iter)
...
}
When calling match_consume_number you are transferring ownership of the iterator to it. It means that at the next iteration of the loop body, this iter variable is no longer available.
If the iterator is meant to still be usable afterward, you should pass a reference to it:
fn consume_number(iter: &mut std::str::Chars) -> Option<i32> { ... }
while let Some(c) = iter.next() {
...
match_consume_number(&mut iter)
...
}
You were close!