1 | #![cfg_attr (test, allow(unused))] |
2 | |
3 | #[cfg (test)] |
4 | mod tests; |
5 | |
6 | use crate::io::prelude::*; |
7 | |
8 | use crate::cell::{Cell, RefCell}; |
9 | use crate::fmt; |
10 | use crate::fs::File; |
11 | use crate::io::{ |
12 | self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, SpecReadByte, |
13 | }; |
14 | use crate::panic::{RefUnwindSafe, UnwindSafe}; |
15 | use crate::sync::atomic::{AtomicBool, Ordering}; |
16 | use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantLock, ReentrantLockGuard}; |
17 | use crate::sys::stdio; |
18 | use crate::thread::AccessError; |
19 | |
20 | type LocalStream = Arc<Mutex<Vec<u8>>>; |
21 | |
22 | thread_local! { |
23 | /// Used by the test crate to capture the output of the print macros and panics. |
24 | static OUTPUT_CAPTURE: Cell<Option<LocalStream>> = { |
25 | Cell::new(None) |
26 | } |
27 | } |
28 | |
29 | /// Flag to indicate OUTPUT_CAPTURE is used. |
30 | /// |
31 | /// If it is None and was never set on any thread, this flag is set to false, |
32 | /// and OUTPUT_CAPTURE can be safely ignored on all threads, saving some time |
33 | /// and memory registering an unused thread local. |
34 | /// |
35 | /// Note about memory ordering: This contains information about whether a |
36 | /// thread local variable might be in use. Although this is a global flag, the |
37 | /// memory ordering between threads does not matter: we only want this flag to |
38 | /// have a consistent order between set_output_capture and print_to *within |
39 | /// the same thread*. Within the same thread, things always have a perfectly |
40 | /// consistent order. So Ordering::Relaxed is fine. |
41 | static OUTPUT_CAPTURE_USED: AtomicBool = AtomicBool::new(false); |
42 | |
43 | /// A handle to a raw instance of the standard input stream of this process. |
44 | /// |
45 | /// This handle is not synchronized or buffered in any fashion. Constructed via |
46 | /// the `std::io::stdio::stdin_raw` function. |
47 | struct StdinRaw(stdio::Stdin); |
48 | |
49 | /// A handle to a raw instance of the standard output stream of this process. |
50 | /// |
51 | /// This handle is not synchronized or buffered in any fashion. Constructed via |
52 | /// the `std::io::stdio::stdout_raw` function. |
53 | struct StdoutRaw(stdio::Stdout); |
54 | |
55 | /// A handle to a raw instance of the standard output stream of this process. |
56 | /// |
57 | /// This handle is not synchronized or buffered in any fashion. Constructed via |
58 | /// the `std::io::stdio::stderr_raw` function. |
59 | struct StderrRaw(stdio::Stderr); |
60 | |
61 | /// Constructs a new raw handle to the standard input of this process. |
62 | /// |
63 | /// The returned handle does not interact with any other handles created nor |
64 | /// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin` |
65 | /// handles is **not** available to raw handles returned from this function. |
66 | /// |
67 | /// The returned handle has no external synchronization or buffering. |
68 | #[unstable (feature = "libstd_sys_internals" , issue = "none" )] |
69 | const fn stdin_raw() -> StdinRaw { |
70 | StdinRaw(stdio::Stdin::new()) |
71 | } |
72 | |
73 | /// Constructs a new raw handle to the standard output stream of this process. |
74 | /// |
75 | /// The returned handle does not interact with any other handles created nor |
76 | /// handles returned by `std::io::stdout`. Note that data is buffered by the |
77 | /// `std::io::stdout` handles so writes which happen via this raw handle may |
78 | /// appear before previous writes. |
79 | /// |
80 | /// The returned handle has no external synchronization or buffering layered on |
81 | /// top. |
82 | #[unstable (feature = "libstd_sys_internals" , issue = "none" )] |
83 | const fn stdout_raw() -> StdoutRaw { |
84 | StdoutRaw(stdio::Stdout::new()) |
85 | } |
86 | |
87 | /// Constructs a new raw handle to the standard error stream of this process. |
88 | /// |
89 | /// The returned handle does not interact with any other handles created nor |
90 | /// handles returned by `std::io::stderr`. |
91 | /// |
92 | /// The returned handle has no external synchronization or buffering layered on |
93 | /// top. |
94 | #[unstable (feature = "libstd_sys_internals" , issue = "none" )] |
95 | const fn stderr_raw() -> StderrRaw { |
96 | StderrRaw(stdio::Stderr::new()) |
97 | } |
98 | |
99 | impl Read for StdinRaw { |
100 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
101 | handle_ebadf(self.0.read(buf), 0) |
102 | } |
103 | |
104 | fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { |
105 | handle_ebadf(self.0.read_buf(buf), ()) |
106 | } |
107 | |
108 | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
109 | handle_ebadf(self.0.read_vectored(bufs), 0) |
110 | } |
111 | |
112 | #[inline ] |
113 | fn is_read_vectored(&self) -> bool { |
114 | self.0.is_read_vectored() |
115 | } |
116 | |
117 | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { |
118 | handle_ebadf(self.0.read_to_end(buf), 0) |
119 | } |
120 | |
121 | fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { |
122 | handle_ebadf(self.0.read_to_string(buf), 0) |
123 | } |
124 | } |
125 | |
126 | impl Write for StdoutRaw { |
127 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
128 | handle_ebadf(self.0.write(buf), buf.len()) |
129 | } |
130 | |
131 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
132 | let total = || bufs.iter().map(|b| b.len()).sum(); |
133 | handle_ebadf_lazy(self.0.write_vectored(bufs), total) |
134 | } |
135 | |
136 | #[inline ] |
137 | fn is_write_vectored(&self) -> bool { |
138 | self.0.is_write_vectored() |
139 | } |
140 | |
141 | fn flush(&mut self) -> io::Result<()> { |
142 | handle_ebadf(self.0.flush(), ()) |
143 | } |
144 | |
145 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
146 | handle_ebadf(self.0.write_all(buf), ()) |
147 | } |
148 | |
149 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { |
150 | handle_ebadf(self.0.write_all_vectored(bufs), ()) |
151 | } |
152 | |
153 | fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { |
154 | handle_ebadf(self.0.write_fmt(fmt), ()) |
155 | } |
156 | } |
157 | |
158 | impl Write for StderrRaw { |
159 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
160 | handle_ebadf(self.0.write(buf), buf.len()) |
161 | } |
162 | |
163 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
164 | let total = || bufs.iter().map(|b| b.len()).sum(); |
165 | handle_ebadf_lazy(self.0.write_vectored(bufs), total) |
166 | } |
167 | |
168 | #[inline ] |
169 | fn is_write_vectored(&self) -> bool { |
170 | self.0.is_write_vectored() |
171 | } |
172 | |
173 | fn flush(&mut self) -> io::Result<()> { |
174 | handle_ebadf(self.0.flush(), ()) |
175 | } |
176 | |
177 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
178 | handle_ebadf(self.0.write_all(buf), ()) |
179 | } |
180 | |
181 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { |
182 | handle_ebadf(self.0.write_all_vectored(bufs), ()) |
183 | } |
184 | |
185 | fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { |
186 | handle_ebadf(self.0.write_fmt(fmt), ()) |
187 | } |
188 | } |
189 | |
190 | fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> { |
191 | match r { |
192 | Err(ref e: &Error) if stdio::is_ebadf(err:e) => Ok(default), |
193 | r: Result => r, |
194 | } |
195 | } |
196 | |
197 | fn handle_ebadf_lazy<T>(r: io::Result<T>, default: impl FnOnce() -> T) -> io::Result<T> { |
198 | match r { |
199 | Err(ref e: &Error) if stdio::is_ebadf(err:e) => Ok(default()), |
200 | r: Result => r, |
201 | } |
202 | } |
203 | |
204 | /// A handle to the standard input stream of a process. |
205 | /// |
206 | /// Each handle is a shared reference to a global buffer of input data to this |
207 | /// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods |
208 | /// (e.g., `.lines()`). Reads to this handle are otherwise locked with respect |
209 | /// to other reads. |
210 | /// |
211 | /// This handle implements the `Read` trait, but beware that concurrent reads |
212 | /// of `Stdin` must be executed with care. |
213 | /// |
214 | /// Created by the [`io::stdin`] method. |
215 | /// |
216 | /// [`io::stdin`]: stdin |
217 | /// |
218 | /// ### Note: Windows Portability Considerations |
219 | /// |
220 | /// When operating in a console, the Windows implementation of this stream does not support |
221 | /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return |
222 | /// an error. |
223 | /// |
224 | /// In a process with a detached console, such as one using |
225 | /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, |
226 | /// the contained handle will be null. In such cases, the standard library's `Read` and |
227 | /// `Write` will do nothing and silently succeed. All other I/O operations, via the |
228 | /// standard library or via raw Windows API calls, will fail. |
229 | /// |
230 | /// # Examples |
231 | /// |
232 | /// ```no_run |
233 | /// use std::io; |
234 | /// |
235 | /// fn main() -> io::Result<()> { |
236 | /// let mut buffer = String::new(); |
237 | /// let stdin = io::stdin(); // We get `Stdin` here. |
238 | /// stdin.read_line(&mut buffer)?; |
239 | /// Ok(()) |
240 | /// } |
241 | /// ``` |
242 | #[stable (feature = "rust1" , since = "1.0.0" )] |
243 | pub struct Stdin { |
244 | inner: &'static Mutex<BufReader<StdinRaw>>, |
245 | } |
246 | |
247 | /// A locked reference to the [`Stdin`] handle. |
248 | /// |
249 | /// This handle implements both the [`Read`] and [`BufRead`] traits, and |
250 | /// is constructed via the [`Stdin::lock`] method. |
251 | /// |
252 | /// ### Note: Windows Portability Considerations |
253 | /// |
254 | /// When operating in a console, the Windows implementation of this stream does not support |
255 | /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return |
256 | /// an error. |
257 | /// |
258 | /// In a process with a detached console, such as one using |
259 | /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, |
260 | /// the contained handle will be null. In such cases, the standard library's `Read` and |
261 | /// `Write` will do nothing and silently succeed. All other I/O operations, via the |
262 | /// standard library or via raw Windows API calls, will fail. |
263 | /// |
264 | /// # Examples |
265 | /// |
266 | /// ```no_run |
267 | /// use std::io::{self, BufRead}; |
268 | /// |
269 | /// fn main() -> io::Result<()> { |
270 | /// let mut buffer = String::new(); |
271 | /// let stdin = io::stdin(); // We get `Stdin` here. |
272 | /// { |
273 | /// let mut handle = stdin.lock(); // We get `StdinLock` here. |
274 | /// handle.read_line(&mut buffer)?; |
275 | /// } // `StdinLock` is dropped here. |
276 | /// Ok(()) |
277 | /// } |
278 | /// ``` |
279 | #[must_use = "if unused stdin will immediately unlock" ] |
280 | #[stable (feature = "rust1" , since = "1.0.0" )] |
281 | pub struct StdinLock<'a> { |
282 | inner: MutexGuard<'a, BufReader<StdinRaw>>, |
283 | } |
284 | |
285 | /// Constructs a new handle to the standard input of the current process. |
286 | /// |
287 | /// Each handle returned is a reference to a shared global buffer whose access |
288 | /// is synchronized via a mutex. If you need more explicit control over |
289 | /// locking, see the [`Stdin::lock`] method. |
290 | /// |
291 | /// ### Note: Windows Portability Considerations |
292 | /// |
293 | /// When operating in a console, the Windows implementation of this stream does not support |
294 | /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return |
295 | /// an error. |
296 | /// |
297 | /// In a process with a detached console, such as one using |
298 | /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, |
299 | /// the contained handle will be null. In such cases, the standard library's `Read` and |
300 | /// `Write` will do nothing and silently succeed. All other I/O operations, via the |
301 | /// standard library or via raw Windows API calls, will fail. |
302 | /// |
303 | /// # Examples |
304 | /// |
305 | /// Using implicit synchronization: |
306 | /// |
307 | /// ```no_run |
308 | /// use std::io; |
309 | /// |
310 | /// fn main() -> io::Result<()> { |
311 | /// let mut buffer = String::new(); |
312 | /// io::stdin().read_line(&mut buffer)?; |
313 | /// Ok(()) |
314 | /// } |
315 | /// ``` |
316 | /// |
317 | /// Using explicit synchronization: |
318 | /// |
319 | /// ```no_run |
320 | /// use std::io::{self, BufRead}; |
321 | /// |
322 | /// fn main() -> io::Result<()> { |
323 | /// let mut buffer = String::new(); |
324 | /// let stdin = io::stdin(); |
325 | /// let mut handle = stdin.lock(); |
326 | /// |
327 | /// handle.read_line(&mut buffer)?; |
328 | /// Ok(()) |
329 | /// } |
330 | /// ``` |
331 | #[must_use ] |
332 | #[stable (feature = "rust1" , since = "1.0.0" )] |
333 | pub fn stdin() -> Stdin { |
334 | static INSTANCE: OnceLock<Mutex<BufReader<StdinRaw>>> = OnceLock::new(); |
335 | Stdin { |
336 | inner: INSTANCE.get_or_init(|| { |
337 | Mutex::new(BufReader::with_capacity(capacity:stdio::STDIN_BUF_SIZE, inner:stdin_raw())) |
338 | }), |
339 | } |
340 | } |
341 | |
342 | impl Stdin { |
343 | /// Locks this handle to the standard input stream, returning a readable |
344 | /// guard. |
345 | /// |
346 | /// The lock is released when the returned lock goes out of scope. The |
347 | /// returned guard also implements the [`Read`] and [`BufRead`] traits for |
348 | /// accessing the underlying data. |
349 | /// |
350 | /// # Examples |
351 | /// |
352 | /// ```no_run |
353 | /// use std::io::{self, BufRead}; |
354 | /// |
355 | /// fn main() -> io::Result<()> { |
356 | /// let mut buffer = String::new(); |
357 | /// let stdin = io::stdin(); |
358 | /// let mut handle = stdin.lock(); |
359 | /// |
360 | /// handle.read_line(&mut buffer)?; |
361 | /// Ok(()) |
362 | /// } |
363 | /// ``` |
364 | #[stable (feature = "rust1" , since = "1.0.0" )] |
365 | pub fn lock(&self) -> StdinLock<'static> { |
366 | // Locks this handle with 'static lifetime. This depends on the |
367 | // implementation detail that the underlying `Mutex` is static. |
368 | StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } |
369 | } |
370 | |
371 | /// Locks this handle and reads a line of input, appending it to the specified buffer. |
372 | /// |
373 | /// For detailed semantics of this method, see the documentation on |
374 | /// [`BufRead::read_line`]. |
375 | /// |
376 | /// # Examples |
377 | /// |
378 | /// ```no_run |
379 | /// use std::io; |
380 | /// |
381 | /// let mut input = String::new(); |
382 | /// match io::stdin().read_line(&mut input) { |
383 | /// Ok(n) => { |
384 | /// println!("{n} bytes read" ); |
385 | /// println!("{input}" ); |
386 | /// } |
387 | /// Err(error) => println!("error: {error}" ), |
388 | /// } |
389 | /// ``` |
390 | /// |
391 | /// You can run the example one of two ways: |
392 | /// |
393 | /// - Pipe some text to it, e.g., `printf foo | path/to/executable` |
394 | /// - Give it text interactively by running the executable directly, |
395 | /// in which case it will wait for the Enter key to be pressed before |
396 | /// continuing |
397 | #[stable (feature = "rust1" , since = "1.0.0" )] |
398 | pub fn read_line(&self, buf: &mut String) -> io::Result<usize> { |
399 | self.lock().read_line(buf) |
400 | } |
401 | |
402 | /// Consumes this handle and returns an iterator over input lines. |
403 | /// |
404 | /// For detailed semantics of this method, see the documentation on |
405 | /// [`BufRead::lines`]. |
406 | /// |
407 | /// # Examples |
408 | /// |
409 | /// ```no_run |
410 | /// use std::io; |
411 | /// |
412 | /// let lines = io::stdin().lines(); |
413 | /// for line in lines { |
414 | /// println!("got a line: {}" , line.unwrap()); |
415 | /// } |
416 | /// ``` |
417 | #[must_use = "`self` will be dropped if the result is not used" ] |
418 | #[stable (feature = "stdin_forwarders" , since = "1.62.0" )] |
419 | pub fn lines(self) -> Lines<StdinLock<'static>> { |
420 | self.lock().lines() |
421 | } |
422 | } |
423 | |
424 | #[stable (feature = "std_debug" , since = "1.16.0" )] |
425 | impl fmt::Debug for Stdin { |
426 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
427 | f.debug_struct(name:"Stdin" ).finish_non_exhaustive() |
428 | } |
429 | } |
430 | |
431 | #[stable (feature = "rust1" , since = "1.0.0" )] |
432 | impl Read for Stdin { |
433 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
434 | self.lock().read(buf) |
435 | } |
436 | fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { |
437 | self.lock().read_buf(buf) |
438 | } |
439 | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
440 | self.lock().read_vectored(bufs) |
441 | } |
442 | #[inline ] |
443 | fn is_read_vectored(&self) -> bool { |
444 | self.lock().is_read_vectored() |
445 | } |
446 | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { |
447 | self.lock().read_to_end(buf) |
448 | } |
449 | fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { |
450 | self.lock().read_to_string(buf) |
451 | } |
452 | fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { |
453 | self.lock().read_exact(buf) |
454 | } |
455 | fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { |
456 | self.lock().read_buf_exact(cursor) |
457 | } |
458 | } |
459 | |
460 | #[stable (feature = "read_shared_stdin" , since = "1.78.0" )] |
461 | impl Read for &Stdin { |
462 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
463 | self.lock().read(buf) |
464 | } |
465 | fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { |
466 | self.lock().read_buf(buf) |
467 | } |
468 | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
469 | self.lock().read_vectored(bufs) |
470 | } |
471 | #[inline ] |
472 | fn is_read_vectored(&self) -> bool { |
473 | self.lock().is_read_vectored() |
474 | } |
475 | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { |
476 | self.lock().read_to_end(buf) |
477 | } |
478 | fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { |
479 | self.lock().read_to_string(buf) |
480 | } |
481 | fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { |
482 | self.lock().read_exact(buf) |
483 | } |
484 | fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { |
485 | self.lock().read_buf_exact(cursor) |
486 | } |
487 | } |
488 | |
489 | // only used by platform-dependent io::copy specializations, i.e. unused on some platforms |
490 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
491 | impl StdinLock<'_> { |
492 | pub(crate) fn as_mut_buf(&mut self) -> &mut BufReader<impl Read> { |
493 | &mut self.inner |
494 | } |
495 | } |
496 | |
497 | #[stable (feature = "rust1" , since = "1.0.0" )] |
498 | impl Read for StdinLock<'_> { |
499 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
500 | self.inner.read(buf) |
501 | } |
502 | |
503 | fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { |
504 | self.inner.read_buf(buf) |
505 | } |
506 | |
507 | fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
508 | self.inner.read_vectored(bufs) |
509 | } |
510 | |
511 | #[inline ] |
512 | fn is_read_vectored(&self) -> bool { |
513 | self.inner.is_read_vectored() |
514 | } |
515 | |
516 | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { |
517 | self.inner.read_to_end(buf) |
518 | } |
519 | |
520 | fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { |
521 | self.inner.read_to_string(buf) |
522 | } |
523 | |
524 | fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { |
525 | self.inner.read_exact(buf) |
526 | } |
527 | |
528 | fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { |
529 | self.inner.read_buf_exact(cursor) |
530 | } |
531 | } |
532 | |
533 | impl SpecReadByte for StdinLock<'_> { |
534 | #[inline ] |
535 | fn spec_read_byte(&mut self) -> Option<io::Result<u8>> { |
536 | BufReader::spec_read_byte(&mut *self.inner) |
537 | } |
538 | } |
539 | |
540 | #[stable (feature = "rust1" , since = "1.0.0" )] |
541 | impl BufRead for StdinLock<'_> { |
542 | fn fill_buf(&mut self) -> io::Result<&[u8]> { |
543 | self.inner.fill_buf() |
544 | } |
545 | |
546 | fn consume(&mut self, n: usize) { |
547 | self.inner.consume(amt:n) |
548 | } |
549 | |
550 | fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> { |
551 | self.inner.read_until(byte, buf) |
552 | } |
553 | |
554 | fn read_line(&mut self, buf: &mut String) -> io::Result<usize> { |
555 | self.inner.read_line(buf) |
556 | } |
557 | } |
558 | |
559 | #[stable (feature = "std_debug" , since = "1.16.0" )] |
560 | impl fmt::Debug for StdinLock<'_> { |
561 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
562 | f.debug_struct(name:"StdinLock" ).finish_non_exhaustive() |
563 | } |
564 | } |
565 | |
566 | /// A handle to the global standard output stream of the current process. |
567 | /// |
568 | /// Each handle shares a global buffer of data to be written to the standard |
569 | /// output stream. Access is also synchronized via a lock and explicit control |
570 | /// over locking is available via the [`lock`] method. |
571 | /// |
572 | /// Created by the [`io::stdout`] method. |
573 | /// |
574 | /// ### Note: Windows Portability Considerations |
575 | /// |
576 | /// When operating in a console, the Windows implementation of this stream does not support |
577 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return |
578 | /// an error. |
579 | /// |
580 | /// In a process with a detached console, such as one using |
581 | /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, |
582 | /// the contained handle will be null. In such cases, the standard library's `Read` and |
583 | /// `Write` will do nothing and silently succeed. All other I/O operations, via the |
584 | /// standard library or via raw Windows API calls, will fail. |
585 | /// |
586 | /// [`lock`]: Stdout::lock |
587 | /// [`io::stdout`]: stdout |
588 | #[stable (feature = "rust1" , since = "1.0.0" )] |
589 | pub struct Stdout { |
590 | // FIXME: this should be LineWriter or BufWriter depending on the state of |
591 | // stdout (tty or not). Note that if this is not line buffered it |
592 | // should also flush-on-panic or some form of flush-on-abort. |
593 | inner: &'static ReentrantLock<RefCell<LineWriter<StdoutRaw>>>, |
594 | } |
595 | |
596 | /// A locked reference to the [`Stdout`] handle. |
597 | /// |
598 | /// This handle implements the [`Write`] trait, and is constructed via |
599 | /// the [`Stdout::lock`] method. See its documentation for more. |
600 | /// |
601 | /// ### Note: Windows Portability Considerations |
602 | /// |
603 | /// When operating in a console, the Windows implementation of this stream does not support |
604 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return |
605 | /// an error. |
606 | /// |
607 | /// In a process with a detached console, such as one using |
608 | /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, |
609 | /// the contained handle will be null. In such cases, the standard library's `Read` and |
610 | /// `Write` will do nothing and silently succeed. All other I/O operations, via the |
611 | /// standard library or via raw Windows API calls, will fail. |
612 | #[must_use = "if unused stdout will immediately unlock" ] |
613 | #[stable (feature = "rust1" , since = "1.0.0" )] |
614 | pub struct StdoutLock<'a> { |
615 | inner: ReentrantLockGuard<'a, RefCell<LineWriter<StdoutRaw>>>, |
616 | } |
617 | |
618 | static STDOUT: OnceLock<ReentrantLock<RefCell<LineWriter<StdoutRaw>>>> = OnceLock::new(); |
619 | |
620 | /// Constructs a new handle to the standard output of the current process. |
621 | /// |
622 | /// Each handle returned is a reference to a shared global buffer whose access |
623 | /// is synchronized via a mutex. If you need more explicit control over |
624 | /// locking, see the [`Stdout::lock`] method. |
625 | /// |
626 | /// ### Note: Windows Portability Considerations |
627 | /// |
628 | /// When operating in a console, the Windows implementation of this stream does not support |
629 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return |
630 | /// an error. |
631 | /// |
632 | /// In a process with a detached console, such as one using |
633 | /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, |
634 | /// the contained handle will be null. In such cases, the standard library's `Read` and |
635 | /// `Write` will do nothing and silently succeed. All other I/O operations, via the |
636 | /// standard library or via raw Windows API calls, will fail. |
637 | /// |
638 | /// # Examples |
639 | /// |
640 | /// Using implicit synchronization: |
641 | /// |
642 | /// ```no_run |
643 | /// use std::io::{self, Write}; |
644 | /// |
645 | /// fn main() -> io::Result<()> { |
646 | /// io::stdout().write_all(b"hello world" )?; |
647 | /// |
648 | /// Ok(()) |
649 | /// } |
650 | /// ``` |
651 | /// |
652 | /// Using explicit synchronization: |
653 | /// |
654 | /// ```no_run |
655 | /// use std::io::{self, Write}; |
656 | /// |
657 | /// fn main() -> io::Result<()> { |
658 | /// let stdout = io::stdout(); |
659 | /// let mut handle = stdout.lock(); |
660 | /// |
661 | /// handle.write_all(b"hello world" )?; |
662 | /// |
663 | /// Ok(()) |
664 | /// } |
665 | /// ``` |
666 | #[must_use ] |
667 | #[stable (feature = "rust1" , since = "1.0.0" )] |
668 | #[cfg_attr (not(test), rustc_diagnostic_item = "io_stdout" )] |
669 | pub fn stdout() -> Stdout { |
670 | Stdout { |
671 | inner: STDOUTOnceLock>> |
672 | .get_or_init(|| ReentrantLock::new(RefCell::new(LineWriter::new(inner:stdout_raw())))), |
673 | } |
674 | } |
675 | |
676 | // Flush the data and disable buffering during shutdown |
677 | // by replacing the line writer by one with zero |
678 | // buffering capacity. |
679 | pub fn cleanup() { |
680 | let mut initialized: bool = false; |
681 | let stdout: &ReentrantLock>> = STDOUT.get_or_init(|| { |
682 | initialized = true; |
683 | ReentrantLock::new(RefCell::new(LineWriter::with_capacity(capacity:0, inner:stdout_raw()))) |
684 | }); |
685 | |
686 | if !initialized { |
687 | // The buffer was previously initialized, overwrite it here. |
688 | // We use try_lock() instead of lock(), because someone |
689 | // might have leaked a StdoutLock, which would |
690 | // otherwise cause a deadlock here. |
691 | if let Some(lock: ReentrantLockGuard<'_, RefCell<…>>) = stdout.try_lock() { |
692 | *lock.borrow_mut() = LineWriter::with_capacity(capacity:0, inner:stdout_raw()); |
693 | } |
694 | } |
695 | } |
696 | |
697 | impl Stdout { |
698 | /// Locks this handle to the standard output stream, returning a writable |
699 | /// guard. |
700 | /// |
701 | /// The lock is released when the returned lock goes out of scope. The |
702 | /// returned guard also implements the `Write` trait for writing data. |
703 | /// |
704 | /// # Examples |
705 | /// |
706 | /// ```no_run |
707 | /// use std::io::{self, Write}; |
708 | /// |
709 | /// fn main() -> io::Result<()> { |
710 | /// let mut stdout = io::stdout().lock(); |
711 | /// |
712 | /// stdout.write_all(b"hello world" )?; |
713 | /// |
714 | /// Ok(()) |
715 | /// } |
716 | /// ``` |
717 | #[stable (feature = "rust1" , since = "1.0.0" )] |
718 | pub fn lock(&self) -> StdoutLock<'static> { |
719 | // Locks this handle with 'static lifetime. This depends on the |
720 | // implementation detail that the underlying `ReentrantMutex` is |
721 | // static. |
722 | StdoutLock { inner: self.inner.lock() } |
723 | } |
724 | } |
725 | |
726 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
727 | impl UnwindSafe for Stdout {} |
728 | |
729 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
730 | impl RefUnwindSafe for Stdout {} |
731 | |
732 | #[stable (feature = "std_debug" , since = "1.16.0" )] |
733 | impl fmt::Debug for Stdout { |
734 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
735 | f.debug_struct(name:"Stdout" ).finish_non_exhaustive() |
736 | } |
737 | } |
738 | |
739 | #[stable (feature = "rust1" , since = "1.0.0" )] |
740 | impl Write for Stdout { |
741 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
742 | (&*self).write(buf) |
743 | } |
744 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
745 | (&*self).write_vectored(bufs) |
746 | } |
747 | #[inline ] |
748 | fn is_write_vectored(&self) -> bool { |
749 | io::Write::is_write_vectored(&&*self) |
750 | } |
751 | fn flush(&mut self) -> io::Result<()> { |
752 | (&*self).flush() |
753 | } |
754 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
755 | (&*self).write_all(buf) |
756 | } |
757 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { |
758 | (&*self).write_all_vectored(bufs) |
759 | } |
760 | fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { |
761 | (&*self).write_fmt(args) |
762 | } |
763 | } |
764 | |
765 | #[stable (feature = "write_mt" , since = "1.48.0" )] |
766 | impl Write for &Stdout { |
767 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
768 | self.lock().write(buf) |
769 | } |
770 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
771 | self.lock().write_vectored(bufs) |
772 | } |
773 | #[inline ] |
774 | fn is_write_vectored(&self) -> bool { |
775 | self.lock().is_write_vectored() |
776 | } |
777 | fn flush(&mut self) -> io::Result<()> { |
778 | self.lock().flush() |
779 | } |
780 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
781 | self.lock().write_all(buf) |
782 | } |
783 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { |
784 | self.lock().write_all_vectored(bufs) |
785 | } |
786 | fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { |
787 | self.lock().write_fmt(args) |
788 | } |
789 | } |
790 | |
791 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
792 | impl UnwindSafe for StdoutLock<'_> {} |
793 | |
794 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
795 | impl RefUnwindSafe for StdoutLock<'_> {} |
796 | |
797 | #[stable (feature = "rust1" , since = "1.0.0" )] |
798 | impl Write for StdoutLock<'_> { |
799 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
800 | self.inner.borrow_mut().write(buf) |
801 | } |
802 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
803 | self.inner.borrow_mut().write_vectored(bufs) |
804 | } |
805 | #[inline ] |
806 | fn is_write_vectored(&self) -> bool { |
807 | self.inner.borrow_mut().is_write_vectored() |
808 | } |
809 | fn flush(&mut self) -> io::Result<()> { |
810 | self.inner.borrow_mut().flush() |
811 | } |
812 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
813 | self.inner.borrow_mut().write_all(buf) |
814 | } |
815 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { |
816 | self.inner.borrow_mut().write_all_vectored(bufs) |
817 | } |
818 | } |
819 | |
820 | #[stable (feature = "std_debug" , since = "1.16.0" )] |
821 | impl fmt::Debug for StdoutLock<'_> { |
822 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
823 | f.debug_struct(name:"StdoutLock" ).finish_non_exhaustive() |
824 | } |
825 | } |
826 | |
827 | /// A handle to the standard error stream of a process. |
828 | /// |
829 | /// For more information, see the [`io::stderr`] method. |
830 | /// |
831 | /// [`io::stderr`]: stderr |
832 | /// |
833 | /// ### Note: Windows Portability Considerations |
834 | /// |
835 | /// When operating in a console, the Windows implementation of this stream does not support |
836 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return |
837 | /// an error. |
838 | /// |
839 | /// In a process with a detached console, such as one using |
840 | /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, |
841 | /// the contained handle will be null. In such cases, the standard library's `Read` and |
842 | /// `Write` will do nothing and silently succeed. All other I/O operations, via the |
843 | /// standard library or via raw Windows API calls, will fail. |
844 | #[stable (feature = "rust1" , since = "1.0.0" )] |
845 | pub struct Stderr { |
846 | inner: &'static ReentrantLock<RefCell<StderrRaw>>, |
847 | } |
848 | |
849 | /// A locked reference to the [`Stderr`] handle. |
850 | /// |
851 | /// This handle implements the [`Write`] trait and is constructed via |
852 | /// the [`Stderr::lock`] method. See its documentation for more. |
853 | /// |
854 | /// ### Note: Windows Portability Considerations |
855 | /// |
856 | /// When operating in a console, the Windows implementation of this stream does not support |
857 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return |
858 | /// an error. |
859 | /// |
860 | /// In a process with a detached console, such as one using |
861 | /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, |
862 | /// the contained handle will be null. In such cases, the standard library's `Read` and |
863 | /// `Write` will do nothing and silently succeed. All other I/O operations, via the |
864 | /// standard library or via raw Windows API calls, will fail. |
865 | #[must_use = "if unused stderr will immediately unlock" ] |
866 | #[stable (feature = "rust1" , since = "1.0.0" )] |
867 | pub struct StderrLock<'a> { |
868 | inner: ReentrantLockGuard<'a, RefCell<StderrRaw>>, |
869 | } |
870 | |
871 | /// Constructs a new handle to the standard error of the current process. |
872 | /// |
873 | /// This handle is not buffered. |
874 | /// |
875 | /// ### Note: Windows Portability Considerations |
876 | /// |
877 | /// When operating in a console, the Windows implementation of this stream does not support |
878 | /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return |
879 | /// an error. |
880 | /// |
881 | /// In a process with a detached console, such as one using |
882 | /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, |
883 | /// the contained handle will be null. In such cases, the standard library's `Read` and |
884 | /// `Write` will do nothing and silently succeed. All other I/O operations, via the |
885 | /// standard library or via raw Windows API calls, will fail. |
886 | /// |
887 | /// # Examples |
888 | /// |
889 | /// Using implicit synchronization: |
890 | /// |
891 | /// ```no_run |
892 | /// use std::io::{self, Write}; |
893 | /// |
894 | /// fn main() -> io::Result<()> { |
895 | /// io::stderr().write_all(b"hello world" )?; |
896 | /// |
897 | /// Ok(()) |
898 | /// } |
899 | /// ``` |
900 | /// |
901 | /// Using explicit synchronization: |
902 | /// |
903 | /// ```no_run |
904 | /// use std::io::{self, Write}; |
905 | /// |
906 | /// fn main() -> io::Result<()> { |
907 | /// let stderr = io::stderr(); |
908 | /// let mut handle = stderr.lock(); |
909 | /// |
910 | /// handle.write_all(b"hello world" )?; |
911 | /// |
912 | /// Ok(()) |
913 | /// } |
914 | /// ``` |
915 | #[must_use ] |
916 | #[stable (feature = "rust1" , since = "1.0.0" )] |
917 | #[cfg_attr (not(test), rustc_diagnostic_item = "io_stderr" )] |
918 | pub fn stderr() -> Stderr { |
919 | // Note that unlike `stdout()` we don't use `at_exit` here to register a |
920 | // destructor. Stderr is not buffered, so there's no need to run a |
921 | // destructor for flushing the buffer |
922 | static INSTANCE: ReentrantLock<RefCell<StderrRaw>> = |
923 | ReentrantLock::new(RefCell::new(stderr_raw())); |
924 | |
925 | Stderr { inner: &INSTANCE } |
926 | } |
927 | |
928 | impl Stderr { |
929 | /// Locks this handle to the standard error stream, returning a writable |
930 | /// guard. |
931 | /// |
932 | /// The lock is released when the returned lock goes out of scope. The |
933 | /// returned guard also implements the [`Write`] trait for writing data. |
934 | /// |
935 | /// # Examples |
936 | /// |
937 | /// ``` |
938 | /// use std::io::{self, Write}; |
939 | /// |
940 | /// fn foo() -> io::Result<()> { |
941 | /// let stderr = io::stderr(); |
942 | /// let mut handle = stderr.lock(); |
943 | /// |
944 | /// handle.write_all(b"hello world" )?; |
945 | /// |
946 | /// Ok(()) |
947 | /// } |
948 | /// ``` |
949 | #[stable (feature = "rust1" , since = "1.0.0" )] |
950 | pub fn lock(&self) -> StderrLock<'static> { |
951 | // Locks this handle with 'static lifetime. This depends on the |
952 | // implementation detail that the underlying `ReentrantMutex` is |
953 | // static. |
954 | StderrLock { inner: self.inner.lock() } |
955 | } |
956 | } |
957 | |
958 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
959 | impl UnwindSafe for Stderr {} |
960 | |
961 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
962 | impl RefUnwindSafe for Stderr {} |
963 | |
964 | #[stable (feature = "std_debug" , since = "1.16.0" )] |
965 | impl fmt::Debug for Stderr { |
966 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
967 | f.debug_struct(name:"Stderr" ).finish_non_exhaustive() |
968 | } |
969 | } |
970 | |
971 | #[stable (feature = "rust1" , since = "1.0.0" )] |
972 | impl Write for Stderr { |
973 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
974 | (&*self).write(buf) |
975 | } |
976 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
977 | (&*self).write_vectored(bufs) |
978 | } |
979 | #[inline ] |
980 | fn is_write_vectored(&self) -> bool { |
981 | io::Write::is_write_vectored(&&*self) |
982 | } |
983 | fn flush(&mut self) -> io::Result<()> { |
984 | (&*self).flush() |
985 | } |
986 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
987 | (&*self).write_all(buf) |
988 | } |
989 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { |
990 | (&*self).write_all_vectored(bufs) |
991 | } |
992 | fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { |
993 | (&*self).write_fmt(args) |
994 | } |
995 | } |
996 | |
997 | #[stable (feature = "write_mt" , since = "1.48.0" )] |
998 | impl Write for &Stderr { |
999 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
1000 | self.lock().write(buf) |
1001 | } |
1002 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
1003 | self.lock().write_vectored(bufs) |
1004 | } |
1005 | #[inline ] |
1006 | fn is_write_vectored(&self) -> bool { |
1007 | self.lock().is_write_vectored() |
1008 | } |
1009 | fn flush(&mut self) -> io::Result<()> { |
1010 | self.lock().flush() |
1011 | } |
1012 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
1013 | self.lock().write_all(buf) |
1014 | } |
1015 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { |
1016 | self.lock().write_all_vectored(bufs) |
1017 | } |
1018 | fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { |
1019 | self.lock().write_fmt(args) |
1020 | } |
1021 | } |
1022 | |
1023 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
1024 | impl UnwindSafe for StderrLock<'_> {} |
1025 | |
1026 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
1027 | impl RefUnwindSafe for StderrLock<'_> {} |
1028 | |
1029 | #[stable (feature = "rust1" , since = "1.0.0" )] |
1030 | impl Write for StderrLock<'_> { |
1031 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
1032 | self.inner.borrow_mut().write(buf) |
1033 | } |
1034 | fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
1035 | self.inner.borrow_mut().write_vectored(bufs) |
1036 | } |
1037 | #[inline ] |
1038 | fn is_write_vectored(&self) -> bool { |
1039 | self.inner.borrow_mut().is_write_vectored() |
1040 | } |
1041 | fn flush(&mut self) -> io::Result<()> { |
1042 | self.inner.borrow_mut().flush() |
1043 | } |
1044 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
1045 | self.inner.borrow_mut().write_all(buf) |
1046 | } |
1047 | fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { |
1048 | self.inner.borrow_mut().write_all_vectored(bufs) |
1049 | } |
1050 | } |
1051 | |
1052 | #[stable (feature = "std_debug" , since = "1.16.0" )] |
1053 | impl fmt::Debug for StderrLock<'_> { |
1054 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1055 | f.debug_struct(name:"StderrLock" ).finish_non_exhaustive() |
1056 | } |
1057 | } |
1058 | |
1059 | /// Sets the thread-local output capture buffer and returns the old one. |
1060 | #[unstable ( |
1061 | feature = "internal_output_capture" , |
1062 | reason = "this function is meant for use in the test crate \ |
1063 | and may disappear in the future" , |
1064 | issue = "none" |
1065 | )] |
1066 | #[doc (hidden)] |
1067 | pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> { |
1068 | try_set_output_capture(sink).expect( |
1069 | msg:"cannot access a Thread Local Storage value \ |
1070 | msg: during or after destruction" , |
1071 | ) |
1072 | } |
1073 | |
1074 | /// Tries to set the thread-local output capture buffer and returns the old one. |
1075 | /// This may fail once thread-local destructors are called. It's used in panic |
1076 | /// handling instead of `set_output_capture`. |
1077 | #[unstable ( |
1078 | feature = "internal_output_capture" , |
1079 | reason = "this function is meant for use in the test crate \ |
1080 | and may disappear in the future" , |
1081 | issue = "none" |
1082 | )] |
1083 | #[doc (hidden)] |
1084 | pub fn try_set_output_capture( |
1085 | sink: Option<LocalStream>, |
1086 | ) -> Result<Option<LocalStream>, AccessError> { |
1087 | if sink.is_none() && !OUTPUT_CAPTURE_USED.load(order:Ordering::Relaxed) { |
1088 | // OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false. |
1089 | return Ok(None); |
1090 | } |
1091 | OUTPUT_CAPTURE_USED.store(val:true, order:Ordering::Relaxed); |
1092 | OUTPUT_CAPTURE.try_with(move |slot: &Cell| slot.replace(val:sink)) |
1093 | } |
1094 | |
1095 | /// Write `args` to the capture buffer if enabled and possible, or `global_s` |
1096 | /// otherwise. `label` identifies the stream in a panic message. |
1097 | /// |
1098 | /// This function is used to print error messages, so it takes extra |
1099 | /// care to avoid causing a panic when `OUTPUT_CAPTURE` is unusable. |
1100 | /// For instance, if the TLS key for output capturing is already destroyed, or |
1101 | /// if the local stream is in use by another thread, it will just fall back to |
1102 | /// the global stream. |
1103 | /// |
1104 | /// However, if the actual I/O causes an error, this function does panic. |
1105 | /// |
1106 | /// Writing to non-blocking stdout/stderr can cause an error, which will lead |
1107 | /// this function to panic. |
1108 | fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str) |
1109 | where |
1110 | T: Write, |
1111 | { |
1112 | if print_to_buffer_if_capture_used(args) { |
1113 | // Successfully wrote to capture buffer. |
1114 | return; |
1115 | } |
1116 | |
1117 | if let Err(e: Error) = global_s().write_fmt(args) { |
1118 | panic!("failed printing to {label}: {e}" ); |
1119 | } |
1120 | } |
1121 | |
1122 | fn print_to_buffer_if_capture_used(args: fmt::Arguments<'_>) -> bool { |
1123 | OUTPUT_CAPTURE_USED.load(order:Ordering::Relaxed) |
1124 | && OUTPUT_CAPTURE.try_with(|s: &Cell| { |
1125 | // Note that we completely remove a local sink to write to in case |
1126 | // our printing recursively panics/prints, so the recursive |
1127 | // panic/print goes to the global sink instead of our local sink. |
1128 | s.take().map(|w: Arc>>| { |
1129 | let _ = w.lock().unwrap_or_else(|e: PoisonError>| e.into_inner()).write_fmt(args); |
1130 | s.set(val:Some(w)); |
1131 | }) |
1132 | }) == Ok(Some(())) |
1133 | } |
1134 | |
1135 | /// Used by impl Termination for Result to print error after `main` or a test |
1136 | /// has returned. Should avoid panicking, although we can't help it if one of |
1137 | /// the Display impls inside args decides to. |
1138 | pub(crate) fn attempt_print_to_stderr(args: fmt::Arguments<'_>) { |
1139 | if print_to_buffer_if_capture_used(args) { |
1140 | return; |
1141 | } |
1142 | |
1143 | // Ignore error if the write fails, for example because stderr is already |
1144 | // closed. There is not much point panicking at this point. |
1145 | let _ = stderr().write_fmt(args); |
1146 | } |
1147 | |
1148 | /// Trait to determine if a descriptor/handle refers to a terminal/tty. |
1149 | #[stable (feature = "is_terminal" , since = "1.70.0" )] |
1150 | pub trait IsTerminal: crate::sealed::Sealed { |
1151 | /// Returns `true` if the descriptor/handle refers to a terminal/tty. |
1152 | /// |
1153 | /// On platforms where Rust does not know how to detect a terminal yet, this will return |
1154 | /// `false`. This will also return `false` if an unexpected error occurred, such as from |
1155 | /// passing an invalid file descriptor. |
1156 | /// |
1157 | /// # Platform-specific behavior |
1158 | /// |
1159 | /// On Windows, in addition to detecting consoles, this currently uses some heuristics to |
1160 | /// detect older msys/cygwin/mingw pseudo-terminals based on device name: devices with names |
1161 | /// starting with `msys-` or `cygwin-` and ending in `-pty` will be considered terminals. |
1162 | /// Note that this [may change in the future][changes]. |
1163 | /// |
1164 | /// [changes]: io#platform-specific-behavior |
1165 | #[stable (feature = "is_terminal" , since = "1.70.0" )] |
1166 | fn is_terminal(&self) -> bool; |
1167 | } |
1168 | |
1169 | macro_rules! impl_is_terminal { |
1170 | ($($t:ty),*$(,)?) => {$( |
1171 | #[unstable(feature = "sealed" , issue = "none" )] |
1172 | impl crate::sealed::Sealed for $t {} |
1173 | |
1174 | #[stable(feature = "is_terminal" , since = "1.70.0" )] |
1175 | impl IsTerminal for $t { |
1176 | #[inline] |
1177 | fn is_terminal(&self) -> bool { |
1178 | crate::sys::io::is_terminal(self) |
1179 | } |
1180 | } |
1181 | )*} |
1182 | } |
1183 | |
1184 | impl_is_terminal!(File, Stdin, StdinLock<'_>, Stdout, StdoutLock<'_>, Stderr, StderrLock<'_>); |
1185 | |
1186 | #[unstable ( |
1187 | feature = "print_internals" , |
1188 | reason = "implementation detail which may disappear or be replaced at any time" , |
1189 | issue = "none" |
1190 | )] |
1191 | #[doc (hidden)] |
1192 | #[cfg (not(test))] |
1193 | pub fn _print(args: fmt::Arguments<'_>) { |
1194 | print_to(args, global_s:stdout, label:"stdout" ); |
1195 | } |
1196 | |
1197 | #[unstable ( |
1198 | feature = "print_internals" , |
1199 | reason = "implementation detail which may disappear or be replaced at any time" , |
1200 | issue = "none" |
1201 | )] |
1202 | #[doc (hidden)] |
1203 | #[cfg (not(test))] |
1204 | pub fn _eprint(args: fmt::Arguments<'_>) { |
1205 | print_to(args, global_s:stderr, label:"stderr" ); |
1206 | } |
1207 | |
1208 | #[cfg (test)] |
1209 | pub use realstd::io::{_eprint, _print}; |
1210 | |