virtual_io/vio.rs
1use std::{env::VarError, io::Write};
2
3/// Virtual IO is a rust library for easily implementing stdin and stdout in a
4/// testable way. It replaces all `println!` and `print!` macro calls.
5///
6/// ```rs
7/// use virtual_io::{VirtualIo, Vio};
8///
9/// fn get_name() -> String {
10/// get_name_base(&mut virtual_io::new())
11/// }
12///
13/// fn get_name_base(vio: &mut impl VirtualIo) -> String {
14/// vio.print("What is your name? ");
15/// let name = vio.read_line();
16/// vio.println(format!("Hello, {}!", name));
17/// name
18/// }
19/// ```
20pub trait VirtualIo {
21 /// Prints a message to the console. Is close to the `print!` macro with
22 /// one difference: output is not buffered and is instead immediately
23 /// flushed.
24 fn print<S: Into<String>>(&mut self, message: S) -> &mut Self;
25
26 /// Prints a message to the console with a new line at the end. Is
27 /// equivalent to the `println!` macro.
28 fn println<S: Into<String>>(&mut self, message: S) -> &mut Self;
29
30 /// Get user input from the console. The input ends when the user types
31 /// a new line.
32 fn read_line(&mut self) -> String;
33
34 /// Get an environment variable. Is equivalent to `std::env::var`.
35 ///
36 /// # Errors
37 /// Returns an error if the environment variable is not present.
38 fn get_environment_var<S: Into<String>>(&self, variable: S) -> Result<String, VarError>;
39
40 /// Get an environment variables as a vector. Each item in the vector
41 /// is a (key, value) tuple.
42 fn get_environment_vars(&self) -> Vec<(String, String)>;
43}
44
45#[derive(PartialEq, Eq, Debug, Default)]
46pub struct Vio {}
47
48impl VirtualIo for Vio {
49 fn print<S: Into<String>>(&mut self, message: S) -> &mut Self {
50 print!("{}", message.into());
51 if std::io::stdout().flush().is_ok() {};
52 self
53 }
54
55 fn println<S: Into<String>>(&mut self, message: S) -> &mut Self {
56 println!("{}", message.into());
57 self
58 }
59
60 fn read_line(&mut self) -> String {
61 let mut input = String::new();
62 match std::io::stdin().read_line(&mut input) {
63 Ok(_) => input.trim().to_string(),
64 Err(_) => String::new(),
65 }
66 }
67
68 fn get_environment_var<S: Into<String>>(&self, variable: S) -> Result<String, VarError> {
69 std::env::var(variable.into())
70 }
71
72 fn get_environment_vars(&self) -> Vec<(String, String)> {
73 std::env::vars().collect()
74 }
75}
76
77impl Vio {
78 #[must_use]
79 pub const fn new() -> Self {
80 Self {}
81 }
82}