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