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}