@@ -29,22 +29,27 @@ use self::StdSource::*;
29
29
30
30
use boxed:: Box ;
31
31
use cell:: RefCell ;
32
+ use clone:: Clone ;
32
33
use failure:: LOCAL_STDERR ;
33
34
use fmt;
34
- use io:: { Reader , Writer , IoResult , IoError , OtherIoError ,
35
+ use io:: { Reader , Writer , IoResult , IoError , OtherIoError , Buffer ,
35
36
standard_error, EndOfFile , LineBufferedWriter , BufferedReader } ;
36
37
use kinds:: Send ;
37
38
use libc;
38
39
use mem;
39
40
use option:: { Option , Some , None } ;
41
+ use ops:: { Deref , DerefMut } ;
40
42
use result:: { Ok , Err } ;
41
43
use rustrt;
42
44
use rustrt:: local:: Local ;
43
45
use rustrt:: task:: Task ;
44
46
use slice:: SlicePrelude ;
45
47
use str:: StrPrelude ;
48
+ use string:: String ;
46
49
use sys:: { fs, tty} ;
50
+ use sync:: { Arc , Mutex , MutexGuard , Once , ONCE_INIT } ;
47
51
use uint;
52
+ use vec:: Vec ;
48
53
49
54
// And so begins the tale of acquiring a uv handle to a stdio stream on all
50
55
// platforms in all situations. Our story begins by splitting the world into two
@@ -90,28 +95,135 @@ thread_local!(static LOCAL_STDOUT: RefCell<Option<Box<Writer + Send>>> = {
90
95
RefCell :: new( None )
91
96
} )
92
97
93
- /// Creates a new non-blocking handle to the stdin of the current process.
94
- ///
95
- /// The returned handled is buffered by default with a `BufferedReader`. If
96
- /// buffered access is not desired, the `stdin_raw` function is provided to
97
- /// provided unbuffered access to stdin.
98
+ /// A synchronized wrapper around a buffered reader from stdin
99
+ #[ deriving( Clone ) ]
100
+ pub struct StdinReader {
101
+ inner : Arc < Mutex < BufferedReader < StdReader > > > ,
102
+ }
103
+
104
+ /// A guard for exlusive access to `StdinReader`'s internal `BufferedReader`.
105
+ pub struct StdinReaderGuard < ' a > {
106
+ inner : MutexGuard < ' a , BufferedReader < StdReader > > ,
107
+ }
108
+
109
+ impl < ' a > Deref < BufferedReader < StdReader > > for StdinReaderGuard < ' a > {
110
+ fn deref ( & self ) -> & BufferedReader < StdReader > {
111
+ & * self . inner
112
+ }
113
+ }
114
+
115
+ impl < ' a > DerefMut < BufferedReader < StdReader > > for StdinReaderGuard < ' a > {
116
+ fn deref_mut ( & mut self ) -> & mut BufferedReader < StdReader > {
117
+ & mut * self . inner
118
+ }
119
+ }
120
+
121
+ impl StdinReader {
122
+ /// Locks the `StdinReader`, granting the calling thread exclusive access
123
+ /// to the underlying `BufferedReader`.
124
+ ///
125
+ /// This provides access to methods like `chars` and `lines`.
126
+ ///
127
+ /// ## Example
128
+ ///
129
+ /// ```rust
130
+ /// use std::io;
131
+ ///
132
+ /// for line in io::stdin().lock().lines() {
133
+ /// println!("{}", line.unwrap());
134
+ /// }
135
+ /// ```
136
+ pub fn lock < ' a > ( & ' a mut self ) -> StdinReaderGuard < ' a > {
137
+ StdinReaderGuard {
138
+ inner : self . inner . lock ( )
139
+ }
140
+ }
141
+
142
+ /// Like `Buffer::read_line`.
143
+ ///
144
+ /// The read is performed atomically - concurrent read calls in other
145
+ /// threads will not interleave with this one.
146
+ pub fn read_line ( & mut self ) -> IoResult < String > {
147
+ self . inner . lock ( ) . read_line ( )
148
+ }
149
+
150
+ /// Like `Buffer::read_until`.
151
+ ///
152
+ /// The read is performed atomically - concurrent read calls in other
153
+ /// threads will not interleave with this one.
154
+ pub fn read_until ( & mut self , byte : u8 ) -> IoResult < Vec < u8 > > {
155
+ self . inner . lock ( ) . read_until ( byte)
156
+ }
157
+
158
+ /// Like `Buffer::read_char`.
159
+ ///
160
+ /// The read is performed atomically - concurrent read calls in other
161
+ /// threads will not interleave with this one.
162
+ pub fn read_char ( & mut self ) -> IoResult < char > {
163
+ self . inner . lock ( ) . read_char ( )
164
+ }
165
+ }
166
+
167
+ impl Reader for StdinReader {
168
+ fn read ( & mut self , buf : & mut [ u8 ] ) -> IoResult < uint > {
169
+ self . inner . lock ( ) . read ( buf)
170
+ }
171
+
172
+ // We have to manually delegate all of these because the default impls call
173
+ // read more than once and we don't want those calls to interleave (or
174
+ // incur the costs of repeated locking).
175
+
176
+ fn read_at_least ( & mut self , min : uint , buf : & mut [ u8 ] ) -> IoResult < uint > {
177
+ self . inner . lock ( ) . read_at_least ( min, buf)
178
+ }
179
+
180
+ fn push_at_least ( & mut self , min : uint , len : uint , buf : & mut Vec < u8 > ) -> IoResult < uint > {
181
+ self . inner . lock ( ) . push_at_least ( min, len, buf)
182
+ }
183
+
184
+ fn read_to_end ( & mut self ) -> IoResult < Vec < u8 > > {
185
+ self . inner . lock ( ) . read_to_end ( )
186
+ }
187
+
188
+ fn read_le_uint_n ( & mut self , nbytes : uint ) -> IoResult < u64 > {
189
+ self . inner . lock ( ) . read_le_uint_n ( nbytes)
190
+ }
191
+
192
+ fn read_be_uint_n ( & mut self , nbytes : uint ) -> IoResult < u64 > {
193
+ self . inner . lock ( ) . read_be_uint_n ( nbytes)
194
+ }
195
+ }
196
+
197
+ /// Creates a new handle to the stdin of the current process.
98
198
///
99
- /// Care should be taken when creating multiple handles to the stdin of a
100
- /// process. Because this is a buffered reader by default, it's possible for
101
- /// pending input to be unconsumed in one reader and unavailable to other
102
- /// readers. It is recommended that only one handle at a time is created for the
103
- /// stdin of a process.
199
+ /// The returned handle is a wrapper around a global `BufferedReader` shared
200
+ /// by all threads. If buffered access is not desired, the `stdin_raw` function
201
+ /// is provided to provided unbuffered access to stdin.
104
202
///
105
203
/// See `stdout()` for more notes about this function.
106
- pub fn stdin ( ) -> BufferedReader < StdReader > {
107
- // The default buffer capacity is 64k, but apparently windows doesn't like
108
- // 64k reads on stdin. See #13304 for details, but the idea is that on
109
- // windows we use a slightly smaller buffer that's been seen to be
110
- // acceptable.
111
- if cfg ! ( windows) {
112
- BufferedReader :: with_capacity ( 8 * 1024 , stdin_raw ( ) )
113
- } else {
114
- BufferedReader :: new ( stdin_raw ( ) )
204
+ pub fn stdin ( ) -> StdinReader {
205
+ // We're following the same strategy as kimundi's lazy_static library
206
+ static mut STDIN : * const StdinReader = 0 as * const StdinReader ;
207
+ static ONCE : Once = ONCE_INIT ;
208
+
209
+ unsafe {
210
+ ONCE . doit ( || {
211
+ // The default buffer capacity is 64k, but apparently windows doesn't like
212
+ // 64k reads on stdin. See #13304 for details, but the idea is that on
213
+ // windows we use a slightly smaller buffer that's been seen to be
214
+ // acceptable.
215
+ let stdin = if cfg ! ( windows) {
216
+ BufferedReader :: with_capacity ( 8 * 1024 , stdin_raw ( ) )
217
+ } else {
218
+ BufferedReader :: new ( stdin_raw ( ) )
219
+ } ;
220
+ let stdin = StdinReader {
221
+ inner : Arc :: new ( Mutex :: new ( stdin) )
222
+ } ;
223
+ STDIN = mem:: transmute ( box stdin) ;
224
+ } ) ;
225
+
226
+ ( * STDIN ) . clone ( )
115
227
}
116
228
}
117
229
0 commit comments