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}