@@ -26,6 +26,97 @@ thread_local! {
26
26
}
27
27
}
28
28
29
+ /// Stderr used by the default panic handler, eprint!, and eprintln! macros
30
+ thread_local ! {
31
+ pub ( crate ) static LOCAL_STDERR : RefCell <Option <Box <Write + Send >>> = {
32
+ RefCell :: new( None )
33
+ }
34
+ }
35
+
36
+ /// Get a handle to the `local` output stream if possible,
37
+ /// falling back to using `global` otherwise.
38
+ ///
39
+ /// This function is used to print error messages, so it takes extra
40
+ /// care to avoid causing a panic when `local_stream` is unusable.
41
+ /// For instance, if the TLS key for the local stream is
42
+ /// already destroyed, or if the local stream is locked by another
43
+ /// thread, it will just fall back to the global stream.
44
+ #[ inline]
45
+ fn with_write < W : Write , R , F : Fn ( & mut io:: Write ) -> R > (
46
+ local : & ' static LocalKey < RefCell < Option < Box < Write +Send > > > > ,
47
+ global : fn ( ) -> W ,
48
+ f : F ,
49
+ ) -> R {
50
+ local. try_with ( |s| {
51
+ if let Ok ( mut borrowed) = s. try_borrow_mut ( ) {
52
+ if let Some ( w) = borrowed. as_mut ( ) {
53
+ return f ( w) ;
54
+ }
55
+ }
56
+ f ( & mut global ( ) )
57
+ } ) . unwrap_or_else ( |_| {
58
+ f ( & mut global ( ) )
59
+ } )
60
+ }
61
+
62
+ /// A `Write` handle that is usually the same as using [`io::stdout()`],
63
+ /// but is overridden during test runs thread-locally to capture output.
64
+ /// This is how `println!` family macros work during test runs.
65
+ #[ unstable( feature = "set_stdio" ,
66
+ reason = "this may disappear completely or be replaced \
67
+ with a more general mechanism",
68
+ issue = "0" ) ]
69
+ #[ derive( Debug ) ]
70
+ pub struct LocalStdout ;
71
+
72
+ /// A `Write` handle that is usually the same as using [`io::stderr()`],
73
+ /// but is overridden during test runs thread-locally to capture output.
74
+ /// This is how `eprintln!` family macros work during test runs.
75
+ #[ unstable( feature = "set_stdio" ,
76
+ reason = "this may disappear completely or be replaced \
77
+ with a more general mechanism",
78
+ issue = "0" ) ]
79
+ #[ derive( Debug ) ]
80
+ pub struct LocalStderr ;
81
+
82
+ #[ unstable( feature = "set_stdio" ,
83
+ reason = "this may disappear completely or be replaced \
84
+ with a more general mechanism",
85
+ issue = "0" ) ]
86
+ impl Write for LocalStdout {
87
+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
88
+ with_write ( & LOCAL_STDOUT , stdout, move |w| w. write ( buf) )
89
+ }
90
+ fn flush ( & mut self ) -> io:: Result < ( ) > {
91
+ with_write ( & LOCAL_STDOUT , stdout, move |w| w. flush ( ) )
92
+ }
93
+ fn write_all ( & mut self , buf : & [ u8 ] ) -> io:: Result < ( ) > {
94
+ with_write ( & LOCAL_STDOUT , stdout, move |w| w. write_all ( buf) )
95
+ }
96
+ fn write_fmt ( & mut self , fmt : fmt:: Arguments ) -> io:: Result < ( ) > {
97
+ with_write ( & LOCAL_STDOUT , stdout, move |w| w. write_fmt ( fmt) )
98
+ }
99
+ }
100
+
101
+ #[ unstable( feature = "set_stdio" ,
102
+ reason = "this may disappear completely or be replaced \
103
+ with a more general mechanism",
104
+ issue = "0" ) ]
105
+ impl Write for LocalStderr {
106
+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
107
+ with_write ( & LOCAL_STDERR , stderr, move |w| w. write ( buf) )
108
+ }
109
+ fn flush ( & mut self ) -> io:: Result < ( ) > {
110
+ with_write ( & LOCAL_STDERR , stderr, move |w| w. flush ( ) )
111
+ }
112
+ fn write_all ( & mut self , buf : & [ u8 ] ) -> io:: Result < ( ) > {
113
+ with_write ( & LOCAL_STDERR , stderr, move |w| w. write_all ( buf) )
114
+ }
115
+ fn write_fmt ( & mut self , fmt : fmt:: Arguments ) -> io:: Result < ( ) > {
116
+ with_write ( & LOCAL_STDERR , stderr, move |w| w. write_fmt ( fmt) )
117
+ }
118
+ }
119
+
29
120
/// A handle to a raw instance of the standard input stream of this process.
30
121
///
31
122
/// This handle is not synchronized or buffered in any fashion. Constructed via
@@ -625,7 +716,6 @@ impl<'a> fmt::Debug for StderrLock<'a> {
625
716
issue = "0" ) ]
626
717
#[ doc( hidden) ]
627
718
pub fn set_panic ( sink : Option < Box < Write + Send > > ) -> Option < Box < Write + Send > > {
628
- use panicking:: LOCAL_STDERR ;
629
719
use mem;
630
720
LOCAL_STDERR . with ( move |slot| {
631
721
mem:: replace ( & mut * slot. borrow_mut ( ) , sink)
@@ -658,56 +748,22 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
658
748
} )
659
749
}
660
750
661
- /// Write `args` to output stream `local_s` if possible, `global_s`
662
- /// otherwise. `label` identifies the stream in a panic message.
663
- ///
664
- /// This function is used to print error messages, so it takes extra
665
- /// care to avoid causing a panic when `local_stream` is unusable.
666
- /// For instance, if the TLS key for the local stream is
667
- /// already destroyed, or if the local stream is locked by another
668
- /// thread, it will just fall back to the global stream.
669
- ///
670
- /// However, if the actual I/O causes an error, this function does panic.
671
- fn print_to < T > (
672
- args : fmt:: Arguments ,
673
- local_s : & ' static LocalKey < RefCell < Option < Box < Write +Send > > > > ,
674
- global_s : fn ( ) -> T ,
675
- label : & str ,
676
- )
677
- where
678
- T : Write ,
679
- {
680
- let result = local_s. try_with ( |s| {
681
- if let Ok ( mut borrowed) = s. try_borrow_mut ( ) {
682
- if let Some ( w) = borrowed. as_mut ( ) {
683
- return w. write_fmt ( args) ;
684
- }
685
- }
686
- global_s ( ) . write_fmt ( args)
687
- } ) . unwrap_or_else ( |_| {
688
- global_s ( ) . write_fmt ( args)
689
- } ) ;
690
-
691
- if let Err ( e) = result {
692
- panic ! ( "failed printing to {}: {}" , label, e) ;
693
- }
694
- }
695
-
696
751
#[ unstable( feature = "print_internals" ,
697
752
reason = "implementation detail which may disappear or be replaced at any time" ,
698
753
issue = "0" ) ]
699
754
#[ doc( hidden) ]
700
755
pub fn _print ( args : fmt:: Arguments ) {
701
- print_to ( args, & LOCAL_STDOUT , stdout, "stdout" ) ;
756
+ LocalStdout . write_fmt ( args)
757
+ . unwrap_or_else ( |e| panic ! ( "failed printing to stdout: {}" , e) ) ;
702
758
}
703
759
704
760
#[ unstable( feature = "print_internals" ,
705
761
reason = "implementation detail which may disappear or be replaced at any time" ,
706
762
issue = "0" ) ]
707
763
#[ doc( hidden) ]
708
764
pub fn _eprint ( args : fmt:: Arguments ) {
709
- use panicking :: LOCAL_STDERR ;
710
- print_to ( args , & LOCAL_STDERR , stderr, "stderr" ) ;
765
+ LocalStderr . write_fmt ( args )
766
+ . unwrap_or_else ( |e| panic ! ( "failed printing to stderr: {}" , e ) ) ;
711
767
}
712
768
713
769
#[ cfg( test) ]
0 commit comments