]>
Commit | Line | Data |
---|---|---|
532ac7d7 XL |
1 | #![cfg_attr(test, allow(unused))] |
2 | ||
1b1a35ee XL |
3 | #[cfg(test)] |
4 | mod tests; | |
5 | ||
532ac7d7 XL |
6 | use crate::io::prelude::*; |
7 | ||
fc512014 | 8 | use crate::cell::{Cell, RefCell}; |
532ac7d7 | 9 | use crate::fmt; |
dfeec247 | 10 | use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; |
1b1a35ee | 11 | use crate::lazy::SyncOnceCell; |
2a314972 | 12 | use crate::pin::Pin; |
1b1a35ee | 13 | use crate::sync::atomic::{AtomicBool, Ordering}; |
fc512014 | 14 | use crate::sync::{Arc, Mutex, MutexGuard}; |
532ac7d7 | 15 | use crate::sys::stdio; |
1b1a35ee | 16 | use crate::sys_common; |
532ac7d7 | 17 | use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; |
532ac7d7 | 18 | |
fc512014 | 19 | type LocalStream = Arc<Mutex<Vec<u8>>>; |
c34b1796 | 20 | |
532ac7d7 | 21 | thread_local! { |
fc512014 XL |
22 | /// Used by the test crate to capture the output of the print macros and panics. |
23 | static OUTPUT_CAPTURE: Cell<Option<LocalStream>> = { | |
24 | Cell::new(None) | |
532ac7d7 XL |
25 | } |
26 | } | |
27 | ||
fc512014 | 28 | /// Flag to indicate OUTPUT_CAPTURE is used. |
1b1a35ee | 29 | /// |
fc512014 XL |
30 | /// If it is None and was never set on any thread, this flag is set to false, |
31 | /// and OUTPUT_CAPTURE can be safely ignored on all threads, saving some time | |
32 | /// and memory registering an unused thread local. | |
1b1a35ee | 33 | /// |
fc512014 XL |
34 | /// Note about memory ordering: This contains information about whether a |
35 | /// thread local variable might be in use. Although this is a global flag, the | |
1b1a35ee | 36 | /// memory ordering between threads does not matter: we only want this flag to |
fc512014 | 37 | /// have a consistent order between set_output_capture and print_to *within |
1b1a35ee XL |
38 | /// the same thread*. Within the same thread, things always have a perfectly |
39 | /// consistent order. So Ordering::Relaxed is fine. | |
fc512014 | 40 | static OUTPUT_CAPTURE_USED: AtomicBool = AtomicBool::new(false); |
1b1a35ee | 41 | |
c34b1796 AL |
42 | /// A handle to a raw instance of the standard input stream of this process. |
43 | /// | |
44 | /// This handle is not synchronized or buffered in any fashion. Constructed via | |
45 | /// the `std::io::stdio::stdin_raw` function. | |
46 | struct StdinRaw(stdio::Stdin); | |
47 | ||
48 | /// A handle to a raw instance of the standard output stream of this process. | |
49 | /// | |
50 | /// This handle is not synchronized or buffered in any fashion. Constructed via | |
51 | /// the `std::io::stdio::stdout_raw` function. | |
52 | struct StdoutRaw(stdio::Stdout); | |
53 | ||
54 | /// A handle to a raw instance of the standard output stream of this process. | |
55 | /// | |
56 | /// This handle is not synchronized or buffered in any fashion. Constructed via | |
57 | /// the `std::io::stdio::stderr_raw` function. | |
58 | struct StderrRaw(stdio::Stderr); | |
59 | ||
9346a6ac | 60 | /// Constructs a new raw handle to the standard input of this process. |
c34b1796 AL |
61 | /// |
62 | /// The returned handle does not interact with any other handles created nor | |
63 | /// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin` | |
64 | /// handles is **not** available to raw handles returned from this function. | |
65 | /// | |
66 | /// The returned handle has no external synchronization or buffering. | |
3dfed10e XL |
67 | #[unstable(feature = "libstd_sys_internals", issue = "none")] |
68 | const fn stdin_raw() -> StdinRaw { | |
69 | StdinRaw(stdio::Stdin::new()) | |
dfeec247 | 70 | } |
c34b1796 | 71 | |
e9174d1e | 72 | /// Constructs a new raw handle to the standard output stream of this process. |
c34b1796 AL |
73 | /// |
74 | /// The returned handle does not interact with any other handles created nor | |
75 | /// handles returned by `std::io::stdout`. Note that data is buffered by the | |
e9174d1e | 76 | /// `std::io::stdout` handles so writes which happen via this raw handle may |
c34b1796 AL |
77 | /// appear before previous writes. |
78 | /// | |
79 | /// The returned handle has no external synchronization or buffering layered on | |
80 | /// top. | |
3dfed10e XL |
81 | #[unstable(feature = "libstd_sys_internals", issue = "none")] |
82 | const fn stdout_raw() -> StdoutRaw { | |
83 | StdoutRaw(stdio::Stdout::new()) | |
dfeec247 | 84 | } |
c34b1796 | 85 | |
e9174d1e | 86 | /// Constructs a new raw handle to the standard error stream of this process. |
c34b1796 AL |
87 | /// |
88 | /// The returned handle does not interact with any other handles created nor | |
e9174d1e | 89 | /// handles returned by `std::io::stderr`. |
c34b1796 AL |
90 | /// |
91 | /// The returned handle has no external synchronization or buffering layered on | |
92 | /// top. | |
3dfed10e XL |
93 | #[unstable(feature = "libstd_sys_internals", issue = "none")] |
94 | const fn stderr_raw() -> StderrRaw { | |
95 | StderrRaw(stdio::Stderr::new()) | |
dfeec247 | 96 | } |
c34b1796 AL |
97 | |
98 | impl Read for StdinRaw { | |
dfeec247 | 99 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
3dfed10e | 100 | handle_ebadf(self.0.read(buf), 0) |
dfeec247 | 101 | } |
041b39d2 | 102 | |
48663c56 | 103 | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
3dfed10e | 104 | handle_ebadf(self.0.read_vectored(bufs), 0) |
48663c56 XL |
105 | } |
106 | ||
f9f354fc XL |
107 | #[inline] |
108 | fn is_read_vectored(&self) -> bool { | |
109 | self.0.is_read_vectored() | |
110 | } | |
111 | ||
041b39d2 XL |
112 | #[inline] |
113 | unsafe fn initializer(&self) -> Initializer { | |
114 | Initializer::nop() | |
54a0048b | 115 | } |
f035d41b XL |
116 | |
117 | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { | |
3dfed10e | 118 | handle_ebadf(self.0.read_to_end(buf), 0) |
f035d41b XL |
119 | } |
120 | ||
121 | fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { | |
3dfed10e | 122 | handle_ebadf(self.0.read_to_string(buf), 0) |
f035d41b | 123 | } |
c34b1796 | 124 | } |
f035d41b | 125 | |
c34b1796 | 126 | impl Write for StdoutRaw { |
dfeec247 | 127 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
3dfed10e | 128 | handle_ebadf(self.0.write(buf), buf.len()) |
dfeec247 | 129 | } |
48663c56 XL |
130 | |
131 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
3dfed10e XL |
132 | let total = bufs.iter().map(|b| b.len()).sum(); |
133 | handle_ebadf(self.0.write_vectored(bufs), total) | |
48663c56 XL |
134 | } |
135 | ||
f9f354fc XL |
136 | #[inline] |
137 | fn is_write_vectored(&self) -> bool { | |
138 | self.0.is_write_vectored() | |
139 | } | |
140 | ||
dfeec247 | 141 | fn flush(&mut self) -> io::Result<()> { |
3dfed10e | 142 | handle_ebadf(self.0.flush(), ()) |
dfeec247 | 143 | } |
f035d41b XL |
144 | |
145 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { | |
3dfed10e | 146 | handle_ebadf(self.0.write_all(buf), ()) |
f035d41b XL |
147 | } |
148 | ||
149 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
3dfed10e | 150 | handle_ebadf(self.0.write_all_vectored(bufs), ()) |
f035d41b XL |
151 | } |
152 | ||
153 | fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { | |
3dfed10e | 154 | handle_ebadf(self.0.write_fmt(fmt), ()) |
f035d41b | 155 | } |
c34b1796 | 156 | } |
f035d41b | 157 | |
c34b1796 | 158 | impl Write for StderrRaw { |
dfeec247 | 159 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
3dfed10e | 160 | handle_ebadf(self.0.write(buf), buf.len()) |
dfeec247 | 161 | } |
48663c56 XL |
162 | |
163 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
3dfed10e XL |
164 | let total = bufs.iter().map(|b| b.len()).sum(); |
165 | handle_ebadf(self.0.write_vectored(bufs), total) | |
48663c56 XL |
166 | } |
167 | ||
f9f354fc XL |
168 | #[inline] |
169 | fn is_write_vectored(&self) -> bool { | |
170 | self.0.is_write_vectored() | |
171 | } | |
172 | ||
dfeec247 | 173 | fn flush(&mut self) -> io::Result<()> { |
3dfed10e | 174 | handle_ebadf(self.0.flush(), ()) |
dfeec247 | 175 | } |
f035d41b XL |
176 | |
177 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { | |
3dfed10e | 178 | handle_ebadf(self.0.write_all(buf), ()) |
f035d41b XL |
179 | } |
180 | ||
181 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
3dfed10e | 182 | handle_ebadf(self.0.write_all_vectored(bufs), ()) |
f035d41b XL |
183 | } |
184 | ||
185 | fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { | |
3dfed10e | 186 | handle_ebadf(self.0.write_fmt(fmt), ()) |
f9f354fc | 187 | } |
62682a34 SL |
188 | } |
189 | ||
190 | fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> { | |
62682a34 | 191 | match r { |
abe05a73 | 192 | Err(ref e) if stdio::is_ebadf(e) => Ok(default), |
dfeec247 | 193 | r => r, |
62682a34 SL |
194 | } |
195 | } | |
196 | ||
c34b1796 AL |
197 | /// A handle to the standard input stream of a process. |
198 | /// | |
199 | /// Each handle is a shared reference to a global buffer of input data to this | |
9cc50fc6 | 200 | /// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods |
0731742a | 201 | /// (e.g., `.lines()`). Reads to this handle are otherwise locked with respect |
54a0048b | 202 | /// to other reads. |
c34b1796 AL |
203 | /// |
204 | /// This handle implements the `Read` trait, but beware that concurrent reads | |
205 | /// of `Stdin` must be executed with care. | |
bd371182 | 206 | /// |
9cc50fc6 SL |
207 | /// Created by the [`io::stdin`] method. |
208 | /// | |
3dfed10e | 209 | /// [`io::stdin`]: stdin |
9fa01778 XL |
210 | /// |
211 | /// ### Note: Windows Portability Consideration | |
3dfed10e | 212 | /// |
9fa01778 XL |
213 | /// When operating in a console, the Windows implementation of this stream does not support |
214 | /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return | |
215 | /// an error. | |
3dfed10e XL |
216 | /// |
217 | /// # Examples | |
218 | /// | |
219 | /// ```no_run | |
220 | /// use std::io::{self, Read}; | |
221 | /// | |
222 | /// fn main() -> io::Result<()> { | |
223 | /// let mut buffer = String::new(); | |
224 | /// let mut stdin = io::stdin(); // We get `Stdin` here. | |
225 | /// stdin.read_to_string(&mut buffer)?; | |
226 | /// Ok(()) | |
227 | /// } | |
228 | /// ``` | |
c34b1796 AL |
229 | #[stable(feature = "rust1", since = "1.0.0")] |
230 | pub struct Stdin { | |
1b1a35ee | 231 | inner: &'static Mutex<BufReader<StdinRaw>>, |
c34b1796 AL |
232 | } |
233 | ||
6a06907d | 234 | /// A locked reference to the [`Stdin`] handle. |
c34b1796 | 235 | /// |
9cc50fc6 SL |
236 | /// This handle implements both the [`Read`] and [`BufRead`] traits, and |
237 | /// is constructed via the [`Stdin::lock`] method. | |
238 | /// | |
9fa01778 | 239 | /// ### Note: Windows Portability Consideration |
3dfed10e | 240 | /// |
9fa01778 XL |
241 | /// When operating in a console, the Windows implementation of this stream does not support |
242 | /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return | |
243 | /// an error. | |
3dfed10e XL |
244 | /// |
245 | /// # Examples | |
246 | /// | |
247 | /// ```no_run | |
248 | /// use std::io::{self, Read}; | |
249 | /// | |
250 | /// fn main() -> io::Result<()> { | |
251 | /// let mut buffer = String::new(); | |
252 | /// let stdin = io::stdin(); // We get `Stdin` here. | |
253 | /// { | |
6a06907d XL |
254 | /// let mut handle = stdin.lock(); // We get `StdinLock` here. |
255 | /// handle.read_to_string(&mut buffer)?; | |
3dfed10e XL |
256 | /// } // `StdinLock` is dropped here. |
257 | /// Ok(()) | |
258 | /// } | |
259 | /// ``` | |
c34b1796 AL |
260 | #[stable(feature = "rust1", since = "1.0.0")] |
261 | pub struct StdinLock<'a> { | |
3dfed10e | 262 | inner: MutexGuard<'a, BufReader<StdinRaw>>, |
c34b1796 AL |
263 | } |
264 | ||
c1a9b12d | 265 | /// Constructs a new handle to the standard input of the current process. |
c34b1796 | 266 | /// |
c1a9b12d SL |
267 | /// Each handle returned is a reference to a shared global buffer whose access |
268 | /// is synchronized via a mutex. If you need more explicit control over | |
e1599b0c | 269 | /// locking, see the [`Stdin::lock`] method. |
c1a9b12d | 270 | /// |
9fa01778 XL |
271 | /// ### Note: Windows Portability Consideration |
272 | /// When operating in a console, the Windows implementation of this stream does not support | |
273 | /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return | |
274 | /// an error. | |
275 | /// | |
c1a9b12d SL |
276 | /// # Examples |
277 | /// | |
278 | /// Using implicit synchronization: | |
279 | /// | |
0531ce1d | 280 | /// ```no_run |
c1a9b12d SL |
281 | /// use std::io::{self, Read}; |
282 | /// | |
0531ce1d XL |
283 | /// fn main() -> io::Result<()> { |
284 | /// let mut buffer = String::new(); | |
285 | /// io::stdin().read_to_string(&mut buffer)?; | |
286 | /// Ok(()) | |
287 | /// } | |
c1a9b12d SL |
288 | /// ``` |
289 | /// | |
290 | /// Using explicit synchronization: | |
291 | /// | |
0531ce1d | 292 | /// ```no_run |
c1a9b12d SL |
293 | /// use std::io::{self, Read}; |
294 | /// | |
0531ce1d XL |
295 | /// fn main() -> io::Result<()> { |
296 | /// let mut buffer = String::new(); | |
297 | /// let stdin = io::stdin(); | |
298 | /// let mut handle = stdin.lock(); | |
c34b1796 | 299 | /// |
0531ce1d XL |
300 | /// handle.read_to_string(&mut buffer)?; |
301 | /// Ok(()) | |
302 | /// } | |
c1a9b12d | 303 | /// ``` |
c34b1796 AL |
304 | #[stable(feature = "rust1", since = "1.0.0")] |
305 | pub fn stdin() -> Stdin { | |
1b1a35ee XL |
306 | static INSTANCE: SyncOnceCell<Mutex<BufReader<StdinRaw>>> = SyncOnceCell::new(); |
307 | Stdin { | |
308 | inner: INSTANCE.get_or_init(|| { | |
309 | Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw())) | |
310 | }), | |
c34b1796 AL |
311 | } |
312 | } | |
313 | ||
314 | impl Stdin { | |
9346a6ac | 315 | /// Locks this handle to the standard input stream, returning a readable |
c34b1796 AL |
316 | /// guard. |
317 | /// | |
318 | /// The lock is released when the returned lock goes out of scope. The | |
9cc50fc6 | 319 | /// returned guard also implements the [`Read`] and [`BufRead`] traits for |
c34b1796 | 320 | /// accessing the underlying data. |
9cc50fc6 | 321 | /// |
5bcae85e SL |
322 | /// # Examples |
323 | /// | |
0531ce1d | 324 | /// ```no_run |
5bcae85e SL |
325 | /// use std::io::{self, Read}; |
326 | /// | |
0531ce1d XL |
327 | /// fn main() -> io::Result<()> { |
328 | /// let mut buffer = String::new(); | |
329 | /// let stdin = io::stdin(); | |
330 | /// let mut handle = stdin.lock(); | |
5bcae85e | 331 | /// |
0531ce1d XL |
332 | /// handle.read_to_string(&mut buffer)?; |
333 | /// Ok(()) | |
334 | /// } | |
5bcae85e | 335 | /// ``` |
c34b1796 | 336 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 337 | pub fn lock(&self) -> StdinLock<'_> { |
c34b1796 AL |
338 | StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } |
339 | } | |
340 | ||
74b04a01 | 341 | /// Locks this handle and reads a line of input, appending it to the specified buffer. |
c34b1796 AL |
342 | /// |
343 | /// For detailed semantics of this method, see the documentation on | |
9cc50fc6 SL |
344 | /// [`BufRead::read_line`]. |
345 | /// | |
c1a9b12d SL |
346 | /// # Examples |
347 | /// | |
348 | /// ```no_run | |
349 | /// use std::io; | |
350 | /// | |
351 | /// let mut input = String::new(); | |
352 | /// match io::stdin().read_line(&mut input) { | |
353 | /// Ok(n) => { | |
354 | /// println!("{} bytes read", n); | |
355 | /// println!("{}", input); | |
356 | /// } | |
357 | /// Err(error) => println!("error: {}", error), | |
358 | /// } | |
359 | /// ``` | |
360 | /// | |
361 | /// You can run the example one of two ways: | |
362 | /// | |
0731742a | 363 | /// - Pipe some text to it, e.g., `printf foo | path/to/executable` |
c1a9b12d | 364 | /// - Give it text interactively by running the executable directly, |
9cc50fc6 | 365 | /// in which case it will wait for the Enter key to be pressed before |
c1a9b12d | 366 | /// continuing |
c34b1796 | 367 | #[stable(feature = "rust1", since = "1.0.0")] |
c1a9b12d | 368 | pub fn read_line(&self, buf: &mut String) -> io::Result<usize> { |
c34b1796 AL |
369 | self.lock().read_line(buf) |
370 | } | |
371 | } | |
372 | ||
8bb4bdeb | 373 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 | 374 | impl fmt::Debug for Stdin { |
532ac7d7 | 375 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
32a655c1 SL |
376 | f.pad("Stdin { .. }") |
377 | } | |
378 | } | |
379 | ||
c34b1796 AL |
380 | #[stable(feature = "rust1", since = "1.0.0")] |
381 | impl Read for Stdin { | |
382 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
383 | self.lock().read(buf) | |
384 | } | |
48663c56 XL |
385 | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
386 | self.lock().read_vectored(bufs) | |
387 | } | |
041b39d2 | 388 | #[inline] |
f9f354fc XL |
389 | fn is_read_vectored(&self) -> bool { |
390 | self.lock().is_read_vectored() | |
391 | } | |
392 | #[inline] | |
041b39d2 XL |
393 | unsafe fn initializer(&self) -> Initializer { |
394 | Initializer::nop() | |
395 | } | |
c34b1796 AL |
396 | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { |
397 | self.lock().read_to_end(buf) | |
398 | } | |
399 | fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { | |
400 | self.lock().read_to_string(buf) | |
401 | } | |
e9174d1e SL |
402 | fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { |
403 | self.lock().read_exact(buf) | |
404 | } | |
c34b1796 AL |
405 | } |
406 | ||
fc512014 XL |
407 | // only used by platform-dependent io::copy specializations, i.e. unused on some platforms |
408 | #[cfg(any(target_os = "linux", target_os = "android"))] | |
409 | impl StdinLock<'_> { | |
410 | pub(crate) fn as_mut_buf(&mut self) -> &mut BufReader<impl Read> { | |
411 | &mut self.inner | |
412 | } | |
413 | } | |
414 | ||
c34b1796 | 415 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 416 | impl Read for StdinLock<'_> { |
c34b1796 AL |
417 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
418 | self.inner.read(buf) | |
419 | } | |
48663c56 XL |
420 | |
421 | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { | |
422 | self.inner.read_vectored(bufs) | |
423 | } | |
424 | ||
f9f354fc XL |
425 | #[inline] |
426 | fn is_read_vectored(&self) -> bool { | |
427 | self.inner.is_read_vectored() | |
428 | } | |
429 | ||
041b39d2 XL |
430 | #[inline] |
431 | unsafe fn initializer(&self) -> Initializer { | |
432 | Initializer::nop() | |
c1a9b12d | 433 | } |
f035d41b XL |
434 | |
435 | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { | |
436 | self.inner.read_to_end(buf) | |
437 | } | |
438 | ||
439 | fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { | |
440 | self.inner.read_to_string(buf) | |
441 | } | |
442 | ||
443 | fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { | |
444 | self.inner.read_exact(buf) | |
445 | } | |
c34b1796 | 446 | } |
62682a34 | 447 | |
c34b1796 | 448 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 449 | impl BufRead for StdinLock<'_> { |
dfeec247 XL |
450 | fn fill_buf(&mut self) -> io::Result<&[u8]> { |
451 | self.inner.fill_buf() | |
452 | } | |
f035d41b | 453 | |
dfeec247 XL |
454 | fn consume(&mut self, n: usize) { |
455 | self.inner.consume(n) | |
456 | } | |
f035d41b XL |
457 | |
458 | fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> { | |
459 | self.inner.read_until(byte, buf) | |
460 | } | |
461 | ||
462 | fn read_line(&mut self, buf: &mut String) -> io::Result<usize> { | |
463 | self.inner.read_line(buf) | |
464 | } | |
c34b1796 AL |
465 | } |
466 | ||
8bb4bdeb | 467 | #[stable(feature = "std_debug", since = "1.16.0")] |
9fa01778 | 468 | impl fmt::Debug for StdinLock<'_> { |
532ac7d7 | 469 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
32a655c1 SL |
470 | f.pad("StdinLock { .. }") |
471 | } | |
472 | } | |
473 | ||
c34b1796 AL |
474 | /// A handle to the global standard output stream of the current process. |
475 | /// | |
476 | /// Each handle shares a global buffer of data to be written to the standard | |
477 | /// output stream. Access is also synchronized via a lock and explicit control | |
cc61c64b | 478 | /// over locking is available via the [`lock`] method. |
bd371182 | 479 | /// |
9cc50fc6 SL |
480 | /// Created by the [`io::stdout`] method. |
481 | /// | |
9fa01778 XL |
482 | /// ### Note: Windows Portability Consideration |
483 | /// When operating in a console, the Windows implementation of this stream does not support | |
484 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return | |
485 | /// an error. | |
486 | /// | |
3dfed10e XL |
487 | /// [`lock`]: Stdout::lock |
488 | /// [`io::stdout`]: stdout | |
c34b1796 AL |
489 | #[stable(feature = "rust1", since = "1.0.0")] |
490 | pub struct Stdout { | |
491 | // FIXME: this should be LineWriter or BufWriter depending on the state of | |
492 | // stdout (tty or not). Note that if this is not line buffered it | |
493 | // should also flush-on-panic or some form of flush-on-abort. | |
2a314972 | 494 | inner: Pin<&'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>, |
c34b1796 AL |
495 | } |
496 | ||
6a06907d | 497 | /// A locked reference to the [`Stdout`] handle. |
c34b1796 | 498 | /// |
9cc50fc6 | 499 | /// This handle implements the [`Write`] trait, and is constructed via |
6a06907d | 500 | /// the [`Stdout::lock`] method. See its documentation for more. |
9cc50fc6 | 501 | /// |
9fa01778 XL |
502 | /// ### Note: Windows Portability Consideration |
503 | /// When operating in a console, the Windows implementation of this stream does not support | |
504 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return | |
505 | /// an error. | |
c34b1796 AL |
506 | #[stable(feature = "rust1", since = "1.0.0")] |
507 | pub struct StdoutLock<'a> { | |
3dfed10e | 508 | inner: ReentrantMutexGuard<'a, RefCell<LineWriter<StdoutRaw>>>, |
c34b1796 AL |
509 | } |
510 | ||
c1a9b12d | 511 | /// Constructs a new handle to the standard output of the current process. |
c34b1796 AL |
512 | /// |
513 | /// Each handle returned is a reference to a shared global buffer whose access | |
c1a9b12d | 514 | /// is synchronized via a mutex. If you need more explicit control over |
e1599b0c | 515 | /// locking, see the [`Stdout::lock`] method. |
c1a9b12d | 516 | /// |
9fa01778 XL |
517 | /// ### Note: Windows Portability Consideration |
518 | /// When operating in a console, the Windows implementation of this stream does not support | |
519 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return | |
520 | /// an error. | |
521 | /// | |
c1a9b12d | 522 | /// # Examples |
c34b1796 | 523 | /// |
c1a9b12d SL |
524 | /// Using implicit synchronization: |
525 | /// | |
0531ce1d | 526 | /// ```no_run |
c1a9b12d SL |
527 | /// use std::io::{self, Write}; |
528 | /// | |
0531ce1d | 529 | /// fn main() -> io::Result<()> { |
532ac7d7 | 530 | /// io::stdout().write_all(b"hello world")?; |
c1a9b12d | 531 | /// |
0531ce1d XL |
532 | /// Ok(()) |
533 | /// } | |
c1a9b12d SL |
534 | /// ``` |
535 | /// | |
536 | /// Using explicit synchronization: | |
537 | /// | |
0531ce1d | 538 | /// ```no_run |
c1a9b12d SL |
539 | /// use std::io::{self, Write}; |
540 | /// | |
0531ce1d XL |
541 | /// fn main() -> io::Result<()> { |
542 | /// let stdout = io::stdout(); | |
543 | /// let mut handle = stdout.lock(); | |
c1a9b12d | 544 | /// |
532ac7d7 | 545 | /// handle.write_all(b"hello world")?; |
c1a9b12d | 546 | /// |
0531ce1d XL |
547 | /// Ok(()) |
548 | /// } | |
c1a9b12d | 549 | /// ``` |
c34b1796 AL |
550 | #[stable(feature = "rust1", since = "1.0.0")] |
551 | pub fn stdout() -> Stdout { | |
1b1a35ee XL |
552 | static INSTANCE: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = |
553 | SyncOnceCell::new(); | |
2a314972 XL |
554 | |
555 | fn cleanup() { | |
556 | if let Some(instance) = INSTANCE.get() { | |
557 | // Flush the data and disable buffering during shutdown | |
558 | // by replacing the line writer by one with zero | |
559 | // buffering capacity. | |
560 | // We use try_lock() instead of lock(), because someone | |
561 | // might have leaked a StdoutLock, which would | |
562 | // otherwise cause a deadlock here. | |
563 | if let Some(lock) = Pin::static_ref(instance).try_lock() { | |
564 | *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); | |
565 | } | |
566 | } | |
567 | } | |
568 | ||
1b1a35ee | 569 | Stdout { |
2a314972 XL |
570 | inner: Pin::static_ref(&INSTANCE).get_or_init_pin( |
571 | || unsafe { | |
572 | let _ = sys_common::at_exit(cleanup); | |
573 | ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) | |
574 | }, | |
575 | |mutex| unsafe { mutex.init() }, | |
576 | ), | |
c34b1796 AL |
577 | } |
578 | } | |
579 | ||
580 | impl Stdout { | |
9346a6ac | 581 | /// Locks this handle to the standard output stream, returning a writable |
c34b1796 AL |
582 | /// guard. |
583 | /// | |
584 | /// The lock is released when the returned lock goes out of scope. The | |
585 | /// returned guard also implements the `Write` trait for writing data. | |
5bcae85e SL |
586 | /// |
587 | /// # Examples | |
588 | /// | |
0531ce1d | 589 | /// ```no_run |
5bcae85e SL |
590 | /// use std::io::{self, Write}; |
591 | /// | |
0531ce1d XL |
592 | /// fn main() -> io::Result<()> { |
593 | /// let stdout = io::stdout(); | |
594 | /// let mut handle = stdout.lock(); | |
5bcae85e | 595 | /// |
532ac7d7 | 596 | /// handle.write_all(b"hello world")?; |
5bcae85e | 597 | /// |
0531ce1d XL |
598 | /// Ok(()) |
599 | /// } | |
5bcae85e | 600 | /// ``` |
c34b1796 | 601 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 602 | pub fn lock(&self) -> StdoutLock<'_> { |
ba9703b0 | 603 | StdoutLock { inner: self.inner.lock() } |
c34b1796 AL |
604 | } |
605 | } | |
606 | ||
8bb4bdeb | 607 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 | 608 | impl fmt::Debug for Stdout { |
532ac7d7 | 609 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
32a655c1 SL |
610 | f.pad("Stdout { .. }") |
611 | } | |
612 | } | |
613 | ||
c34b1796 AL |
614 | #[stable(feature = "rust1", since = "1.0.0")] |
615 | impl Write for Stdout { | |
1b1a35ee XL |
616 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
617 | (&*self).write(buf) | |
618 | } | |
619 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
620 | (&*self).write_vectored(bufs) | |
621 | } | |
622 | #[inline] | |
623 | fn is_write_vectored(&self) -> bool { | |
624 | io::Write::is_write_vectored(&&*self) | |
625 | } | |
626 | fn flush(&mut self) -> io::Result<()> { | |
627 | (&*self).flush() | |
628 | } | |
629 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { | |
630 | (&*self).write_all(buf) | |
631 | } | |
632 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
633 | (&*self).write_all_vectored(bufs) | |
634 | } | |
635 | fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { | |
636 | (&*self).write_fmt(args) | |
637 | } | |
638 | } | |
639 | ||
640 | #[stable(feature = "write_mt", since = "1.48.0")] | |
641 | impl Write for &Stdout { | |
c34b1796 AL |
642 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
643 | self.lock().write(buf) | |
644 | } | |
48663c56 XL |
645 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
646 | self.lock().write_vectored(bufs) | |
647 | } | |
f9f354fc XL |
648 | #[inline] |
649 | fn is_write_vectored(&self) -> bool { | |
650 | self.lock().is_write_vectored() | |
651 | } | |
c34b1796 AL |
652 | fn flush(&mut self) -> io::Result<()> { |
653 | self.lock().flush() | |
654 | } | |
655 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { | |
656 | self.lock().write_all(buf) | |
657 | } | |
f035d41b XL |
658 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { |
659 | self.lock().write_all_vectored(bufs) | |
660 | } | |
532ac7d7 | 661 | fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { |
9346a6ac AL |
662 | self.lock().write_fmt(args) |
663 | } | |
c34b1796 | 664 | } |
1b1a35ee | 665 | |
c34b1796 | 666 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 667 | impl Write for StdoutLock<'_> { |
c34b1796 | 668 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
54a0048b | 669 | self.inner.borrow_mut().write(buf) |
9346a6ac | 670 | } |
48663c56 XL |
671 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
672 | self.inner.borrow_mut().write_vectored(bufs) | |
673 | } | |
f9f354fc XL |
674 | #[inline] |
675 | fn is_write_vectored(&self) -> bool { | |
676 | self.inner.borrow_mut().is_write_vectored() | |
677 | } | |
9346a6ac AL |
678 | fn flush(&mut self) -> io::Result<()> { |
679 | self.inner.borrow_mut().flush() | |
c34b1796 | 680 | } |
f035d41b XL |
681 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
682 | self.inner.borrow_mut().write_all(buf) | |
683 | } | |
684 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
685 | self.inner.borrow_mut().write_all_vectored(bufs) | |
686 | } | |
c34b1796 AL |
687 | } |
688 | ||
8bb4bdeb | 689 | #[stable(feature = "std_debug", since = "1.16.0")] |
9fa01778 | 690 | impl fmt::Debug for StdoutLock<'_> { |
532ac7d7 | 691 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
32a655c1 SL |
692 | f.pad("StdoutLock { .. }") |
693 | } | |
694 | } | |
695 | ||
c34b1796 AL |
696 | /// A handle to the standard error stream of a process. |
697 | /// | |
9cc50fc6 SL |
698 | /// For more information, see the [`io::stderr`] method. |
699 | /// | |
3dfed10e | 700 | /// [`io::stderr`]: stderr |
9fa01778 XL |
701 | /// |
702 | /// ### Note: Windows Portability Consideration | |
703 | /// When operating in a console, the Windows implementation of this stream does not support | |
704 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return | |
705 | /// an error. | |
c34b1796 AL |
706 | #[stable(feature = "rust1", since = "1.0.0")] |
707 | pub struct Stderr { | |
2a314972 | 708 | inner: Pin<&'static ReentrantMutex<RefCell<StderrRaw>>>, |
c34b1796 AL |
709 | } |
710 | ||
6a06907d | 711 | /// A locked reference to the [`Stderr`] handle. |
c34b1796 | 712 | /// |
6a06907d XL |
713 | /// This handle implements the [`Write`] trait and is constructed via |
714 | /// the [`Stderr::lock`] method. See its documentation for more. | |
9cc50fc6 | 715 | /// |
9fa01778 XL |
716 | /// ### Note: Windows Portability Consideration |
717 | /// When operating in a console, the Windows implementation of this stream does not support | |
718 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return | |
719 | /// an error. | |
c34b1796 AL |
720 | #[stable(feature = "rust1", since = "1.0.0")] |
721 | pub struct StderrLock<'a> { | |
3dfed10e | 722 | inner: ReentrantMutexGuard<'a, RefCell<StderrRaw>>, |
c34b1796 AL |
723 | } |
724 | ||
c1a9b12d SL |
725 | /// Constructs a new handle to the standard error of the current process. |
726 | /// | |
727 | /// This handle is not buffered. | |
728 | /// | |
9fa01778 XL |
729 | /// ### Note: Windows Portability Consideration |
730 | /// When operating in a console, the Windows implementation of this stream does not support | |
731 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return | |
732 | /// an error. | |
733 | /// | |
c1a9b12d SL |
734 | /// # Examples |
735 | /// | |
736 | /// Using implicit synchronization: | |
737 | /// | |
0531ce1d | 738 | /// ```no_run |
c1a9b12d SL |
739 | /// use std::io::{self, Write}; |
740 | /// | |
0531ce1d | 741 | /// fn main() -> io::Result<()> { |
532ac7d7 | 742 | /// io::stderr().write_all(b"hello world")?; |
c1a9b12d | 743 | /// |
0531ce1d XL |
744 | /// Ok(()) |
745 | /// } | |
c1a9b12d SL |
746 | /// ``` |
747 | /// | |
748 | /// Using explicit synchronization: | |
749 | /// | |
0531ce1d | 750 | /// ```no_run |
c1a9b12d SL |
751 | /// use std::io::{self, Write}; |
752 | /// | |
0531ce1d XL |
753 | /// fn main() -> io::Result<()> { |
754 | /// let stderr = io::stderr(); | |
755 | /// let mut handle = stderr.lock(); | |
c34b1796 | 756 | /// |
532ac7d7 | 757 | /// handle.write_all(b"hello world")?; |
c34b1796 | 758 | /// |
0531ce1d XL |
759 | /// Ok(()) |
760 | /// } | |
c1a9b12d | 761 | /// ``` |
c34b1796 AL |
762 | #[stable(feature = "rust1", since = "1.0.0")] |
763 | pub fn stderr() -> Stderr { | |
2a314972 XL |
764 | // Note that unlike `stdout()` we don't use `at_exit` here to register a |
765 | // destructor. Stderr is not buffered , so there's no need to run a | |
766 | // destructor for flushing the buffer | |
1b1a35ee | 767 | static INSTANCE: SyncOnceCell<ReentrantMutex<RefCell<StderrRaw>>> = SyncOnceCell::new(); |
ba9703b0 | 768 | |
1b1a35ee | 769 | Stderr { |
2a314972 XL |
770 | inner: Pin::static_ref(&INSTANCE).get_or_init_pin( |
771 | || unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) }, | |
772 | |mutex| unsafe { mutex.init() }, | |
773 | ), | |
1b1a35ee | 774 | } |
c34b1796 AL |
775 | } |
776 | ||
777 | impl Stderr { | |
9346a6ac | 778 | /// Locks this handle to the standard error stream, returning a writable |
c34b1796 AL |
779 | /// guard. |
780 | /// | |
781 | /// The lock is released when the returned lock goes out of scope. The | |
3dfed10e | 782 | /// returned guard also implements the [`Write`] trait for writing data. |
5bcae85e SL |
783 | /// |
784 | /// # Examples | |
785 | /// | |
786 | /// ``` | |
787 | /// use std::io::{self, Write}; | |
788 | /// | |
789 | /// fn foo() -> io::Result<()> { | |
790 | /// let stderr = io::stderr(); | |
791 | /// let mut handle = stderr.lock(); | |
792 | /// | |
532ac7d7 | 793 | /// handle.write_all(b"hello world")?; |
5bcae85e SL |
794 | /// |
795 | /// Ok(()) | |
796 | /// } | |
797 | /// ``` | |
c34b1796 | 798 | #[stable(feature = "rust1", since = "1.0.0")] |
532ac7d7 | 799 | pub fn lock(&self) -> StderrLock<'_> { |
ba9703b0 | 800 | StderrLock { inner: self.inner.lock() } |
c34b1796 AL |
801 | } |
802 | } | |
803 | ||
8bb4bdeb | 804 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 | 805 | impl fmt::Debug for Stderr { |
532ac7d7 | 806 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
32a655c1 SL |
807 | f.pad("Stderr { .. }") |
808 | } | |
809 | } | |
810 | ||
c34b1796 AL |
811 | #[stable(feature = "rust1", since = "1.0.0")] |
812 | impl Write for Stderr { | |
1b1a35ee XL |
813 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
814 | (&*self).write(buf) | |
815 | } | |
816 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { | |
817 | (&*self).write_vectored(bufs) | |
818 | } | |
819 | #[inline] | |
820 | fn is_write_vectored(&self) -> bool { | |
821 | io::Write::is_write_vectored(&&*self) | |
822 | } | |
823 | fn flush(&mut self) -> io::Result<()> { | |
824 | (&*self).flush() | |
825 | } | |
826 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { | |
827 | (&*self).write_all(buf) | |
828 | } | |
829 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
830 | (&*self).write_all_vectored(bufs) | |
831 | } | |
832 | fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { | |
833 | (&*self).write_fmt(args) | |
834 | } | |
835 | } | |
836 | ||
837 | #[stable(feature = "write_mt", since = "1.48.0")] | |
838 | impl Write for &Stderr { | |
c34b1796 AL |
839 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
840 | self.lock().write(buf) | |
841 | } | |
48663c56 XL |
842 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
843 | self.lock().write_vectored(bufs) | |
844 | } | |
f9f354fc XL |
845 | #[inline] |
846 | fn is_write_vectored(&self) -> bool { | |
847 | self.lock().is_write_vectored() | |
848 | } | |
c34b1796 AL |
849 | fn flush(&mut self) -> io::Result<()> { |
850 | self.lock().flush() | |
851 | } | |
852 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { | |
853 | self.lock().write_all(buf) | |
854 | } | |
f035d41b XL |
855 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { |
856 | self.lock().write_all_vectored(bufs) | |
857 | } | |
532ac7d7 | 858 | fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { |
9346a6ac AL |
859 | self.lock().write_fmt(args) |
860 | } | |
c34b1796 | 861 | } |
1b1a35ee | 862 | |
c34b1796 | 863 | #[stable(feature = "rust1", since = "1.0.0")] |
9fa01778 | 864 | impl Write for StderrLock<'_> { |
c34b1796 | 865 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
54a0048b | 866 | self.inner.borrow_mut().write(buf) |
9346a6ac | 867 | } |
48663c56 XL |
868 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
869 | self.inner.borrow_mut().write_vectored(bufs) | |
870 | } | |
f9f354fc XL |
871 | #[inline] |
872 | fn is_write_vectored(&self) -> bool { | |
873 | self.inner.borrow_mut().is_write_vectored() | |
874 | } | |
9346a6ac AL |
875 | fn flush(&mut self) -> io::Result<()> { |
876 | self.inner.borrow_mut().flush() | |
c34b1796 | 877 | } |
f035d41b XL |
878 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
879 | self.inner.borrow_mut().write_all(buf) | |
880 | } | |
881 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { | |
882 | self.inner.borrow_mut().write_all_vectored(bufs) | |
883 | } | |
c34b1796 AL |
884 | } |
885 | ||
8bb4bdeb | 886 | #[stable(feature = "std_debug", since = "1.16.0")] |
9fa01778 | 887 | impl fmt::Debug for StderrLock<'_> { |
532ac7d7 | 888 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
32a655c1 SL |
889 | f.pad("StderrLock { .. }") |
890 | } | |
891 | } | |
892 | ||
fc512014 | 893 | /// Sets the thread-local output capture buffer and returns the old one. |
dfeec247 | 894 | #[unstable( |
fc512014 XL |
895 | feature = "internal_output_capture", |
896 | reason = "this function is meant for use in the test crate \ | |
897 | and may disappear in the future", | |
dfeec247 XL |
898 | issue = "none" |
899 | )] | |
c34b1796 | 900 | #[doc(hidden)] |
fc512014 XL |
901 | pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> { |
902 | if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) { | |
903 | // OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false. | |
1b1a35ee XL |
904 | return None; |
905 | } | |
fc512014 XL |
906 | OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed); |
907 | OUTPUT_CAPTURE.with(move |slot| slot.replace(sink)) | |
29967ef6 XL |
908 | } |
909 | ||
fc512014 | 910 | /// Write `args` to the capture buffer if enabled and possible, or `global_s` |
7cac9316 XL |
911 | /// otherwise. `label` identifies the stream in a panic message. |
912 | /// | |
913 | /// This function is used to print error messages, so it takes extra | |
e74abb32 | 914 | /// care to avoid causing a panic when `local_s` is unusable. |
0531ce1d XL |
915 | /// For instance, if the TLS key for the local stream is |
916 | /// already destroyed, or if the local stream is locked by another | |
7cac9316 XL |
917 | /// thread, it will just fall back to the global stream. |
918 | /// | |
919 | /// However, if the actual I/O causes an error, this function does panic. | |
fc512014 XL |
920 | fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str) |
921 | where | |
0531ce1d XL |
922 | T: Write, |
923 | { | |
fc512014 XL |
924 | if OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) |
925 | && OUTPUT_CAPTURE.try_with(|s| { | |
926 | // Note that we completely remove a local sink to write to in case | |
927 | // our printing recursively panics/prints, so the recursive | |
928 | // panic/print goes to the global sink instead of our local sink. | |
929 | s.take().map(|w| { | |
930 | let _ = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args); | |
931 | s.set(Some(w)); | |
932 | }) | |
933 | }) == Ok(Some(())) | |
934 | { | |
935 | // Succesfully wrote to capture buffer. | |
936 | return; | |
937 | } | |
938 | ||
939 | if let Err(e) = global_s().write_fmt(args) { | |
7cac9316 | 940 | panic!("failed printing to {}: {}", label, e); |
c34b1796 AL |
941 | } |
942 | } | |
943 | ||
dfeec247 XL |
944 | #[unstable( |
945 | feature = "print_internals", | |
946 | reason = "implementation detail which may disappear or be replaced at any time", | |
947 | issue = "none" | |
948 | )] | |
7cac9316 | 949 | #[doc(hidden)] |
532ac7d7 XL |
950 | #[cfg(not(test))] |
951 | pub fn _print(args: fmt::Arguments<'_>) { | |
fc512014 | 952 | print_to(args, stdout, "stdout"); |
7cac9316 XL |
953 | } |
954 | ||
dfeec247 XL |
955 | #[unstable( |
956 | feature = "print_internals", | |
957 | reason = "implementation detail which may disappear or be replaced at any time", | |
958 | issue = "none" | |
959 | )] | |
7cac9316 | 960 | #[doc(hidden)] |
532ac7d7 XL |
961 | #[cfg(not(test))] |
962 | pub fn _eprint(args: fmt::Arguments<'_>) { | |
fc512014 | 963 | print_to(args, stderr, "stderr"); |
7cac9316 XL |
964 | } |
965 | ||
532ac7d7 XL |
966 | #[cfg(test)] |
967 | pub use realstd::io::{_eprint, _print}; |