@@ -5,44 +5,38 @@ mod tests;
5
5
6
6
use crate :: io:: prelude:: * ;
7
7
8
- use crate :: cell:: RefCell ;
8
+ use crate :: cell:: { Cell , RefCell } ;
9
9
use crate :: fmt;
10
10
use crate :: io:: { self , BufReader , Initializer , IoSlice , IoSliceMut , LineWriter } ;
11
11
use crate :: lazy:: SyncOnceCell ;
12
12
use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
13
- use crate :: sync:: { Mutex , MutexGuard } ;
13
+ use crate :: sync:: { Arc , Mutex , MutexGuard } ;
14
14
use crate :: sys:: stdio;
15
15
use crate :: sys_common;
16
16
use crate :: sys_common:: remutex:: { ReentrantMutex , ReentrantMutexGuard } ;
17
- use crate :: thread:: LocalKey ;
18
17
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 > > > ;
25
19
26
20
thread_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 )
30
24
}
31
25
}
32
26
33
- /// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used.
27
+ /// Flag to indicate OUTPUT_CAPTURE is used.
34
28
///
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.
38
32
///
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
41
35
/// 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
43
37
/// the same thread*. Within the same thread, things always have a perfectly
44
38
/// consistent order. So Ordering::Relaxed is fine.
45
- static LOCAL_STREAMS : AtomicBool = AtomicBool :: new ( false ) ;
39
+ static OUTPUT_CAPTURE_USED : AtomicBool = AtomicBool :: new ( false ) ;
46
40
47
41
/// A handle to a raw instance of the standard input stream of this process.
48
42
///
@@ -896,97 +890,24 @@ impl fmt::Debug for StderrLock<'_> {
896
890
}
897
891
}
898
892
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.
950
894
#[ 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 ",
954
898
issue = "none"
955
899
) ]
956
900
#[ 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.
961
904
return None ;
962
905
}
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) )
987
908
}
988
909
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`
990
911
/// otherwise. `label` identifies the stream in a panic message.
991
912
///
992
913
/// 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
996
917
/// thread, it will just fall back to the global stream.
997
918
///
998
919
/// 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
1005
922
T : Write ,
1006
923
{
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) {
1029
940
panic ! ( "failed printing to {}: {}" , label, e) ;
1030
941
}
1031
942
}
@@ -1038,7 +949,7 @@ fn print_to<T>(
1038
949
#[ doc( hidden) ]
1039
950
#[ cfg( not( test) ) ]
1040
951
pub fn _print ( args : fmt:: Arguments < ' _ > ) {
1041
- print_to ( args, & LOCAL_STDOUT , stdout, "stdout" ) ;
952
+ print_to ( args, stdout, "stdout" ) ;
1042
953
}
1043
954
1044
955
#[ unstable(
@@ -1049,7 +960,7 @@ pub fn _print(args: fmt::Arguments<'_>) {
1049
960
#[ doc( hidden) ]
1050
961
#[ cfg( not( test) ) ]
1051
962
pub fn _eprint ( args : fmt:: Arguments < ' _ > ) {
1052
- print_to ( args, & LOCAL_STDERR , stderr, "stderr" ) ;
963
+ print_to ( args, stderr, "stderr" ) ;
1053
964
}
1054
965
1055
966
#[ cfg( test) ]
0 commit comments