@@ -8,7 +8,8 @@ use crate::fmt;
88use crate :: fs:: File ;
99use crate :: io:: prelude:: * ;
1010use crate :: io:: {
11- self , BorrowedCursor , BufReader , IoSlice , IoSliceMut , LineWriter , Lines , SpecReadByte ,
11+ self , BorrowedCursor , BufReader , BufWriter , IoSlice , IoSliceMut , LineWriter , Lines ,
12+ SpecReadByte ,
1213} ;
1314use crate :: panic:: { RefUnwindSafe , UnwindSafe } ;
1415use crate :: sync:: atomic:: { Atomic , AtomicBool , Ordering } ;
@@ -168,6 +169,20 @@ impl Write for StdoutRaw {
168169 }
169170}
170171
172+ #[ cfg( any(
173+ unix,
174+ target_os = "hermit" ,
175+ target_os = "trusty" ,
176+ target_os = "wasi" ,
177+ target_os = "motor" ,
178+ ) ) ]
179+ impl crate :: os:: fd:: AsFd for StdoutRaw {
180+ #[ inline]
181+ fn as_fd ( & self ) -> crate :: os:: fd:: BorrowedFd < ' _ > {
182+ unsafe { crate :: os:: fd:: BorrowedFd :: borrow_raw ( 1 ) }
183+ }
184+ }
185+
171186impl Write for StderrRaw {
172187 fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
173188 handle_ebadf ( self . 0 . write ( buf) , || Ok ( buf. len ( ) ) )
@@ -576,6 +591,76 @@ impl fmt::Debug for StdinLock<'_> {
576591 }
577592}
578593
594+ /// A buffered writer for stdout and stderr.
595+ ///
596+ /// This writer may be either [line-buffered](LineWriter) or [block-buffered](BufWriter), depending
597+ /// on whether the underlying file is a terminal or not.
598+ #[ derive( Debug ) ]
599+ enum StdioBufWriter < W : Write > {
600+ LineBuffered ( LineWriter < W > ) ,
601+ BlockBuffered ( BufWriter < W > ) ,
602+ }
603+
604+ impl < W : Write + IsTerminal > StdioBufWriter < W > {
605+ /// Wraps a writer using the most appropriate buffering method.
606+ ///
607+ /// If `w` is a terminal, then the resulting `StdioBufWriter` will be line-buffered, otherwise
608+ /// it will be block-buffered.
609+ fn new ( w : W ) -> Self {
610+ if w. is_terminal ( ) {
611+ Self :: LineBuffered ( LineWriter :: new ( w) )
612+ } else {
613+ Self :: BlockBuffered ( BufWriter :: new ( w) )
614+ }
615+ }
616+ }
617+
618+ impl < W : Write > StdioBufWriter < W > {
619+ /// Wraps a writer using a block-buffer with the given capacity.
620+ fn with_capacity ( cap : usize , w : W ) -> Self {
621+ Self :: BlockBuffered ( BufWriter :: with_capacity ( cap, w) )
622+ }
623+ }
624+
625+ impl < W : Write > Write for StdioBufWriter < W > {
626+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
627+ match self {
628+ Self :: LineBuffered ( w) => w. write ( buf) ,
629+ Self :: BlockBuffered ( w) => w. write ( buf) ,
630+ }
631+ }
632+ fn write_vectored ( & mut self , bufs : & [ IoSlice < ' _ > ] ) -> io:: Result < usize > {
633+ match self {
634+ Self :: LineBuffered ( w) => w. write_vectored ( bufs) ,
635+ Self :: BlockBuffered ( w) => w. write_vectored ( bufs) ,
636+ }
637+ }
638+ fn is_write_vectored ( & self ) -> bool {
639+ match self {
640+ Self :: LineBuffered ( w) => w. is_write_vectored ( ) ,
641+ Self :: BlockBuffered ( w) => w. is_write_vectored ( ) ,
642+ }
643+ }
644+ fn flush ( & mut self ) -> io:: Result < ( ) > {
645+ match self {
646+ Self :: LineBuffered ( w) => w. flush ( ) ,
647+ Self :: BlockBuffered ( w) => w. flush ( ) ,
648+ }
649+ }
650+ fn write_all ( & mut self , buf : & [ u8 ] ) -> io:: Result < ( ) > {
651+ match self {
652+ Self :: LineBuffered ( w) => w. write_all ( buf) ,
653+ Self :: BlockBuffered ( w) => w. write_all ( buf) ,
654+ }
655+ }
656+ fn write_all_vectored ( & mut self , bufs : & mut [ IoSlice < ' _ > ] ) -> io:: Result < ( ) > {
657+ match self {
658+ Self :: LineBuffered ( w) => w. write_all_vectored ( bufs) ,
659+ Self :: BlockBuffered ( w) => w. write_all_vectored ( bufs) ,
660+ }
661+ }
662+ }
663+
579664/// A handle to the global standard output stream of the current process.
580665///
581666/// Each handle shares a global buffer of data to be written to the standard
@@ -606,10 +691,9 @@ impl fmt::Debug for StdinLock<'_> {
606691/// [`io::stdout`]: stdout
607692#[ stable( feature = "rust1" , since = "1.0.0" ) ]
608693pub struct Stdout {
609- // FIXME: this should be LineWriter or BufWriter depending on the state of
610- // stdout (tty or not). Note that if this is not line buffered it
611- // should also flush-on-panic or some form of flush-on-abort.
612- inner : & ' static ReentrantLock < RefCell < LineWriter < StdoutRaw > > > ,
694+ // FIXME: if this is not line buffered it should flush-on-panic or some
695+ // form of flush-on-abort.
696+ inner : & ' static ReentrantLock < RefCell < StdioBufWriter < StdoutRaw > > > ,
613697}
614698
615699/// A locked reference to the [`Stdout`] handle.
@@ -638,10 +722,10 @@ pub struct Stdout {
638722#[ must_use = "if unused stdout will immediately unlock" ]
639723#[ stable( feature = "rust1" , since = "1.0.0" ) ]
640724pub struct StdoutLock < ' a > {
641- inner : ReentrantLockGuard < ' a , RefCell < LineWriter < StdoutRaw > > > ,
725+ inner : ReentrantLockGuard < ' a , RefCell < StdioBufWriter < StdoutRaw > > > ,
642726}
643727
644- static STDOUT : OnceLock < ReentrantLock < RefCell < LineWriter < StdoutRaw > > > > = OnceLock :: new ( ) ;
728+ static STDOUT : OnceLock < ReentrantLock < RefCell < StdioBufWriter < StdoutRaw > > > > = OnceLock :: new ( ) ;
645729
646730/// Constructs a new handle to the standard output of the current process.
647731///
@@ -716,7 +800,7 @@ static STDOUT: OnceLock<ReentrantLock<RefCell<LineWriter<StdoutRaw>>>> = OnceLoc
716800pub fn stdout ( ) -> Stdout {
717801 Stdout {
718802 inner : STDOUT
719- . get_or_init ( || ReentrantLock :: new ( RefCell :: new ( LineWriter :: new ( stdout_raw ( ) ) ) ) ) ,
803+ . get_or_init ( || ReentrantLock :: new ( RefCell :: new ( StdioBufWriter :: new ( stdout_raw ( ) ) ) ) ) ,
720804 }
721805}
722806
@@ -727,7 +811,7 @@ pub fn cleanup() {
727811 let mut initialized = false ;
728812 let stdout = STDOUT . get_or_init ( || {
729813 initialized = true ;
730- ReentrantLock :: new ( RefCell :: new ( LineWriter :: with_capacity ( 0 , stdout_raw ( ) ) ) )
814+ ReentrantLock :: new ( RefCell :: new ( StdioBufWriter :: with_capacity ( 0 , stdout_raw ( ) ) ) )
731815 } ) ;
732816
733817 if !initialized {
@@ -736,7 +820,7 @@ pub fn cleanup() {
736820 // might have leaked a StdoutLock, which would
737821 // otherwise cause a deadlock here.
738822 if let Some ( lock) = stdout. try_lock ( ) {
739- * lock. borrow_mut ( ) = LineWriter :: with_capacity ( 0 , stdout_raw ( ) ) ;
823+ * lock. borrow_mut ( ) = StdioBufWriter :: with_capacity ( 0 , stdout_raw ( ) ) ;
740824 }
741825 }
742826}
@@ -1262,7 +1346,16 @@ macro_rules! impl_is_terminal {
12621346 ) * }
12631347}
12641348
1265- impl_is_terminal ! ( File , Stdin , StdinLock <' _>, Stdout , StdoutLock <' _>, Stderr , StderrLock <' _>) ;
1349+ impl_is_terminal ! (
1350+ File ,
1351+ Stdin ,
1352+ StdinLock <' _>,
1353+ Stdout ,
1354+ StdoutLock <' _>,
1355+ StdoutRaw ,
1356+ Stderr ,
1357+ StderrLock <' _>,
1358+ ) ;
12661359
12671360#[ unstable(
12681361 feature = "print_internals" ,
0 commit comments