1#![cfg_attr(test, allow(unused))]
23#[cfg(test)]
4mod tests;
56use crate::cell::{Cell, RefCell};
7use crate::fmt;
8use crate::fs::File;
9use crate::io::prelude::*;
10use crate::io::{
11self, 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;
1819type LocalStream = Arc<Mutex<Vec<u8>>>;
2021#[doc =
r" Used by the test crate to capture the output of the print macros and panics."]
const OUTPUT_CAPTURE: crate::thread::LocalKey<Cell<Option<LocalStream>>> =
{
const __RUST_STD_INTERNAL_INIT: Cell<Option<LocalStream>> =
{ Cell::new(None) };
unsafe {
crate::thread::LocalKey::new(const {
if crate::mem::needs_drop::<Cell<Option<LocalStream>>>() {
|_|
{
#[thread_local]
static __RUST_STD_INTERNAL_VAL:
crate::thread::local_impl::EagerStorage<Cell<Option<LocalStream>>>
=
crate::thread::local_impl::EagerStorage::new(__RUST_STD_INTERNAL_INIT);
__RUST_STD_INTERNAL_VAL.get()
}
} else {
|_|
{
#[thread_local]
static __RUST_STD_INTERNAL_VAL: Cell<Option<LocalStream>> =
__RUST_STD_INTERNAL_INIT;
&__RUST_STD_INTERNAL_VAL
}
}
})
}
};thread_local! {
22/// Used by the test crate to capture the output of the print macros and panics.
23static OUTPUT_CAPTURE: Cell<Option<LocalStream>> = const {
24 Cell::new(None)
25 }
26}2728/// 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);
4142/// 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);
4748/// 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);
5354/// 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);
5960/// 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 {
69StdinRaw(stdio::Stdin::new())
70}
7172/// 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 {
83StdoutRaw(stdio::Stdout::new())
84}
8586/// 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 {
95StderrRaw(stdio::Stderr::new())
96}
9798impl Readfor StdinRaw {
99fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
100handle_ebadf(self.0.read(buf), || Ok(0))
101 }
102103fn read_buf(&mut self, buf: BorrowedCursor<'_, u8>) -> io::Result<()> {
104handle_ebadf(self.0.read_buf(buf), || Ok(()))
105 }
106107fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
108handle_ebadf(self.0.read_vectored(bufs), || Ok(0))
109 }
110111#[inline]
112fn is_read_vectored(&self) -> bool {
113self.0.is_read_vectored()
114 }
115116fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
117if buf.is_empty() {
118return Ok(());
119 }
120handle_ebadf(self.0.read_exact(buf), || Err(io::Error::READ_EXACT_EOF))
121 }
122123fn read_buf_exact(&mut self, buf: BorrowedCursor<'_, u8>) -> io::Result<()> {
124if buf.capacity() == 0 {
125return Ok(());
126 }
127handle_ebadf(self.0.read_buf_exact(buf), || Err(io::Error::READ_EXACT_EOF))
128 }
129130fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
131handle_ebadf(self.0.read_to_end(buf), || Ok(0))
132 }
133134fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
135handle_ebadf(self.0.read_to_string(buf), || Ok(0))
136 }
137}
138139impl Writefor StdoutRaw {
140fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
141handle_ebadf(self.0.write(buf), || Ok(buf.len()))
142 }
143144fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
145let total = || Ok(bufs.iter().map(|b| b.len()).sum());
146handle_ebadf(self.0.write_vectored(bufs), total)
147 }
148149#[inline]
150fn is_write_vectored(&self) -> bool {
151self.0.is_write_vectored()
152 }
153154fn flush(&mut self) -> io::Result<()> {
155handle_ebadf(self.0.flush(), || Ok(()))
156 }
157158fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
159handle_ebadf(self.0.write_all(buf), || Ok(()))
160 }
161162fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
163handle_ebadf(self.0.write_all_vectored(bufs), || Ok(()))
164 }
165166fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
167handle_ebadf(self.0.write_fmt(fmt), || Ok(()))
168 }
169}
170171impl Writefor StderrRaw {
172fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
173handle_ebadf(self.0.write(buf), || Ok(buf.len()))
174 }
175176fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
177let total = || Ok(bufs.iter().map(|b| b.len()).sum());
178handle_ebadf(self.0.write_vectored(bufs), total)
179 }
180181#[inline]
182fn is_write_vectored(&self) -> bool {
183self.0.is_write_vectored()
184 }
185186fn flush(&mut self) -> io::Result<()> {
187handle_ebadf(self.0.flush(), || Ok(()))
188 }
189190fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
191handle_ebadf(self.0.write_all(buf), || Ok(()))
192 }
193194fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
195handle_ebadf(self.0.write_all_vectored(bufs), || Ok(()))
196 }
197198fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
199handle_ebadf(self.0.write_fmt(fmt), || Ok(()))
200 }
201}
202203fn handle_ebadf<T>(r: io::Result<T>, default: impl FnOnce() -> io::Result<T>) -> io::Result<T> {
204match r {
205Err(ref e) if stdio::is_ebadf(e) => default(),
206 r => r,
207 }
208}
209210/// A handle to the standard input stream of a process.
211///
212/// Each handle is a shared reference to a global buffer of input data to this
213/// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods
214/// (e.g., `.lines()`). Reads to this handle are otherwise locked with respect
215/// to other reads.
216///
217/// This handle implements the `Read` trait, but beware that concurrent reads
218/// of `Stdin` must be executed with care.
219///
220/// Created by the [`io::stdin`] method.
221///
222/// [`io::stdin`]: stdin
223///
224/// ### Note: Windows Portability Considerations
225///
226/// When operating in a console, the Windows implementation of this stream does not support
227/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
228/// an error.
229///
230/// In a process with a detached console, such as one using
231/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
232/// the contained handle will be null. In such cases, the standard library's `Read` and
233/// `Write` will do nothing and silently succeed. All other I/O operations, via the
234/// standard library or via raw Windows API calls, will fail.
235///
236/// # Examples
237///
238/// ```no_run
239/// use std::io;
240///
241/// fn main() -> io::Result<()> {
242/// let mut buffer = String::new();
243/// let stdin = io::stdin(); // We get `Stdin` here.
244/// stdin.read_line(&mut buffer)?;
245/// Ok(())
246/// }
247/// ```
248#[stable(feature = "rust1", since = "1.0.0")]
249#[cfg_attr(not(test), rustc_diagnostic_item = "Stdin")]
250pub struct Stdin {
251 inner: &'static Mutex<BufReader<StdinRaw>>,
252}
253254/// A locked reference to the [`Stdin`] handle.
255///
256/// This handle implements both the [`Read`] and [`BufRead`] traits, and
257/// is constructed via the [`Stdin::lock`] method.
258///
259/// ### Note: Windows Portability Considerations
260///
261/// When operating in a console, the Windows implementation of this stream does not support
262/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
263/// an error.
264///
265/// In a process with a detached console, such as one using
266/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
267/// the contained handle will be null. In such cases, the standard library's `Read` and
268/// `Write` will do nothing and silently succeed. All other I/O operations, via the
269/// standard library or via raw Windows API calls, will fail.
270///
271/// # Examples
272///
273/// ```no_run
274/// use std::io::{self, BufRead};
275///
276/// fn main() -> io::Result<()> {
277/// let mut buffer = String::new();
278/// let stdin = io::stdin(); // We get `Stdin` here.
279/// {
280/// let mut handle = stdin.lock(); // We get `StdinLock` here.
281/// handle.read_line(&mut buffer)?;
282/// } // `StdinLock` is dropped here.
283/// Ok(())
284/// }
285/// ```
286#[must_use = "if unused stdin will immediately unlock"]
287#[stable(feature = "rust1", since = "1.0.0")]
288#[cfg_attr(not(test), rustc_diagnostic_item = "StdinLock")]
289pub struct StdinLock<'a> {
290 inner: MutexGuard<'a, BufReader<StdinRaw>>,
291}
292293/// Constructs a new handle to the standard input of the current process.
294///
295/// Each handle returned is a reference to a shared global buffer whose access
296/// is synchronized via a mutex. If you need more explicit control over
297/// locking, see the [`Stdin::lock`] method.
298///
299/// ### Note: Windows Portability Considerations
300///
301/// When operating in a console, the Windows implementation of this stream does not support
302/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
303/// an error.
304///
305/// In a process with a detached console, such as one using
306/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
307/// the contained handle will be null. In such cases, the standard library's `Read` and
308/// `Write` will do nothing and silently succeed. All other I/O operations, via the
309/// standard library or via raw Windows API calls, will fail.
310///
311/// # Examples
312///
313/// Using implicit synchronization:
314///
315/// ```no_run
316/// use std::io;
317///
318/// fn main() -> io::Result<()> {
319/// let mut buffer = String::new();
320/// io::stdin().read_line(&mut buffer)?;
321/// Ok(())
322/// }
323/// ```
324///
325/// Using explicit synchronization:
326///
327/// ```no_run
328/// use std::io::{self, BufRead};
329///
330/// fn main() -> io::Result<()> {
331/// let mut buffer = String::new();
332/// let stdin = io::stdin();
333/// let mut handle = stdin.lock();
334///
335/// handle.read_line(&mut buffer)?;
336/// Ok(())
337/// }
338/// ```
339#[must_use]
340#[stable(feature = "rust1", since = "1.0.0")]
341pub fn stdin() -> Stdin {
342static INSTANCE: OnceLock<Mutex<BufReader<StdinRaw>>> = OnceLock::new();
343Stdin {
344 inner: INSTANCE.get_or_init(|| {
345Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw()))
346 }),
347 }
348}
349350impl Stdin {
351/// Locks this handle to the standard input stream, returning a readable
352 /// guard.
353 ///
354 /// The lock is released when the returned lock goes out of scope. The
355 /// returned guard also implements the [`Read`] and [`BufRead`] traits for
356 /// accessing the underlying data.
357 ///
358 /// # Examples
359 ///
360 /// ```no_run
361 /// use std::io::{self, BufRead};
362 ///
363 /// fn main() -> io::Result<()> {
364 /// let mut buffer = String::new();
365 /// let stdin = io::stdin();
366 /// let mut handle = stdin.lock();
367 ///
368 /// handle.read_line(&mut buffer)?;
369 /// Ok(())
370 /// }
371 /// ```
372#[stable(feature = "rust1", since = "1.0.0")]
373pub fn lock(&self) -> StdinLock<'static> {
374// Locks this handle with 'static lifetime. This depends on the
375 // implementation detail that the underlying `Mutex` is static.
376StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
377 }
378379/// Locks this handle and reads a line of input, appending it to the specified buffer.
380 ///
381 /// For detailed semantics of this method, see the documentation on
382 /// [`BufRead::read_line`]. In particular:
383 /// * Previous content of the buffer will be preserved. To avoid appending
384 /// to the buffer, you need to [`clear`] it first.
385 /// * The trailing newline character, if any, is included in the buffer.
386 ///
387 /// [`clear`]: String::clear
388 ///
389 /// # Examples
390 ///
391 /// ```no_run
392 /// use std::io;
393 ///
394 /// let mut input = String::new();
395 /// match io::stdin().read_line(&mut input) {
396 /// Ok(n) => {
397 /// println!("{n} bytes read");
398 /// println!("{input}");
399 /// }
400 /// Err(error) => println!("error: {error}"),
401 /// }
402 /// ```
403 ///
404 /// You can run the example one of two ways:
405 ///
406 /// - Pipe some text to it, e.g., `printf foo | path/to/executable`
407 /// - Give it text interactively by running the executable directly,
408 /// in which case it will wait for the Enter key to be pressed before
409 /// continuing
410#[stable(feature = "rust1", since = "1.0.0")]
411 #[rustc_confusables("get_line")]
412pub fn read_line(&self, buf: &mut String) -> io::Result<usize> {
413self.lock().read_line(buf)
414 }
415416/// Consumes this handle and returns an iterator over input lines.
417 ///
418 /// For detailed semantics of this method, see the documentation on
419 /// [`BufRead::lines`].
420 ///
421 /// # Examples
422 ///
423 /// ```no_run
424 /// use std::io;
425 ///
426 /// let lines = io::stdin().lines();
427 /// for line in lines {
428 /// println!("got a line: {}", line.unwrap());
429 /// }
430 /// ```
431#[must_use = "`self` will be dropped if the result is not used"]
432 #[stable(feature = "stdin_forwarders", since = "1.62.0")]
433pub fn lines(self) -> Lines<StdinLock<'static>> {
434self.lock().lines()
435 }
436}
437438#[stable(feature = "std_debug", since = "1.16.0")]
439impl fmt::Debugfor Stdin {
440fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441f.debug_struct("Stdin").finish_non_exhaustive()
442 }
443}
444445#[stable(feature = "rust1", since = "1.0.0")]
446impl Readfor Stdin {
447fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
448self.lock().read(buf)
449 }
450fn read_buf(&mut self, buf: BorrowedCursor<'_, u8>) -> io::Result<()> {
451self.lock().read_buf(buf)
452 }
453fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
454self.lock().read_vectored(bufs)
455 }
456#[inline]
457fn is_read_vectored(&self) -> bool {
458self.lock().is_read_vectored()
459 }
460fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
461self.lock().read_to_end(buf)
462 }
463fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
464self.lock().read_to_string(buf)
465 }
466fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
467self.lock().read_exact(buf)
468 }
469fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_, u8>) -> io::Result<()> {
470self.lock().read_buf_exact(cursor)
471 }
472}
473474#[stable(feature = "read_shared_stdin", since = "1.78.0")]
475impl Readfor &Stdin {
476fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
477self.lock().read(buf)
478 }
479fn read_buf(&mut self, buf: BorrowedCursor<'_, u8>) -> io::Result<()> {
480self.lock().read_buf(buf)
481 }
482fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
483self.lock().read_vectored(bufs)
484 }
485#[inline]
486fn is_read_vectored(&self) -> bool {
487self.lock().is_read_vectored()
488 }
489fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
490self.lock().read_to_end(buf)
491 }
492fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
493self.lock().read_to_string(buf)
494 }
495fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
496self.lock().read_exact(buf)
497 }
498fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_, u8>) -> io::Result<()> {
499self.lock().read_buf_exact(cursor)
500 }
501}
502503// only used by platform-dependent io::copy specializations, i.e. unused on some platforms
504#[cfg(any(target_os = "linux", target_os = "android"))]
505impl StdinLock<'_> {
506pub(crate) fn as_mut_buf(&mut self) -> &mut BufReader<impl Read> {
507&mut self.inner
508 }
509}
510511#[stable(feature = "rust1", since = "1.0.0")]
512impl Readfor StdinLock<'_> {
513fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
514self.inner.read(buf)
515 }
516517fn read_buf(&mut self, buf: BorrowedCursor<'_, u8>) -> io::Result<()> {
518self.inner.read_buf(buf)
519 }
520521fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
522self.inner.read_vectored(bufs)
523 }
524525#[inline]
526fn is_read_vectored(&self) -> bool {
527self.inner.is_read_vectored()
528 }
529530fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
531self.inner.read_to_end(buf)
532 }
533534fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
535self.inner.read_to_string(buf)
536 }
537538fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
539self.inner.read_exact(buf)
540 }
541542fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_, u8>) -> io::Result<()> {
543self.inner.read_buf_exact(cursor)
544 }
545}
546547#[doc(hidden)]
548#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
549impl SpecReadByte for StdinLock<'_> {
550#[inline]
551fn spec_read_byte(&mut self) -> Option<io::Result<u8>> {
552BufReader::spec_read_byte(&mut *self.inner)
553 }
554}
555556#[stable(feature = "rust1", since = "1.0.0")]
557impl BufReadfor StdinLock<'_> {
558fn fill_buf(&mut self) -> io::Result<&[u8]> {
559self.inner.fill_buf()
560 }
561562fn consume(&mut self, n: usize) {
563self.inner.consume(n)
564 }
565566fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
567self.inner.read_until(byte, buf)
568 }
569570fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
571self.inner.read_line(buf)
572 }
573}
574575#[stable(feature = "std_debug", since = "1.16.0")]
576impl fmt::Debugfor StdinLock<'_> {
577fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578f.debug_struct("StdinLock").finish_non_exhaustive()
579 }
580}
581582/// A handle to the global standard output stream of the current process.
583///
584/// Each handle shares a global buffer of data to be written to the standard
585/// output stream. Access is also synchronized via a lock and explicit control
586/// over locking is available via the [`lock`] method.
587///
588/// By default, the handle is line-buffered when connected to a terminal, meaning
589/// it flushes automatically when a newline (`\n`) is encountered. For immediate
590/// output, you can manually call the [`flush`] method. When the handle goes out
591/// of scope, the buffer is automatically flushed.
592///
593/// Created by the [`io::stdout`] method.
594///
595/// ### Note: Windows Portability Considerations
596///
597/// When operating in a console, the Windows implementation of this stream does not support
598/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
599/// an error.
600///
601/// In a process with a detached console, such as one using
602/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
603/// the contained handle will be null. In such cases, the standard library's `Read` and
604/// `Write` will do nothing and silently succeed. All other I/O operations, via the
605/// standard library or via raw Windows API calls, will fail.
606///
607/// [`lock`]: Stdout::lock
608/// [`flush`]: Write::flush
609/// [`io::stdout`]: stdout
610#[stable(feature = "rust1", since = "1.0.0")]
611pub struct Stdout {
612// FIXME: this should be LineWriter or BufWriter depending on the state of
613 // stdout (tty or not). Note that if this is not line buffered it
614 // should also flush-on-panic or some form of flush-on-abort.
615inner: &'static ReentrantLock<RefCell<LineWriter<StdoutRaw>>>,
616}
617618/// A locked reference to the [`Stdout`] handle.
619///
620/// This handle implements the [`Write`] trait, and is constructed via
621/// the [`Stdout::lock`] method. See its documentation for more.
622///
623/// By default, the handle is line-buffered when connected to a terminal, meaning
624/// it flushes automatically when a newline (`\n`) is encountered. For immediate
625/// output, you can manually call the [`flush`] method. When the handle goes out
626/// of scope, the buffer is automatically flushed.
627///
628/// ### Note: Windows Portability Considerations
629///
630/// When operating in a console, the Windows implementation of this stream does not support
631/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
632/// an error.
633///
634/// In a process with a detached console, such as one using
635/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
636/// the contained handle will be null. In such cases, the standard library's `Read` and
637/// `Write` will do nothing and silently succeed. All other I/O operations, via the
638/// standard library or via raw Windows API calls, will fail.
639///
640/// [`flush`]: Write::flush
641#[must_use = "if unused stdout will immediately unlock"]
642#[stable(feature = "rust1", since = "1.0.0")]
643pub struct StdoutLock<'a> {
644 inner: ReentrantLockGuard<'a, RefCell<LineWriter<StdoutRaw>>>,
645}
646647static STDOUT: OnceLock<ReentrantLock<RefCell<LineWriter<StdoutRaw>>>> = OnceLock::new();
648649/// Constructs a new handle to the standard output of the current process.
650///
651/// Each handle returned is a reference to a shared global buffer whose access
652/// is synchronized via a mutex. If you need more explicit control over
653/// locking, see the [`Stdout::lock`] method.
654///
655/// By default, the handle is line-buffered when connected to a terminal, meaning
656/// it flushes automatically when a newline (`\n`) is encountered. For immediate
657/// output, you can manually call the [`flush`] method. When the handle goes out
658/// of scope, the buffer is automatically flushed.
659///
660/// ### Note: Windows Portability Considerations
661///
662/// When operating in a console, the Windows implementation of this stream does not support
663/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
664/// an error.
665///
666/// In a process with a detached console, such as one using
667/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
668/// the contained handle will be null. In such cases, the standard library's `Read` and
669/// `Write` will do nothing and silently succeed. All other I/O operations, via the
670/// standard library or via raw Windows API calls, will fail.
671///
672/// # Examples
673///
674/// Using implicit synchronization:
675///
676/// ```no_run
677/// use std::io::{self, Write};
678///
679/// fn main() -> io::Result<()> {
680/// io::stdout().write_all(b"hello world")?;
681///
682/// Ok(())
683/// }
684/// ```
685///
686/// Using explicit synchronization:
687///
688/// ```no_run
689/// use std::io::{self, Write};
690///
691/// fn main() -> io::Result<()> {
692/// let stdout = io::stdout();
693/// let mut handle = stdout.lock();
694///
695/// handle.write_all(b"hello world")?;
696///
697/// Ok(())
698/// }
699/// ```
700///
701/// Ensuring output is flushed immediately:
702///
703/// ```no_run
704/// use std::io::{self, Write};
705///
706/// fn main() -> io::Result<()> {
707/// let mut stdout = io::stdout();
708/// stdout.write_all(b"hello, ")?;
709/// stdout.flush()?; // Manual flush
710/// stdout.write_all(b"world!\n")?; // Automatically flushed
711/// Ok(())
712/// }
713/// ```
714///
715/// [`flush`]: Write::flush
716#[must_use]
717#[stable(feature = "rust1", since = "1.0.0")]
718#[cfg_attr(not(test), rustc_diagnostic_item = "io_stdout")]
719pub fn stdout() -> Stdout {
720Stdout {
721 inner: STDOUT722 .get_or_init(|| ReentrantLock::new(RefCell::new(LineWriter::new(stdout_raw())))),
723 }
724}
725726// Flush the data and disable buffering during shutdown
727// by replacing the line writer by one with zero
728// buffering capacity.
729pub fn cleanup() {
730let mut initialized = false;
731let stdout = STDOUT.get_or_init(|| {
732initialized = true;
733ReentrantLock::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw())))
734 });
735736if !initialized {
737// The buffer was previously initialized, overwrite it here.
738 // We use try_lock() instead of lock(), because someone
739 // might have leaked a StdoutLock, which would
740 // otherwise cause a deadlock here.
741if let Some(lock) = stdout.try_lock() {
742*lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw());
743 }
744 }
745}
746747impl Stdout {
748/// Locks this handle to the standard output stream, returning a writable
749 /// guard.
750 ///
751 /// The lock is released when the returned lock goes out of scope. The
752 /// returned guard also implements the `Write` trait for writing data.
753 ///
754 /// # Examples
755 ///
756 /// ```no_run
757 /// use std::io::{self, Write};
758 ///
759 /// fn main() -> io::Result<()> {
760 /// let mut stdout = io::stdout().lock();
761 ///
762 /// stdout.write_all(b"hello world")?;
763 ///
764 /// Ok(())
765 /// }
766 /// ```
767#[stable(feature = "rust1", since = "1.0.0")]
768pub fn lock(&self) -> StdoutLock<'static> {
769// Locks this handle with 'static lifetime. This depends on the
770 // implementation detail that the underlying `ReentrantMutex` is
771 // static.
772StdoutLock { inner: self.inner.lock() }
773 }
774}
775776#[stable(feature = "catch_unwind", since = "1.9.0")]
777impl UnwindSafefor Stdout {}
778779#[stable(feature = "catch_unwind", since = "1.9.0")]
780impl RefUnwindSafefor Stdout {}
781782#[stable(feature = "std_debug", since = "1.16.0")]
783impl fmt::Debugfor Stdout {
784fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
785f.debug_struct("Stdout").finish_non_exhaustive()
786 }
787}
788789#[stable(feature = "rust1", since = "1.0.0")]
790impl Writefor Stdout {
791fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
792 (&*self).write(buf)
793 }
794fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
795 (&*self).write_vectored(bufs)
796 }
797#[inline]
798fn is_write_vectored(&self) -> bool {
799 io::Write::is_write_vectored(&self)
800 }
801fn flush(&mut self) -> io::Result<()> {
802 (&*self).flush()
803 }
804fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
805 (&*self).write_all(buf)
806 }
807fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
808 (&*self).write_all_vectored(bufs)
809 }
810fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
811 (&*self).write_fmt(args)
812 }
813}
814815#[stable(feature = "write_mt", since = "1.48.0")]
816impl Writefor &Stdout {
817fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
818self.lock().write(buf)
819 }
820fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
821self.lock().write_vectored(bufs)
822 }
823#[inline]
824fn is_write_vectored(&self) -> bool {
825self.lock().is_write_vectored()
826 }
827fn flush(&mut self) -> io::Result<()> {
828self.lock().flush()
829 }
830fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
831self.lock().write_all(buf)
832 }
833fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
834self.lock().write_all_vectored(bufs)
835 }
836fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
837self.lock().write_fmt(args)
838 }
839}
840841#[stable(feature = "catch_unwind", since = "1.9.0")]
842impl UnwindSafefor StdoutLock<'_> {}
843844#[stable(feature = "catch_unwind", since = "1.9.0")]
845impl RefUnwindSafefor StdoutLock<'_> {}
846847#[stable(feature = "rust1", since = "1.0.0")]
848impl Writefor StdoutLock<'_> {
849fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
850self.inner.borrow_mut().write(buf)
851 }
852fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
853self.inner.borrow_mut().write_vectored(bufs)
854 }
855#[inline]
856fn is_write_vectored(&self) -> bool {
857self.inner.borrow_mut().is_write_vectored()
858 }
859fn flush(&mut self) -> io::Result<()> {
860self.inner.borrow_mut().flush()
861 }
862fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
863self.inner.borrow_mut().write_all(buf)
864 }
865fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
866self.inner.borrow_mut().write_all_vectored(bufs)
867 }
868}
869870#[stable(feature = "std_debug", since = "1.16.0")]
871impl fmt::Debugfor StdoutLock<'_> {
872fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
873f.debug_struct("StdoutLock").finish_non_exhaustive()
874 }
875}
876877/// A handle to the standard error stream of a process.
878///
879/// For more information, see the [`io::stderr`] method.
880///
881/// [`io::stderr`]: stderr
882///
883/// ### Note: Windows Portability Considerations
884///
885/// When operating in a console, the Windows implementation of this stream does not support
886/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
887/// an error.
888///
889/// In a process with a detached console, such as one using
890/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
891/// the contained handle will be null. In such cases, the standard library's `Read` and
892/// `Write` will do nothing and silently succeed. All other I/O operations, via the
893/// standard library or via raw Windows API calls, will fail.
894#[stable(feature = "rust1", since = "1.0.0")]
895pub struct Stderr {
896 inner: &'static ReentrantLock<RefCell<StderrRaw>>,
897}
898899/// A locked reference to the [`Stderr`] handle.
900///
901/// This handle implements the [`Write`] trait and is constructed via
902/// the [`Stderr::lock`] method. See its documentation for more.
903///
904/// ### Note: Windows Portability Considerations
905///
906/// When operating in a console, the Windows implementation of this stream does not support
907/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
908/// an error.
909///
910/// In a process with a detached console, such as one using
911/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
912/// the contained handle will be null. In such cases, the standard library's `Read` and
913/// `Write` will do nothing and silently succeed. All other I/O operations, via the
914/// standard library or via raw Windows API calls, will fail.
915#[must_use = "if unused stderr will immediately unlock"]
916#[stable(feature = "rust1", since = "1.0.0")]
917pub struct StderrLock<'a> {
918 inner: ReentrantLockGuard<'a, RefCell<StderrRaw>>,
919}
920921/// Constructs a new handle to the standard error of the current process.
922///
923/// This handle is not buffered.
924///
925/// ### Note: Windows Portability Considerations
926///
927/// When operating in a console, the Windows implementation of this stream does not support
928/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
929/// an error.
930///
931/// In a process with a detached console, such as one using
932/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
933/// the contained handle will be null. In such cases, the standard library's `Read` and
934/// `Write` will do nothing and silently succeed. All other I/O operations, via the
935/// standard library or via raw Windows API calls, will fail.
936///
937/// # Examples
938///
939/// Using implicit synchronization:
940///
941/// ```no_run
942/// use std::io::{self, Write};
943///
944/// fn main() -> io::Result<()> {
945/// io::stderr().write_all(b"hello world")?;
946///
947/// Ok(())
948/// }
949/// ```
950///
951/// Using explicit synchronization:
952///
953/// ```no_run
954/// use std::io::{self, Write};
955///
956/// fn main() -> io::Result<()> {
957/// let stderr = io::stderr();
958/// let mut handle = stderr.lock();
959///
960/// handle.write_all(b"hello world")?;
961///
962/// Ok(())
963/// }
964/// ```
965#[must_use]
966#[stable(feature = "rust1", since = "1.0.0")]
967#[cfg_attr(not(test), rustc_diagnostic_item = "io_stderr")]
968pub fn stderr() -> Stderr {
969// Note that unlike `stdout()` we don't use `at_exit` here to register a
970 // destructor. Stderr is not buffered, so there's no need to run a
971 // destructor for flushing the buffer
972static INSTANCE: ReentrantLock<RefCell<StderrRaw>> =
973ReentrantLock::new(RefCell::new(stderr_raw()));
974975Stderr { inner: &INSTANCE }
976}
977978impl Stderr {
979/// Locks this handle to the standard error stream, returning a writable
980 /// guard.
981 ///
982 /// The lock is released when the returned lock goes out of scope. The
983 /// returned guard also implements the [`Write`] trait for writing data.
984 ///
985 /// # Examples
986 ///
987 /// ```
988 /// use std::io::{self, Write};
989 ///
990 /// fn foo() -> io::Result<()> {
991 /// let stderr = io::stderr();
992 /// let mut handle = stderr.lock();
993 ///
994 /// handle.write_all(b"hello world")?;
995 ///
996 /// Ok(())
997 /// }
998 /// ```
999#[stable(feature = "rust1", since = "1.0.0")]
1000pub fn lock(&self) -> StderrLock<'static> {
1001// Locks this handle with 'static lifetime. This depends on the
1002 // implementation detail that the underlying `ReentrantMutex` is
1003 // static.
1004StderrLock { inner: self.inner.lock() }
1005 }
1006}
10071008#[stable(feature = "catch_unwind", since = "1.9.0")]
1009impl UnwindSafefor Stderr {}
10101011#[stable(feature = "catch_unwind", since = "1.9.0")]
1012impl RefUnwindSafefor Stderr {}
10131014#[stable(feature = "std_debug", since = "1.16.0")]
1015impl fmt::Debugfor Stderr {
1016fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1017f.debug_struct("Stderr").finish_non_exhaustive()
1018 }
1019}
10201021#[stable(feature = "rust1", since = "1.0.0")]
1022impl Writefor Stderr {
1023fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1024 (&*self).write(buf)
1025 }
1026fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
1027 (&*self).write_vectored(bufs)
1028 }
1029#[inline]
1030fn is_write_vectored(&self) -> bool {
1031 io::Write::is_write_vectored(&self)
1032 }
1033fn flush(&mut self) -> io::Result<()> {
1034 (&*self).flush()
1035 }
1036fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1037 (&*self).write_all(buf)
1038 }
1039fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
1040 (&*self).write_all_vectored(bufs)
1041 }
1042fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
1043 (&*self).write_fmt(args)
1044 }
1045}
10461047#[stable(feature = "write_mt", since = "1.48.0")]
1048impl Writefor &Stderr {
1049fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1050self.lock().write(buf)
1051 }
1052fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
1053self.lock().write_vectored(bufs)
1054 }
1055#[inline]
1056fn is_write_vectored(&self) -> bool {
1057self.lock().is_write_vectored()
1058 }
1059fn flush(&mut self) -> io::Result<()> {
1060self.lock().flush()
1061 }
1062fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1063self.lock().write_all(buf)
1064 }
1065fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
1066self.lock().write_all_vectored(bufs)
1067 }
1068fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
1069self.lock().write_fmt(args)
1070 }
1071}
10721073#[stable(feature = "catch_unwind", since = "1.9.0")]
1074impl UnwindSafefor StderrLock<'_> {}
10751076#[stable(feature = "catch_unwind", since = "1.9.0")]
1077impl RefUnwindSafefor StderrLock<'_> {}
10781079#[stable(feature = "rust1", since = "1.0.0")]
1080impl Writefor StderrLock<'_> {
1081fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1082self.inner.borrow_mut().write(buf)
1083 }
1084fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
1085self.inner.borrow_mut().write_vectored(bufs)
1086 }
1087#[inline]
1088fn is_write_vectored(&self) -> bool {
1089self.inner.borrow_mut().is_write_vectored()
1090 }
1091fn flush(&mut self) -> io::Result<()> {
1092self.inner.borrow_mut().flush()
1093 }
1094fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1095self.inner.borrow_mut().write_all(buf)
1096 }
1097fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
1098self.inner.borrow_mut().write_all_vectored(bufs)
1099 }
1100}
11011102#[stable(feature = "std_debug", since = "1.16.0")]
1103impl fmt::Debugfor StderrLock<'_> {
1104fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1105f.debug_struct("StderrLock").finish_non_exhaustive()
1106 }
1107}
11081109/// Sets the thread-local output capture buffer and returns the old one.
1110#[unstable(
1111 feature = "internal_output_capture",
1112 reason = "this function is meant for use in the test crate \
1113 and may disappear in the future",
1114 issue = "none"
1115)]
1116#[doc(hidden)]
1117pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> {
1118try_set_output_capture(sink).expect(
1119"cannot access a Thread Local Storage value \
1120 during or after destruction",
1121 )
1122}
11231124/// Tries to set the thread-local output capture buffer and returns the old one.
1125/// This may fail once thread-local destructors are called. It's used in panic
1126/// handling instead of `set_output_capture`.
1127#[unstable(
1128 feature = "internal_output_capture",
1129 reason = "this function is meant for use in the test crate \
1130 and may disappear in the future",
1131 issue = "none"
1132)]
1133#[doc(hidden)]
1134pub fn try_set_output_capture(
1135 sink: Option<LocalStream>,
1136) -> Result<Option<LocalStream>, AccessError> {
1137if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) {
1138// OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false.
1139return Ok(None);
1140 }
1141OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed);
1142OUTPUT_CAPTURE.try_with(move |slot| slot.replace(sink))
1143}
11441145/// Writes `args` to the capture buffer if enabled and possible, or `global_s`
1146/// otherwise. `label` identifies the stream in a panic message.
1147///
1148/// This function is used to print error messages, so it takes extra
1149/// care to avoid causing a panic when `OUTPUT_CAPTURE` is unusable.
1150/// For instance, if the TLS key for output capturing is already destroyed, or
1151/// if the local stream is in use by another thread, it will just fall back to
1152/// the global stream.
1153///
1154/// However, if the actual I/O causes an error, this function does panic.
1155///
1156/// Writing to non-blocking stdout/stderr can cause an error, which will lead
1157/// this function to panic.
1158fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
1159where
1160T: Write,
1161{
1162if print_to_buffer_if_capture_used(args) {
1163// Successfully wrote to capture buffer.
1164return;
1165 }
11661167if let Err(e) = global_s().write_fmt(args) {
1168{
::core::panicking::panic_fmt(format_args!("failed printing to {0}: {1}",
label, e));
};panic!("failed printing to {label}: {e}");
1169 }
1170}
11711172fn print_to_buffer_if_capture_used(args: fmt::Arguments<'_>) -> bool {
1173OUTPUT_CAPTURE_USED.load(Ordering::Relaxed)
1174 && OUTPUT_CAPTURE.try_with(|s| {
1175// Note that we completely remove a local sink to write to in case
1176 // our printing recursively panics/prints, so the recursive
1177 // panic/print goes to the global sink instead of our local sink.
1178s.take().map(|w| {
1179let _ = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args);
1180s.set(Some(w));
1181 })
1182 }) == Ok(Some(()))
1183}
11841185/// Used by impl Termination for Result to print error after `main` or a test
1186/// has returned. Should avoid panicking, although we can't help it if one of
1187/// the Display impls inside args decides to.
1188pub(crate) fn attempt_print_to_stderr(args: fmt::Arguments<'_>) {
1189if print_to_buffer_if_capture_used(args) {
1190return;
1191 }
11921193// Ignore error if the write fails, for example because stderr is already
1194 // closed. There is not much point panicking at this point.
1195let _ = stderr().write_fmt(args);
1196}
11971198/// Trait to determine if a descriptor/handle refers to a terminal/tty.
1199#[stable(feature = "is_terminal", since = "1.70.0")]
1200pub impl(crate) trait IsTerminal {
1201/// Returns `true` if the descriptor/handle refers to a terminal/tty.
1202 ///
1203 /// On platforms where Rust does not know how to detect a terminal yet, this will return
1204 /// `false`. This will also return `false` if an unexpected error occurred, such as from
1205 /// passing an invalid file descriptor.
1206 ///
1207 /// # Platform-specific behavior
1208 ///
1209 /// On Windows, in addition to detecting consoles, this currently uses some heuristics to
1210 /// detect older msys/cygwin/mingw pseudo-terminals based on device name: devices with names
1211 /// starting with `msys-` or `cygwin-` and ending in `-pty` will be considered terminals.
1212 /// Note that this [may change in the future][changes].
1213 ///
1214 /// # Examples
1215 ///
1216 /// An example of a type for which `IsTerminal` is implemented is [`Stdin`]:
1217 ///
1218 /// ```no_run
1219 /// use std::io::{self, IsTerminal, Write};
1220 ///
1221 /// fn main() -> io::Result<()> {
1222 /// let stdin = io::stdin();
1223 ///
1224 /// // Indicate that the user is prompted for input, if this is a terminal.
1225 /// if stdin.is_terminal() {
1226 /// print!("> ");
1227 /// io::stdout().flush()?;
1228 /// }
1229 ///
1230 /// let mut name = String::new();
1231 /// let _ = stdin.read_line(&mut name)?;
1232 ///
1233 /// println!("Hello {}", name.trim_end());
1234 ///
1235 /// Ok(())
1236 /// }
1237 /// ```
1238 ///
1239 /// The example can be run in two ways:
1240 ///
1241 /// - If you run this example by piping some text to it, e.g. `echo "foo" | path/to/executable`
1242 /// it will print: `Hello foo`.
1243 /// - If you instead run the example interactively by running `path/to/executable` directly, it will
1244 /// prompt for input.
1245 ///
1246 /// [changes]: io#platform-specific-behavior
1247 /// [`Stdin`]: crate::io::Stdin
1248#[doc(alias = "isatty", alias = "atty")]
1249 #[stable(feature = "is_terminal", since = "1.70.0")]
1250fn is_terminal(&self) -> bool;
1251}
12521253macro_rules!impl_is_terminal {
1254 ($($t:ty),*$(,)?) => {$(
1255#[stable(feature = "is_terminal", since = "1.70.0")]
1256impl IsTerminal for $t {
1257#[inline]
1258fn is_terminal(&self) -> bool {
1259crate::sys::io::is_terminal(self)
1260 }
1261 }
1262 )*}
1263}
12641265#[stable(feature = "is_terminal", since = "1.70.0")]
impl IsTerminal for File {
#[inline]
fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) }
}
#[stable(feature = "is_terminal", since = "1.70.0")]
impl IsTerminal for Stdin {
#[inline]
fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) }
}
#[stable(feature = "is_terminal", since = "1.70.0")]
impl IsTerminal for StdinLock<'_> {
#[inline]
fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) }
}
#[stable(feature = "is_terminal", since = "1.70.0")]
impl IsTerminal for Stdout {
#[inline]
fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) }
}
#[stable(feature = "is_terminal", since = "1.70.0")]
impl IsTerminal for StdoutLock<'_> {
#[inline]
fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) }
}
#[stable(feature = "is_terminal", since = "1.70.0")]
impl IsTerminal for Stderr {
#[inline]
fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) }
}
#[stable(feature = "is_terminal", since = "1.70.0")]
impl IsTerminal for StderrLock<'_> {
#[inline]
fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) }
}impl_is_terminal!(File, Stdin, StdinLock<'_>, Stdout, StdoutLock<'_>, Stderr, StderrLock<'_>);
12661267#[unstable(
1268 feature = "print_internals",
1269 reason = "implementation detail which may disappear or be replaced at any time",
1270 issue = "none"
1271)]
1272#[doc(hidden)]
1273#[cfg(not(test))]
1274pub fn _print(args: fmt::Arguments<'_>) {
1275print_to(args, stdout, "stdout");
1276}
12771278#[unstable(
1279 feature = "print_internals",
1280 reason = "implementation detail which may disappear or be replaced at any time",
1281 issue = "none"
1282)]
1283#[doc(hidden)]
1284#[cfg(not(test))]
1285pub fn _eprint(args: fmt::Arguments<'_>) {
1286print_to(args, stderr, "stderr");
1287}
12881289#[cfg(test)]
1290pub use realstd::io::{_eprint, _print};