@@ -5,44 +5,38 @@ mod tests;
55
66use crate :: io:: prelude:: * ;
77
8- use crate :: cell:: RefCell ;
8+ use crate :: cell:: { Cell , RefCell } ;
99use crate :: fmt;
1010use crate :: io:: { self , BufReader , Initializer , IoSlice , IoSliceMut , LineWriter } ;
1111use crate :: lazy:: SyncOnceCell ;
1212use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
13- use crate :: sync:: { Mutex , MutexGuard } ;
13+ use crate :: sync:: { Arc , Mutex , MutexGuard } ;
1414use crate :: sys:: stdio;
1515use crate :: sys_common;
1616use crate :: sys_common:: remutex:: { ReentrantMutex , ReentrantMutexGuard } ;
17- use crate :: thread:: LocalKey ;
1817
19- thread_local ! {
20- /// Used by the test crate to capture the output of the print! and println! macros.
21- static LOCAL_STDOUT : RefCell <Option <Box <dyn LocalOutput >>> = {
22- RefCell :: new( None )
23- }
24- }
18+ type LocalStream = Arc < Mutex < Vec < u8 > > > ;
2519
2620thread_local ! {
27- /// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics.
28- static LOCAL_STDERR : RefCell <Option <Box <dyn LocalOutput > >> = {
29- RefCell :: new( None )
21+ /// Used by the test crate to capture the output of the print macros and panics.
22+ static OUTPUT_CAPTURE : Cell <Option <LocalStream >> = {
23+ Cell :: new( None )
3024 }
3125}
3226
33- /// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used.
27+ /// Flag to indicate OUTPUT_CAPTURE is used.
3428///
35- /// If both are None and were never set on any thread, this flag is set to
36- /// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all
37- /// threads, saving some time and memory registering an unused thread local.
29+ /// If it is None and was never set on any thread, this flag is set to false,
30+ /// and OUTPUT_CAPTURE can be safely ignored on all threads, saving some time
31+ /// and memory registering an unused thread local.
3832///
39- /// Note about memory ordering: This contains information about whether two
40- /// thread local variables might be in use. Although this is a global flag, the
33+ /// Note about memory ordering: This contains information about whether a
34+ /// thread local variable might be in use. Although this is a global flag, the
4135/// memory ordering between threads does not matter: we only want this flag to
42- /// have a consistent order between set_print/set_panic and print_to *within
36+ /// have a consistent order between set_output_capture and print_to *within
4337/// the same thread*. Within the same thread, things always have a perfectly
4438/// consistent order. So Ordering::Relaxed is fine.
45- static LOCAL_STREAMS : AtomicBool = AtomicBool :: new ( false ) ;
39+ static OUTPUT_CAPTURE_USED : AtomicBool = AtomicBool :: new ( false ) ;
4640
4741/// A handle to a raw instance of the standard input stream of this process.
4842///
@@ -896,97 +890,24 @@ impl fmt::Debug for StderrLock<'_> {
896890 }
897891}
898892
899- /// A writer than can be cloned to new threads.
900- #[ unstable(
901- feature = "set_stdio" ,
902- reason = "this trait may disappear completely or be replaced \
903- with a more general mechanism",
904- issue = "none"
905- ) ]
906- #[ doc( hidden) ]
907- pub trait LocalOutput : Write + Send {
908- fn clone_box ( & self ) -> Box < dyn LocalOutput > ;
909- }
910-
911- /// Resets the thread-local stderr handle to the specified writer
912- ///
913- /// This will replace the current thread's stderr handle, returning the old
914- /// handle. All future calls to `panic!` and friends will emit their output to
915- /// this specified handle.
916- ///
917- /// Note that this does not need to be called for all new threads; the default
918- /// output handle is to the process's stderr stream.
919- #[ unstable(
920- feature = "set_stdio" ,
921- reason = "this function may disappear completely or be replaced \
922- with a more general mechanism",
923- issue = "none"
924- ) ]
925- #[ doc( hidden) ]
926- pub fn set_panic ( sink : Option < Box < dyn LocalOutput > > ) -> Option < Box < dyn LocalOutput > > {
927- use crate :: mem;
928- if sink. is_none ( ) && !LOCAL_STREAMS . load ( Ordering :: Relaxed ) {
929- // LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
930- return None ;
931- }
932- let s = LOCAL_STDERR . with ( move |slot| mem:: replace ( & mut * slot. borrow_mut ( ) , sink) ) . and_then (
933- |mut s| {
934- let _ = s. flush ( ) ;
935- Some ( s)
936- } ,
937- ) ;
938- LOCAL_STREAMS . store ( true , Ordering :: Relaxed ) ;
939- s
940- }
941-
942- /// Resets the thread-local stdout handle to the specified writer
943- ///
944- /// This will replace the current thread's stdout handle, returning the old
945- /// handle. All future calls to `print!` and friends will emit their output to
946- /// this specified handle.
947- ///
948- /// Note that this does not need to be called for all new threads; the default
949- /// output handle is to the process's stdout stream.
893+ /// Sets the thread-local output capture buffer and returns the old one.
950894#[ unstable(
951- feature = "set_stdio " ,
952- reason = "this function may disappear completely or be replaced \
953- with a more general mechanism ",
895+ feature = "internal_output_capture " ,
896+ reason = "this function is meant for use in the test crate \
897+ and may disappear in the future ",
954898 issue = "none"
955899) ]
956900#[ doc( hidden) ]
957- pub fn set_print ( sink : Option < Box < dyn LocalOutput > > ) -> Option < Box < dyn LocalOutput > > {
958- use crate :: mem;
959- if sink. is_none ( ) && !LOCAL_STREAMS . load ( Ordering :: Relaxed ) {
960- // LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
901+ pub fn set_output_capture ( sink : Option < LocalStream > ) -> Option < LocalStream > {
902+ if sink. is_none ( ) && !OUTPUT_CAPTURE_USED . load ( Ordering :: Relaxed ) {
903+ // OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false.
961904 return None ;
962905 }
963- let s = LOCAL_STDOUT . with ( move |slot| mem:: replace ( & mut * slot. borrow_mut ( ) , sink) ) . and_then (
964- |mut s| {
965- let _ = s. flush ( ) ;
966- Some ( s)
967- } ,
968- ) ;
969- LOCAL_STREAMS . store ( true , Ordering :: Relaxed ) ;
970- s
971- }
972-
973- pub ( crate ) fn clone_io ( ) -> ( Option < Box < dyn LocalOutput > > , Option < Box < dyn LocalOutput > > ) {
974- // Don't waste time when LOCAL_{STDOUT,STDERR} are definitely None.
975- if !LOCAL_STREAMS . load ( Ordering :: Relaxed ) {
976- return ( None , None ) ;
977- }
978-
979- LOCAL_STDOUT . with ( |stdout| {
980- LOCAL_STDERR . with ( |stderr| {
981- (
982- stdout. borrow ( ) . as_ref ( ) . map ( |o| o. clone_box ( ) ) ,
983- stderr. borrow ( ) . as_ref ( ) . map ( |o| o. clone_box ( ) ) ,
984- )
985- } )
986- } )
906+ OUTPUT_CAPTURE_USED . store ( true , Ordering :: Relaxed ) ;
907+ OUTPUT_CAPTURE . with ( move |slot| slot. replace ( sink) )
987908}
988909
989- /// Write `args` to output stream `local_s` if possible, `global_s`
910+ /// Write `args` to the capture buffer if enabled and possible, or `global_s`
990911/// otherwise. `label` identifies the stream in a panic message.
991912///
992913/// This function is used to print error messages, so it takes extra
@@ -996,36 +917,26 @@ pub(crate) fn clone_io() -> (Option<Box<dyn LocalOutput>>, Option<Box<dyn LocalO
996917/// thread, it will just fall back to the global stream.
997918///
998919/// However, if the actual I/O causes an error, this function does panic.
999- fn print_to < T > (
1000- args : fmt:: Arguments < ' _ > ,
1001- local_s : & ' static LocalKey < RefCell < Option < Box < dyn LocalOutput > > > > ,
1002- global_s : fn ( ) -> T ,
1003- label : & str ,
1004- ) where
920+ fn print_to < T > ( args : fmt:: Arguments < ' _ > , global_s : fn ( ) -> T , label : & str )
921+ where
1005922 T : Write ,
1006923{
1007- let result = LOCAL_STREAMS
1008- . load ( Ordering :: Relaxed )
1009- . then ( || {
1010- local_s
1011- . try_with ( |s| {
1012- // Note that we completely remove a local sink to write to in case
1013- // our printing recursively panics/prints, so the recursive
1014- // panic/print goes to the global sink instead of our local sink.
1015- let prev = s. borrow_mut ( ) . take ( ) ;
1016- if let Some ( mut w) = prev {
1017- let result = w. write_fmt ( args) ;
1018- * s. borrow_mut ( ) = Some ( w) ;
1019- return result;
1020- }
1021- global_s ( ) . write_fmt ( args)
1022- } )
1023- . ok ( )
1024- } )
1025- . flatten ( )
1026- . unwrap_or_else ( || global_s ( ) . write_fmt ( args) ) ;
1027-
1028- if let Err ( e) = result {
924+ if OUTPUT_CAPTURE_USED . load ( Ordering :: Relaxed )
925+ && OUTPUT_CAPTURE . try_with ( |s| {
926+ // Note that we completely remove a local sink to write to in case
927+ // our printing recursively panics/prints, so the recursive
928+ // panic/print goes to the global sink instead of our local sink.
929+ s. take ( ) . map ( |w| {
930+ let _ = w. lock ( ) . unwrap_or_else ( |e| e. into_inner ( ) ) . write_fmt ( args) ;
931+ s. set ( Some ( w) ) ;
932+ } )
933+ } ) == Ok ( Some ( ( ) ) )
934+ {
935+ // Succesfully wrote to capture buffer.
936+ return ;
937+ }
938+
939+ if let Err ( e) = global_s ( ) . write_fmt ( args) {
1029940 panic ! ( "failed printing to {}: {}" , label, e) ;
1030941 }
1031942}
@@ -1038,7 +949,7 @@ fn print_to<T>(
1038949#[ doc( hidden) ]
1039950#[ cfg( not( test) ) ]
1040951pub fn _print ( args : fmt:: Arguments < ' _ > ) {
1041- print_to ( args, & LOCAL_STDOUT , stdout, "stdout" ) ;
952+ print_to ( args, stdout, "stdout" ) ;
1042953}
1043954
1044955#[ unstable(
@@ -1049,7 +960,7 @@ pub fn _print(args: fmt::Arguments<'_>) {
1049960#[ doc( hidden) ]
1050961#[ cfg( not( test) ) ]
1051962pub fn _eprint ( args : fmt:: Arguments < ' _ > ) {
1052- print_to ( args, & LOCAL_STDERR , stderr, "stderr" ) ;
963+ print_to ( args, stderr, "stderr" ) ;
1053964}
1054965
1055966#[ cfg( test) ]
0 commit comments