parent
6b9fbf212a
commit
d0d0e78208
14 changed files with 177 additions and 12 deletions
|
@ -213,13 +213,13 @@ impl<B: BufRead + ?Sized> BufRead for Box<B> {
|
|||
#[cfg(test)]
|
||||
/// This impl is only used by printing logic, so any error returned is always
|
||||
/// of kind `Other`, and should be ignored.
|
||||
impl Write for Box<dyn (::realstd::io::Write) + Send> {
|
||||
impl Write for dyn ::realstd::io::LocalOutput {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
(**self).write(buf).map_err(|_| ErrorKind::Other.into())
|
||||
(*self).write(buf).map_err(|_| ErrorKind::Other.into())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
(**self).flush().map_err(|_| ErrorKind::Other.into())
|
||||
(*self).flush().map_err(|_| ErrorKind::Other.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -277,10 +277,12 @@ pub use self::stdio::{StderrLock, StdinLock, StdoutLock};
|
|||
pub use self::stdio::{_eprint, _print};
|
||||
#[unstable(feature = "libstd_io_internals", issue = "42788")]
|
||||
#[doc(no_inline, hidden)]
|
||||
pub use self::stdio::{set_panic, set_print};
|
||||
pub use self::stdio::{set_panic, set_print, LocalOutput};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::util::{copy, empty, repeat, sink, Empty, Repeat, Sink};
|
||||
|
||||
pub(crate) use self::stdio::clone_io;
|
||||
|
||||
mod buffered;
|
||||
mod cursor;
|
||||
mod error;
|
||||
|
|
|
@ -18,14 +18,14 @@ use crate::thread::LocalKey;
|
|||
|
||||
thread_local! {
|
||||
/// Used by the test crate to capture the output of the print! and println! macros.
|
||||
static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
|
||||
static LOCAL_STDOUT: RefCell<Option<Box<dyn LocalOutput>>> = {
|
||||
RefCell::new(None)
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
/// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics.
|
||||
static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
|
||||
static LOCAL_STDERR: RefCell<Option<Box<dyn LocalOutput>>> = {
|
||||
RefCell::new(None)
|
||||
}
|
||||
}
|
||||
|
@ -888,6 +888,18 @@ impl fmt::Debug for StderrLock<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A writer than can be cloned to new threads.
|
||||
#[unstable(
|
||||
feature = "set_stdio",
|
||||
reason = "this trait may disappear completely or be replaced \
|
||||
with a more general mechanism",
|
||||
issue = "none"
|
||||
)]
|
||||
#[doc(hidden)]
|
||||
pub trait LocalOutput: Write + Send {
|
||||
fn clone_box(&self) -> Box<dyn LocalOutput>;
|
||||
}
|
||||
|
||||
/// Resets the thread-local stderr handle to the specified writer
|
||||
///
|
||||
/// This will replace the current thread's stderr handle, returning the old
|
||||
|
@ -903,7 +915,7 @@ impl fmt::Debug for StderrLock<'_> {
|
|||
issue = "none"
|
||||
)]
|
||||
#[doc(hidden)]
|
||||
pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
|
||||
pub fn set_panic(sink: Option<Box<dyn LocalOutput>>) -> Option<Box<dyn LocalOutput>> {
|
||||
use crate::mem;
|
||||
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
||||
// LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
|
||||
|
@ -934,7 +946,7 @@ pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write +
|
|||
issue = "none"
|
||||
)]
|
||||
#[doc(hidden)]
|
||||
pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
|
||||
pub fn set_print(sink: Option<Box<dyn LocalOutput>>) -> Option<Box<dyn LocalOutput>> {
|
||||
use crate::mem;
|
||||
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
||||
// LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
|
||||
|
@ -950,6 +962,17 @@ pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write +
|
|||
s
|
||||
}
|
||||
|
||||
pub(crate) fn clone_io() -> (Option<Box<dyn LocalOutput>>, Option<Box<dyn LocalOutput>>) {
|
||||
LOCAL_STDOUT.with(|stdout| {
|
||||
LOCAL_STDERR.with(|stderr| {
|
||||
(
|
||||
stdout.borrow().as_ref().map(|o| o.clone_box()),
|
||||
stderr.borrow().as_ref().map(|o| o.clone_box()),
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Write `args` to output stream `local_s` if possible, `global_s`
|
||||
/// otherwise. `label` identifies the stream in a panic message.
|
||||
///
|
||||
|
@ -962,7 +985,7 @@ pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write +
|
|||
/// However, if the actual I/O causes an error, this function does panic.
|
||||
fn print_to<T>(
|
||||
args: fmt::Arguments<'_>,
|
||||
local_s: &'static LocalKey<RefCell<Option<Box<dyn Write + Send>>>>,
|
||||
local_s: &'static LocalKey<RefCell<Option<Box<dyn LocalOutput>>>>,
|
||||
global_s: fn() -> T,
|
||||
label: &str,
|
||||
) where
|
||||
|
|
|
@ -220,7 +220,7 @@ fn default_hook(info: &PanicInfo<'_>) {
|
|||
|
||||
if let Some(mut local) = set_panic(None) {
|
||||
// NB. In `cfg(test)` this uses the forwarding impl
|
||||
// for `Box<dyn (::realstd::io::Write) + Send>`.
|
||||
// for `dyn ::realstd::io::LocalOutput`.
|
||||
write(&mut local);
|
||||
set_panic(Some(local));
|
||||
} else if let Some(mut out) = panic_output() {
|
||||
|
|
|
@ -457,11 +457,16 @@ impl Builder {
|
|||
let my_packet: Arc<UnsafeCell<Option<Result<T>>>> = Arc::new(UnsafeCell::new(None));
|
||||
let their_packet = my_packet.clone();
|
||||
|
||||
let (stdout, stderr) = crate::io::clone_io();
|
||||
|
||||
let main = move || {
|
||||
if let Some(name) = their_thread.cname() {
|
||||
imp::Thread::set_name(name);
|
||||
}
|
||||
|
||||
crate::io::set_print(stdout);
|
||||
crate::io::set_panic(stderr);
|
||||
|
||||
// SAFETY: the stack guard passed is the one for the current thread.
|
||||
// This means the current thread's stack and the new thread's stack
|
||||
// are properly set and protected from each other.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue