io_providers/
lib.rs

1//! Defines "provider" traits and implementations for different types of I/O operations.
2//!
3//! The purpose of this is mainly for dependency injection: by having your code depend on a
4//! generic provider, it can be tested by giving it a virtual, inspectable implementation of that
5//! provider. In production, the "real" implementation can be used.
6//!
7//! Each type of provider exists in its own submodule and can be used independently. However,
8//! this module also contains the all-encompassing `IoProvider` trait which provides access to
9//! all of them. If you have a lot of I/O dependencies, it might be easier to create and pass
10//! around one `&mut IoProvider` rather than several different providers.
11//!
12//! # Examples
13//!
14//! ```
15//! extern crate io_providers;
16//!
17//! use std::io::Write;
18//! use std::path::Path;
19//! use io_providers::{IoProvider, LocalIoProvider, VirtualIoProvider};
20//! use io_providers::env::Provider as EnvProvider;
21//! use io_providers::stream::Provider as StreamProvider;
22//!
23//! /// Gets the current working directory and prints it to stdout.
24//! fn do_work<P: IoProvider>(io: &mut P) {
25//!     let cur_dir = io.env().current_dir().unwrap();
26//!     let stdout = io.stream().output();
27//!     writeln!(stdout, "The current directory is: {}", cur_dir.to_str().unwrap()).unwrap();
28//! }
29//!
30//! fn main() {
31//!     test_do_work_prints_current_dir();
32//!
33//!     // Use a local I/O provider here to get real interaction with the system
34//!     let mut io = LocalIoProvider::new();
35//!     do_work(&mut io);
36//! }
37//!
38//! fn test_do_work_prints_current_dir() {
39//!     // Use a virtual I/O provider here so we can verify how it was used
40//!     let mut virtual_io = VirtualIoProvider::new();
41//!     virtual_io.env().set_current_dir(Path::new("/foo/bar")).unwrap();
42//!
43//!     do_work(&mut virtual_io);
44//!
45//!     assert_eq!(
46//!         "The current directory is: /foo/bar\n",
47//!         ::std::str::from_utf8(virtual_io.stream().read_output()).unwrap());
48//! }
49//! ```
50
51pub mod env;
52pub mod stream;
53
54/// Provides access to an environment provider and a stream provider.
55///
56/// See `env::Provider` and `stream::Provider` for more information.
57pub trait IoProvider {
58    // The type of the environment provider.
59    type E: env::Provider;
60
61    // The type of the stream provider.
62    type S: stream::Provider;
63
64    /// Gets the `env::Provider`.
65    fn env<'a>(&'a mut self) -> &'a mut Self::E;
66
67    /// Gets the `stream::Provider`.
68    fn stream<'a>(&'a mut self) -> &'a mut Self::S;
69}
70
71/// "Real" implementer of `IoProvider`, using standard streams and the local environment.
72///
73/// See `env::Local` and `stream::Std` for more information.
74pub struct LocalIoProvider {
75    env: env::Local,
76    stream: stream::Std,
77}
78
79impl LocalIoProvider {
80    /// Creates a new `LocalIoProvider`.
81    pub fn new() -> LocalIoProvider {
82        LocalIoProvider {
83            env: env::Local,
84            stream: stream::Std::new(),
85        }
86    }
87}
88
89impl IoProvider for LocalIoProvider {
90    type E = env::Local;
91    type S = stream::Std;
92
93    fn env<'a>(&'a mut self) -> &'a mut env::Local {
94        &mut self.env
95    }
96
97    fn stream<'a>(&'a mut self) -> &'a mut stream::Std {
98        &mut self.stream
99    }
100}
101
102/// Virtual implementer of `IoProvider`, using in-memory data which can be inspected.
103///
104/// See `env::Virtual` and `stream::Virtual` for more information.
105pub struct VirtualIoProvider {
106    env: env::Virtual,
107    stream: stream::Virtual,
108}
109
110impl VirtualIoProvider {
111    /// Creates a new `VirtualIoProvider`.
112    pub fn new() -> VirtualIoProvider {
113        VirtualIoProvider {
114            env: env::Virtual::new(),
115            stream: stream::Virtual::new(),
116        }
117    }
118}
119
120impl IoProvider for VirtualIoProvider {
121    type E = env::Virtual;
122    type S = stream::Virtual;
123
124    fn env<'a>(&'a mut self) -> &'a mut env::Virtual {
125        &mut self.env
126    }
127
128    fn stream<'a>(&'a mut self) -> &'a mut stream::Virtual {
129        &mut self.stream
130    }
131}