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