Skip to content

Commit 78c16f8

Browse files
committed
Unify stdio buffering with faking unavailable stdio
1 parent 590ae0e commit 78c16f8

File tree

1 file changed

+148
-50
lines changed

1 file changed

+148
-50
lines changed

src/libstd/io/stdio.rs

+148-50
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::io::prelude::*;
55
use crate::cell::RefCell;
66
use crate::fmt;
77
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};
99
use crate::sync::{Arc, Mutex, MutexGuard};
1010
use crate::sys::stdio;
1111
use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
@@ -103,48 +103,31 @@ impl Write for StderrRaw {
103103
fn flush(&mut self) -> io::Result<()> { self.0.flush() }
104104
}
105105

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);
110108

111-
impl<W: io::Write> io::Write for Maybe<W> {
109+
impl<W: Write> Write for HandleEbadf<W> {
112110
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())
117112
}
118-
119113
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
120114
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)
125116
}
126-
127117
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(), ())
132119
}
133120
}
134121

135-
impl<R: io::Read> io::Read for Maybe<R> {
122+
impl<R: Read> Read for HandleEbadf<R> {
136123
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)
141125
}
142-
143126
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()
148131
}
149132
}
150133

@@ -155,6 +138,121 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
155138
}
156139
}
157140

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+
158256
/// A handle to the standard input stream of a process.
159257
///
160258
/// 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> {
176274
/// an error.
177275
#[stable(feature = "rust1", since = "1.0.0")]
178276
pub struct Stdin {
179-
inner: Arc<Mutex<BufReader<Maybe<StdinRaw>>>>,
277+
inner: Arc<Mutex<StdioReader<StdinRaw>>>,
180278
}
181279

182280
/// A locked reference to the `Stdin` handle.
@@ -194,7 +292,7 @@ pub struct Stdin {
194292
/// an error.
195293
#[stable(feature = "rust1", since = "1.0.0")]
196294
pub struct StdinLock<'a> {
197-
inner: MutexGuard<'a, BufReader<Maybe<StdinRaw>>>,
295+
inner: MutexGuard<'a, StdioReader<StdinRaw>>,
198296
}
199297

200298
/// Constructs a new handle to the standard input of the current process.
@@ -240,21 +338,21 @@ pub struct StdinLock<'a> {
240338
/// ```
241339
#[stable(feature = "rust1", since = "1.0.0")]
242340
pub fn stdin() -> Stdin {
243-
static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new();
341+
static INSTANCE: Lazy<Mutex<StdioReader<StdinRaw>>> = Lazy::new();
244342
return Stdin {
245343
inner: unsafe {
246344
INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown")
247345
},
248346
};
249347

250-
fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
348+
fn stdin_init() -> Arc<Mutex<StdioReader<StdinRaw>>> {
251349
// This must not reentrantly access `INSTANCE`
252350
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(),
255353
};
256354

257-
Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin)))
355+
Arc::new(Mutex::new(stdin))
258356
}
259357
}
260358

@@ -401,7 +499,7 @@ pub struct Stdout {
401499
// FIXME: this should be LineWriter or BufWriter depending on the state of
402500
// stdout (tty or not). Note that if this is not line buffered it
403501
// 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>>>>,
405503
}
406504

407505
/// A locked reference to the `Stdout` handle.
@@ -418,7 +516,7 @@ pub struct Stdout {
418516
/// [`Stdout::lock`]: struct.Stdout.html#method.lock
419517
#[stable(feature = "rust1", since = "1.0.0")]
420518
pub struct StdoutLock<'a> {
421-
inner: ReentrantMutexGuard<'a, RefCell<LineWriter<Maybe<StdoutRaw>>>>,
519+
inner: ReentrantMutexGuard<'a, RefCell<StdioWriter<StdoutRaw>>>,
422520
}
423521

424522
/// Constructs a new handle to the standard output of the current process.
@@ -464,20 +562,20 @@ pub struct StdoutLock<'a> {
464562
/// ```
465563
#[stable(feature = "rust1", since = "1.0.0")]
466564
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();
468566
return Stdout {
469567
inner: unsafe {
470568
INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown")
471569
},
472570
};
473571

474-
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
572+
fn stdout_init() -> Arc<ReentrantMutex<RefCell<StdioWriter<StdoutRaw>>>> {
475573
// This must not reentrantly access `INSTANCE`
476574
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(),
479577
};
480-
Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout))))
578+
Arc::new(ReentrantMutex::new(RefCell::new(stdout)))
481579
}
482580
}
483581

@@ -565,7 +663,7 @@ impl fmt::Debug for StdoutLock<'_> {
565663
/// an error.
566664
#[stable(feature = "rust1", since = "1.0.0")]
567665
pub struct Stderr {
568-
inner: Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>>,
666+
inner: Arc<ReentrantMutex<RefCell<StdioWriter<StderrRaw>>>>,
569667
}
570668

571669
/// A locked reference to the `Stderr` handle.
@@ -581,7 +679,7 @@ pub struct Stderr {
581679
/// an error.
582680
#[stable(feature = "rust1", since = "1.0.0")]
583681
pub struct StderrLock<'a> {
584-
inner: ReentrantMutexGuard<'a, RefCell<Maybe<StderrRaw>>>,
682+
inner: ReentrantMutexGuard<'a, RefCell<StdioWriter<StderrRaw>>>,
585683
}
586684

587685
/// Constructs a new handle to the standard error of the current process.
@@ -623,18 +721,18 @@ pub struct StderrLock<'a> {
623721
/// ```
624722
#[stable(feature = "rust1", since = "1.0.0")]
625723
pub fn stderr() -> Stderr {
626-
static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new();
724+
static INSTANCE: Lazy<ReentrantMutex<RefCell<StdioWriter<StderrRaw>>>> = Lazy::new();
627725
return Stderr {
628726
inner: unsafe {
629727
INSTANCE.get(stderr_init).expect("cannot access stderr during shutdown")
630728
},
631729
};
632730

633-
fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
731+
fn stderr_init() -> Arc<ReentrantMutex<RefCell<StdioWriter<StderrRaw>>>> {
634732
// This must not reentrantly access `INSTANCE`
635733
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(),
638736
};
639737
Arc::new(ReentrantMutex::new(RefCell::new(stderr)))
640738
}

0 commit comments

Comments
 (0)