@@ -5,7 +5,7 @@ use crate::io::prelude::*;
5
5
use crate :: cell:: RefCell ;
6
6
use crate :: fmt;
7
7
use crate :: io:: lazy:: Lazy ;
8
- use crate :: io:: { self , Initializer , BufReader , LineWriter , IoSlice , IoSliceMut } ;
8
+ use crate :: io:: { self , Initializer , BufReader , BufWriter , LineWriter , IoSlice , IoSliceMut } ;
9
9
use crate :: sync:: { Arc , Mutex , MutexGuard } ;
10
10
use crate :: sys:: stdio;
11
11
use crate :: sys_common:: remutex:: { ReentrantMutex , ReentrantMutexGuard } ;
@@ -103,48 +103,31 @@ impl Write for StderrRaw {
103
103
fn flush ( & mut self ) -> io:: Result < ( ) > { self . 0 . flush ( ) }
104
104
}
105
105
106
- enum Maybe < T > {
107
- Real ( T ) ,
108
- Fake ,
109
- }
106
+ /// Maps `EBADF` errors for reading and writing to success.
107
+ struct HandleEbadf < T > ( T ) ;
110
108
111
- impl < W : io :: Write > io :: Write for Maybe < W > {
109
+ impl < W : Write > Write for HandleEbadf < W > {
112
110
fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
113
- match * self {
114
- Maybe :: Real ( ref mut w) => handle_ebadf ( w. write ( buf) , buf. len ( ) ) ,
115
- Maybe :: Fake => Ok ( buf. len ( ) )
116
- }
111
+ handle_ebadf ( self . 0 . write ( buf) , buf. len ( ) )
117
112
}
118
-
119
113
fn write_vectored ( & mut self , bufs : & [ IoSlice < ' _ > ] ) -> io:: Result < usize > {
120
114
let total = bufs. iter ( ) . map ( |b| b. len ( ) ) . sum ( ) ;
121
- match self {
122
- Maybe :: Real ( w) => handle_ebadf ( w. write_vectored ( bufs) , total) ,
123
- Maybe :: Fake => Ok ( total) ,
124
- }
115
+ handle_ebadf ( self . 0 . write_vectored ( bufs) , total)
125
116
}
126
-
127
117
fn flush ( & mut self ) -> io:: Result < ( ) > {
128
- match * self {
129
- Maybe :: Real ( ref mut w) => handle_ebadf ( w. flush ( ) , ( ) ) ,
130
- Maybe :: Fake => Ok ( ( ) )
131
- }
118
+ handle_ebadf ( self . 0 . flush ( ) , ( ) )
132
119
}
133
120
}
134
121
135
- impl < R : io :: Read > io :: Read for Maybe < R > {
122
+ impl < R : Read > Read for HandleEbadf < R > {
136
123
fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
137
- match * self {
138
- Maybe :: Real ( ref mut r) => handle_ebadf ( r. read ( buf) , 0 ) ,
139
- Maybe :: Fake => Ok ( 0 )
140
- }
124
+ handle_ebadf ( self . 0 . read ( buf) , 0 )
141
125
}
142
-
143
126
fn read_vectored ( & mut self , bufs : & mut [ IoSliceMut < ' _ > ] ) -> io:: Result < usize > {
144
- match self {
145
- Maybe :: Real ( r ) => handle_ebadf ( r . read_vectored ( bufs ) , 0 ) ,
146
- Maybe :: Fake => Ok ( 0 )
147
- }
127
+ handle_ebadf ( self . 0 . read_vectored ( bufs ) , 0 )
128
+ }
129
+ unsafe fn initializer ( & self ) -> Initializer {
130
+ self . 0 . initializer ( )
148
131
}
149
132
}
150
133
@@ -155,6 +138,121 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
155
138
}
156
139
}
157
140
141
+ enum StdioBufferKind {
142
+ LineBuffered ,
143
+ Buffered ,
144
+ Unbuffered ,
145
+ }
146
+
147
+ /// A reader that can either be buffered or fake.
148
+ ///
149
+ /// If it is fake, all reads succeed and indicate end-of-file.
150
+ enum StdioReader < R : Read > {
151
+ Buffered ( BufReader < HandleEbadf < R > > ) ,
152
+ Fake ,
153
+ }
154
+
155
+ impl < R : Read > StdioReader < R > {
156
+ fn new_buffered ( reader : R ) -> StdioReader < R > {
157
+ let cap = stdio:: STDIN_BUF_SIZE ;
158
+ StdioReader :: Buffered ( BufReader :: with_capacity ( cap, HandleEbadf ( reader) ) )
159
+ }
160
+ fn new_fake ( ) -> StdioReader < R > {
161
+ StdioReader :: Fake
162
+ }
163
+ }
164
+
165
+ impl < R : Read > Read for StdioReader < R > {
166
+ fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
167
+ match self {
168
+ StdioReader :: Buffered ( i) => i. read ( buf) ,
169
+ StdioReader :: Fake => Ok ( 0 ) ,
170
+ }
171
+ }
172
+ fn read_vectored ( & mut self , bufs : & mut [ io:: IoSliceMut < ' _ > ] ) -> io:: Result < usize > {
173
+ match self {
174
+ StdioReader :: Buffered ( i) => i. read_vectored ( bufs) ,
175
+ StdioReader :: Fake => Ok ( 0 ) ,
176
+ }
177
+ }
178
+ #[ inline]
179
+ unsafe fn initializer ( & self ) -> Initializer {
180
+ match self {
181
+ StdioReader :: Buffered ( i) => i. initializer ( ) ,
182
+ StdioReader :: Fake => Initializer :: nop ( ) ,
183
+ }
184
+ }
185
+ }
186
+
187
+ impl < R : Read > BufRead for StdioReader < R > {
188
+ fn fill_buf ( & mut self ) -> io:: Result < & [ u8 ] > {
189
+ match self {
190
+ StdioReader :: Buffered ( i) => i. fill_buf ( ) ,
191
+ StdioReader :: Fake => Ok ( & [ ] ) ,
192
+ }
193
+ }
194
+ fn consume ( & mut self , amt : usize ) {
195
+ match self {
196
+ StdioReader :: Buffered ( i) => i. consume ( amt) ,
197
+ StdioReader :: Fake => ( ) ,
198
+ }
199
+ }
200
+ }
201
+
202
+ /// A writer that can either be line-buffered, buffered, unbuffered or fake.
203
+ ///
204
+ /// If it is fake, all outputs just succeed and are dropped silently.
205
+ enum StdioWriter < W : Write > {
206
+ LineBuffered ( LineWriter < HandleEbadf < W > > ) ,
207
+ Buffered ( BufWriter < HandleEbadf < W > > ) ,
208
+ Unbuffered ( HandleEbadf < W > ) ,
209
+ Fake ,
210
+ }
211
+
212
+ impl < W : Write > StdioWriter < W > {
213
+ fn new ( writer : W , kind : StdioBufferKind ) -> StdioWriter < W > {
214
+ let writer = HandleEbadf ( writer) ;
215
+ match kind {
216
+ StdioBufferKind :: LineBuffered =>
217
+ StdioWriter :: LineBuffered ( LineWriter :: new ( writer) ) ,
218
+ StdioBufferKind :: Buffered =>
219
+ StdioWriter :: Buffered ( BufWriter :: new ( writer) ) ,
220
+ StdioBufferKind :: Unbuffered =>
221
+ StdioWriter :: Unbuffered ( writer) ,
222
+ }
223
+ }
224
+ fn new_fake ( ) -> StdioWriter < W > {
225
+ StdioWriter :: Fake
226
+ }
227
+ }
228
+
229
+ impl < W : Write > Write for StdioWriter < W > {
230
+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
231
+ match self {
232
+ StdioWriter :: LineBuffered ( i) => i. write ( buf) ,
233
+ StdioWriter :: Buffered ( i) => i. write ( buf) ,
234
+ StdioWriter :: Unbuffered ( i) => i. write ( buf) ,
235
+ StdioWriter :: Fake => Ok ( buf. len ( ) ) ,
236
+ }
237
+ }
238
+ fn write_vectored ( & mut self , bufs : & [ io:: IoSlice < ' _ > ] ) -> io:: Result < usize > {
239
+ match self {
240
+ StdioWriter :: LineBuffered ( i) => i. write_vectored ( bufs) ,
241
+ StdioWriter :: Buffered ( i) => i. write_vectored ( bufs) ,
242
+ StdioWriter :: Unbuffered ( i) => i. write_vectored ( bufs) ,
243
+ StdioWriter :: Fake => Ok ( bufs. iter ( ) . map ( |b| b. len ( ) ) . sum ( ) ) ,
244
+ }
245
+ }
246
+ fn flush ( & mut self ) -> io:: Result < ( ) > {
247
+ match self {
248
+ StdioWriter :: LineBuffered ( i) => i. flush ( ) ,
249
+ StdioWriter :: Buffered ( i) => i. flush ( ) ,
250
+ StdioWriter :: Unbuffered ( i) => i. flush ( ) ,
251
+ StdioWriter :: Fake => Ok ( ( ) ) ,
252
+ }
253
+ }
254
+ }
255
+
158
256
/// A handle to the standard input stream of a process.
159
257
///
160
258
/// Each handle is a shared reference to a global buffer of input data to this
@@ -176,7 +274,7 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
176
274
/// an error.
177
275
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
178
276
pub struct Stdin {
179
- inner : Arc < Mutex < BufReader < Maybe < StdinRaw > > > > ,
277
+ inner : Arc < Mutex < StdioReader < StdinRaw > > > ,
180
278
}
181
279
182
280
/// A locked reference to the `Stdin` handle.
@@ -194,7 +292,7 @@ pub struct Stdin {
194
292
/// an error.
195
293
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
196
294
pub struct StdinLock < ' a > {
197
- inner : MutexGuard < ' a , BufReader < Maybe < StdinRaw > > > ,
295
+ inner : MutexGuard < ' a , StdioReader < StdinRaw > > ,
198
296
}
199
297
200
298
/// Constructs a new handle to the standard input of the current process.
@@ -240,21 +338,21 @@ pub struct StdinLock<'a> {
240
338
/// ```
241
339
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
242
340
pub fn stdin ( ) -> Stdin {
243
- static INSTANCE : Lazy < Mutex < BufReader < Maybe < StdinRaw > > > > = Lazy :: new ( ) ;
341
+ static INSTANCE : Lazy < Mutex < StdioReader < StdinRaw > > > = Lazy :: new ( ) ;
244
342
return Stdin {
245
343
inner : unsafe {
246
344
INSTANCE . get ( stdin_init) . expect ( "cannot access stdin during shutdown" )
247
345
} ,
248
346
} ;
249
347
250
- fn stdin_init ( ) -> Arc < Mutex < BufReader < Maybe < StdinRaw > > > > {
348
+ fn stdin_init ( ) -> Arc < Mutex < StdioReader < StdinRaw > > > {
251
349
// This must not reentrantly access `INSTANCE`
252
350
let stdin = match stdin_raw ( ) {
253
- Ok ( stdin) => Maybe :: Real ( stdin) ,
254
- _ => Maybe :: Fake
351
+ Ok ( stdin) => StdioReader :: new_buffered ( stdin) ,
352
+ _ => StdioReader :: new_fake ( ) ,
255
353
} ;
256
354
257
- Arc :: new ( Mutex :: new ( BufReader :: with_capacity ( stdio :: STDIN_BUF_SIZE , stdin) ) )
355
+ Arc :: new ( Mutex :: new ( stdin) )
258
356
}
259
357
}
260
358
@@ -401,7 +499,7 @@ pub struct Stdout {
401
499
// FIXME: this should be LineWriter or BufWriter depending on the state of
402
500
// stdout (tty or not). Note that if this is not line buffered it
403
501
// should also flush-on-panic or some form of flush-on-abort.
404
- inner : Arc < ReentrantMutex < RefCell < LineWriter < Maybe < StdoutRaw > > > > > ,
502
+ inner : Arc < ReentrantMutex < RefCell < StdioWriter < StdoutRaw > > > > ,
405
503
}
406
504
407
505
/// A locked reference to the `Stdout` handle.
@@ -418,7 +516,7 @@ pub struct Stdout {
418
516
/// [`Stdout::lock`]: struct.Stdout.html#method.lock
419
517
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
420
518
pub struct StdoutLock < ' a > {
421
- inner : ReentrantMutexGuard < ' a , RefCell < LineWriter < Maybe < StdoutRaw > > > > ,
519
+ inner : ReentrantMutexGuard < ' a , RefCell < StdioWriter < StdoutRaw > > > ,
422
520
}
423
521
424
522
/// Constructs a new handle to the standard output of the current process.
@@ -464,20 +562,20 @@ pub struct StdoutLock<'a> {
464
562
/// ```
465
563
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
466
564
pub fn stdout ( ) -> Stdout {
467
- static INSTANCE : Lazy < ReentrantMutex < RefCell < LineWriter < Maybe < StdoutRaw > > > > > = Lazy :: new ( ) ;
565
+ static INSTANCE : Lazy < ReentrantMutex < RefCell < StdioWriter < StdoutRaw > > > > = Lazy :: new ( ) ;
468
566
return Stdout {
469
567
inner : unsafe {
470
568
INSTANCE . get ( stdout_init) . expect ( "cannot access stdout during shutdown" )
471
569
} ,
472
570
} ;
473
571
474
- fn stdout_init ( ) -> Arc < ReentrantMutex < RefCell < LineWriter < Maybe < StdoutRaw > > > > > {
572
+ fn stdout_init ( ) -> Arc < ReentrantMutex < RefCell < StdioWriter < StdoutRaw > > > > {
475
573
// This must not reentrantly access `INSTANCE`
476
574
let stdout = match stdout_raw ( ) {
477
- Ok ( stdout) => Maybe :: Real ( stdout) ,
478
- _ => Maybe :: Fake ,
575
+ Ok ( stdout) => StdioWriter :: new ( stdout, StdioBufferKind :: LineBuffered ) ,
576
+ _ => StdioWriter :: new_fake ( ) ,
479
577
} ;
480
- Arc :: new ( ReentrantMutex :: new ( RefCell :: new ( LineWriter :: new ( stdout) ) ) )
578
+ Arc :: new ( ReentrantMutex :: new ( RefCell :: new ( stdout) ) )
481
579
}
482
580
}
483
581
@@ -565,7 +663,7 @@ impl fmt::Debug for StdoutLock<'_> {
565
663
/// an error.
566
664
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
567
665
pub struct Stderr {
568
- inner : Arc < ReentrantMutex < RefCell < Maybe < StderrRaw > > > > ,
666
+ inner : Arc < ReentrantMutex < RefCell < StdioWriter < StderrRaw > > > > ,
569
667
}
570
668
571
669
/// A locked reference to the `Stderr` handle.
@@ -581,7 +679,7 @@ pub struct Stderr {
581
679
/// an error.
582
680
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
583
681
pub struct StderrLock < ' a > {
584
- inner : ReentrantMutexGuard < ' a , RefCell < Maybe < StderrRaw > > > ,
682
+ inner : ReentrantMutexGuard < ' a , RefCell < StdioWriter < StderrRaw > > > ,
585
683
}
586
684
587
685
/// Constructs a new handle to the standard error of the current process.
@@ -623,18 +721,18 @@ pub struct StderrLock<'a> {
623
721
/// ```
624
722
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
625
723
pub fn stderr ( ) -> Stderr {
626
- static INSTANCE : Lazy < ReentrantMutex < RefCell < Maybe < StderrRaw > > > > = Lazy :: new ( ) ;
724
+ static INSTANCE : Lazy < ReentrantMutex < RefCell < StdioWriter < StderrRaw > > > > = Lazy :: new ( ) ;
627
725
return Stderr {
628
726
inner : unsafe {
629
727
INSTANCE . get ( stderr_init) . expect ( "cannot access stderr during shutdown" )
630
728
} ,
631
729
} ;
632
730
633
- fn stderr_init ( ) -> Arc < ReentrantMutex < RefCell < Maybe < StderrRaw > > > > {
731
+ fn stderr_init ( ) -> Arc < ReentrantMutex < RefCell < StdioWriter < StderrRaw > > > > {
634
732
// This must not reentrantly access `INSTANCE`
635
733
let stderr = match stderr_raw ( ) {
636
- Ok ( stderr) => Maybe :: Real ( stderr) ,
637
- _ => Maybe :: Fake ,
734
+ Ok ( stderr) => StdioWriter :: new ( stderr, StdioBufferKind :: Unbuffered ) ,
735
+ _ => StdioWriter :: new_fake ( ) ,
638
736
} ;
639
737
Arc :: new ( ReentrantMutex :: new ( RefCell :: new ( stderr) ) )
640
738
}
0 commit comments