summaryrefslogtreecommitdiffstats
path: root/library/std/src/io
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/std/src/io/error.rs7
-rw-r--r--library/std/src/io/error/tests.rs2
-rw-r--r--library/std/src/io/mod.rs7
-rw-r--r--library/std/src/io/readbuf.rs9
-rw-r--r--library/std/src/io/stdio.rs57
5 files changed, 67 insertions, 15 deletions
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 29b09fcc5..3cabf2449 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -76,7 +76,6 @@ impl fmt::Debug for Error {
}
}
-#[cfg(not(bootstrap))]
#[stable(feature = "rust1", since = "1.0.0")]
impl From<alloc::ffi::NulError> for Error {
/// Converts a [`alloc::ffi::NulError`] into a [`Error`].
@@ -388,7 +387,7 @@ pub enum ErrorKind {
impl ErrorKind {
pub(crate) fn as_str(&self) -> &'static str {
use ErrorKind::*;
- // Strictly alphabetical, please. (Sadly rustfmt cannot do this yet.)
+ // tidy-alphabetical-start
match *self {
AddrInUse => "address in use",
AddrNotAvailable => "address not available",
@@ -432,6 +431,7 @@ impl ErrorKind {
WouldBlock => "operation would block",
WriteZero => "write zero",
}
+ // tidy-alphabetical-end
}
}
@@ -482,6 +482,7 @@ impl Error {
/// originate from the OS itself. The `error` argument is an arbitrary
/// payload which will be contained in this [`Error`].
///
+ /// Note that this function allocates memory on the heap.
/// If no extra payload is required, use the `From` conversion from
/// `ErrorKind`.
///
@@ -496,7 +497,7 @@ impl Error {
/// // errors can also be created from other errors
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
///
- /// // creating an error without payload
+ /// // creating an error without payload (and without memory allocation)
/// let eof_error = Error::from(ErrorKind::UnexpectedEof);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs
index c897a5e87..16c634e9a 100644
--- a/library/std/src/io/error/tests.rs
+++ b/library/std/src/io/error/tests.rs
@@ -86,7 +86,7 @@ fn test_errorkind_packing() {
assert_eq!(Error::from(ErrorKind::NotFound).kind(), ErrorKind::NotFound);
assert_eq!(Error::from(ErrorKind::PermissionDenied).kind(), ErrorKind::PermissionDenied);
assert_eq!(Error::from(ErrorKind::Uncategorized).kind(), ErrorKind::Uncategorized);
- // Check that the innards look like like what we want.
+ // Check that the innards look like what we want.
assert_matches!(
Error::from(ErrorKind::OutOfMemory).repr.data(),
ErrorData::Simple(ErrorKind::OutOfMemory),
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index eeace2c43..23a13523f 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -262,9 +262,12 @@ use crate::sys_common::memchr;
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub use self::buffered::WriterPanicked;
+pub(crate) use self::stdio::attempt_print_to_stderr;
#[unstable(feature = "internal_output_capture", issue = "none")]
#[doc(no_inline, hidden)]
pub use self::stdio::set_output_capture;
+#[unstable(feature = "is_terminal", issue = "98070")]
+pub use self::stdio::IsTerminal;
#[unstable(feature = "print_internals", issue = "none")]
pub use self::stdio::{_eprint, _print};
#[stable(feature = "rust1", since = "1.0.0")]
@@ -580,7 +583,7 @@ pub trait Read {
/// `n > buf.len()`.
///
/// No guarantees are provided about the contents of `buf` when this
- /// function is called, implementations cannot rely on any property of the
+ /// function is called, so implementations cannot rely on any property of the
/// contents of `buf` being true. It is recommended that *implementations*
/// only write data to `buf` instead of reading its contents.
///
@@ -756,7 +759,7 @@ pub trait Read {
/// specified buffer `buf`.
///
/// No guarantees are provided about the contents of `buf` when this
- /// function is called, implementations cannot rely on any property of the
+ /// function is called, so implementations cannot rely on any property of the
/// contents of `buf` being true. It is recommended that implementations
/// only write data to `buf` instead of reading its contents. The
/// documentation on [`read`] has a more detailed explanation on this
diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs
index b1a84095f..4800eeda0 100644
--- a/library/std/src/io/readbuf.rs
+++ b/library/std/src/io/readbuf.rs
@@ -3,10 +3,10 @@
#[cfg(test)]
mod tests;
-use crate::cmp;
use crate::fmt::{self, Debug, Formatter};
use crate::io::{Result, Write};
use crate::mem::{self, MaybeUninit};
+use crate::{cmp, ptr};
/// A borrowed byte buffer which is incrementally filled and initialized.
///
@@ -250,8 +250,11 @@ impl<'a> BorrowedCursor<'a> {
/// Initializes all bytes in the cursor.
#[inline]
pub fn ensure_init(&mut self) -> &mut Self {
- for byte in self.uninit_mut() {
- byte.write(0);
+ let uninit = self.uninit_mut();
+ // SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation
+ // since it is comes from a slice reference.
+ unsafe {
+ ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len());
}
self.buf.init = self.buf.capacity();
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 2dc12a18a..1141a957d 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -7,6 +7,7 @@ use crate::io::prelude::*;
use crate::cell::{Cell, RefCell};
use crate::fmt;
+use crate::fs::File;
use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sync::{Arc, Mutex, MutexGuard, OnceLock};
@@ -999,7 +1000,18 @@ fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
where
T: Write,
{
- if OUTPUT_CAPTURE_USED.load(Ordering::Relaxed)
+ if print_to_buffer_if_capture_used(args) {
+ // Successfully wrote to capture buffer.
+ return;
+ }
+
+ if let Err(e) = global_s().write_fmt(args) {
+ panic!("failed printing to {label}: {e}");
+ }
+}
+
+fn print_to_buffer_if_capture_used(args: fmt::Arguments<'_>) -> bool {
+ OUTPUT_CAPTURE_USED.load(Ordering::Relaxed)
&& OUTPUT_CAPTURE.try_with(|s| {
// Note that we completely remove a local sink to write to in case
// our printing recursively panics/prints, so the recursive
@@ -1009,16 +1021,49 @@ where
s.set(Some(w));
})
}) == Ok(Some(()))
- {
- // Successfully wrote to capture buffer.
+}
+
+/// Used by impl Termination for Result to print error after `main` or a test
+/// has returned. Should avoid panicking, although we can't help it if one of
+/// the Display impls inside args decides to.
+pub(crate) fn attempt_print_to_stderr(args: fmt::Arguments<'_>) {
+ if print_to_buffer_if_capture_used(args) {
return;
}
- if let Err(e) = global_s().write_fmt(args) {
- panic!("failed printing to {label}: {e}");
- }
+ // Ignore error if the write fails, for example because stderr is already
+ // closed. There is not much point panicking at this point.
+ let _ = stderr().write_fmt(args);
}
+/// Trait to determine if a descriptor/handle refers to a terminal/tty.
+#[unstable(feature = "is_terminal", issue = "98070")]
+pub trait IsTerminal: crate::sealed::Sealed {
+ /// Returns `true` if the descriptor/handle refers to a terminal/tty.
+ ///
+ /// On platforms where Rust does not know how to detect a terminal yet, this will return
+ /// `false`. This will also return `false` if an unexpected error occurred, such as from
+ /// passing an invalid file descriptor.
+ fn is_terminal(&self) -> bool;
+}
+
+macro_rules! impl_is_terminal {
+ ($($t:ty),*$(,)?) => {$(
+ #[unstable(feature = "sealed", issue = "none")]
+ impl crate::sealed::Sealed for $t {}
+
+ #[unstable(feature = "is_terminal", issue = "98070")]
+ impl IsTerminal for $t {
+ #[inline]
+ fn is_terminal(&self) -> bool {
+ crate::sys::io::is_terminal(self)
+ }
+ }
+ )*}
+}
+
+impl_is_terminal!(File, Stdin, StdinLock<'_>, Stdout, StdoutLock<'_>, Stderr, StderrLock<'_>);
+
#[unstable(
feature = "print_internals",
reason = "implementation detail which may disappear or be replaced at any time",