@@ -8,8 +8,10 @@ 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} ; 
14+ use  crate :: os:: fd:: { AsFd ,  BorrowedFd } ; 
1315use  crate :: panic:: { RefUnwindSafe ,  UnwindSafe } ; 
1416use  crate :: sync:: atomic:: { Atomic ,  AtomicBool ,  Ordering } ; 
1517use  crate :: sync:: { Arc ,  Mutex ,  MutexGuard ,  OnceLock ,  ReentrantLock ,  ReentrantLockGuard } ; 
@@ -168,6 +170,13 @@ impl Write for StdoutRaw {
168170    } 
169171} 
170172
173+ impl  AsFd  for  StdoutRaw  { 
174+     #[ inline]  
175+     fn  as_fd ( & self )  -> BorrowedFd < ' _ >  { 
176+         unsafe  {  BorrowedFd :: borrow_raw ( 1 )  } 
177+     } 
178+ } 
179+ 
171180impl  Write  for  StderrRaw  { 
172181    fn  write ( & mut  self ,  buf :  & [ u8 ] )  -> io:: Result < usize >  { 
173182        handle_ebadf ( self . 0 . write ( buf) ,  || Ok ( buf. len ( ) ) ) 
@@ -200,6 +209,13 @@ impl Write for StderrRaw {
200209    } 
201210} 
202211
212+ impl  AsFd  for  StderrRaw  { 
213+     #[ inline]  
214+     fn  as_fd ( & self )  -> BorrowedFd < ' _ >  { 
215+         unsafe  {  BorrowedFd :: borrow_raw ( 2 )  } 
216+     } 
217+ } 
218+ 
203219fn  handle_ebadf < T > ( r :  io:: Result < T > ,  default :  impl  FnOnce ( )  -> io:: Result < T > )  -> io:: Result < T >  { 
204220    match  r { 
205221        Err ( ref  e)  if  stdio:: is_ebadf ( e)  => default ( ) , 
@@ -576,6 +592,76 @@ impl fmt::Debug for StdinLock<'_> {
576592    } 
577593} 
578594
595+ /// A buffered writer for stdout and stderr. 
596+ /// 
597+ /// This writer may be either [line-buffered](LineWriter) or [block-buffered](BufWriter), depending 
598+ /// on whether the underlying file is a terminal or not. 
599+ #[ derive( Debug ) ]  
600+ enum  StdioBufWriter < W :  Write >  { 
601+     LineBuffered ( LineWriter < W > ) , 
602+     BlockBuffered ( BufWriter < W > ) , 
603+ } 
604+ 
605+ impl < W :  Write  + IsTerminal >  StdioBufWriter < W >  { 
606+     /// Wraps a writer using the most appropriate buffering method. 
607+ /// 
608+ /// If `w` is a terminal, then the resulting `StdioBufWriter` will be line-buffered, otherwise 
609+ /// it will be block-buffered. 
610+ fn  new ( w :  W )  -> Self  { 
611+         if  w. is_terminal ( )  { 
612+             Self :: LineBuffered ( LineWriter :: new ( w) ) 
613+         }  else  { 
614+             Self :: BlockBuffered ( BufWriter :: new ( w) ) 
615+         } 
616+     } 
617+ } 
618+ 
619+ impl < W :  Write >  StdioBufWriter < W >  { 
620+     /// Wraps a writer using a block-buffer with the given capacity. 
621+ fn  with_capacity ( cap :  usize ,  w :  W )  -> Self  { 
622+         Self :: BlockBuffered ( BufWriter :: with_capacity ( cap,  w) ) 
623+     } 
624+ } 
625+ 
626+ impl < W :  Write >  Write  for  StdioBufWriter < W >  { 
627+     fn  write ( & mut  self ,  buf :  & [ u8 ] )  -> io:: Result < usize >  { 
628+         match  self  { 
629+             Self :: LineBuffered ( w)  => w. write ( buf) , 
630+             Self :: BlockBuffered ( w)  => w. write ( buf) , 
631+         } 
632+     } 
633+     fn  write_vectored ( & mut  self ,  bufs :  & [ IoSlice < ' _ > ] )  -> io:: Result < usize >  { 
634+         match  self  { 
635+             Self :: LineBuffered ( w)  => w. write_vectored ( bufs) , 
636+             Self :: BlockBuffered ( w)  => w. write_vectored ( bufs) , 
637+         } 
638+     } 
639+     fn  is_write_vectored ( & self )  -> bool  { 
640+         match  self  { 
641+             Self :: LineBuffered ( w)  => w. is_write_vectored ( ) , 
642+             Self :: BlockBuffered ( w)  => w. is_write_vectored ( ) , 
643+         } 
644+     } 
645+     fn  flush ( & mut  self )  -> io:: Result < ( ) >  { 
646+         match  self  { 
647+             Self :: LineBuffered ( w)  => w. flush ( ) , 
648+             Self :: BlockBuffered ( w)  => w. flush ( ) , 
649+         } 
650+     } 
651+     fn  write_all ( & mut  self ,  buf :  & [ u8 ] )  -> io:: Result < ( ) >  { 
652+         match  self  { 
653+             Self :: LineBuffered ( w)  => w. write_all ( buf) , 
654+             Self :: BlockBuffered ( w)  => w. write_all ( buf) , 
655+         } 
656+     } 
657+     fn  write_all_vectored ( & mut  self ,  bufs :  & mut  [ IoSlice < ' _ > ] )  -> io:: Result < ( ) >  { 
658+         match  self  { 
659+             Self :: LineBuffered ( w)  => w. write_all_vectored ( bufs) , 
660+             Self :: BlockBuffered ( w)  => w. write_all_vectored ( bufs) , 
661+         } 
662+     } 
663+ } 
664+ 
579665/// A handle to the global standard output stream of the current process. 
580666/// 
581667/// Each handle shares a global buffer of data to be written to the standard 
@@ -606,10 +692,9 @@ impl fmt::Debug for StdinLock<'_> {
606692/// [`io::stdout`]: stdout 
607693#[ stable( feature = "rust1" ,  since = "1.0.0" ) ]  
608694pub  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 > > > , 
695+     // FIXME: if this is not line buffered it should flush-on-panic or some 
696+     //        form of flush-on-abort. 
697+     inner :  & ' static  ReentrantLock < RefCell < StdioBufWriter < StdoutRaw > > > , 
613698} 
614699
615700/// A locked reference to the [`Stdout`] handle. 
@@ -638,10 +723,10 @@ pub struct Stdout {
638723#[ must_use = "if unused stdout will immediately unlock" ]  
639724#[ stable( feature = "rust1" ,  since = "1.0.0" ) ]  
640725pub  struct  StdoutLock < ' a >  { 
641-     inner :  ReentrantLockGuard < ' a ,  RefCell < LineWriter < StdoutRaw > > > , 
726+     inner :  ReentrantLockGuard < ' a ,  RefCell < StdioBufWriter < StdoutRaw > > > , 
642727} 
643728
644- static  STDOUT :  OnceLock < ReentrantLock < RefCell < LineWriter < StdoutRaw > > > >  = OnceLock :: new ( ) ; 
729+ static  STDOUT :  OnceLock < ReentrantLock < RefCell < StdioBufWriter < StdoutRaw > > > >  = OnceLock :: new ( ) ; 
645730
646731/// Constructs a new handle to the standard output of the current process. 
647732/// 
@@ -716,7 +801,7 @@ static STDOUT: OnceLock<ReentrantLock<RefCell<LineWriter<StdoutRaw>>>> = OnceLoc
716801pub  fn  stdout ( )  -> Stdout  { 
717802    Stdout  { 
718803        inner :  STDOUT 
719-             . get_or_init ( || ReentrantLock :: new ( RefCell :: new ( LineWriter :: new ( stdout_raw ( ) ) ) ) ) , 
804+             . get_or_init ( || ReentrantLock :: new ( RefCell :: new ( StdioBufWriter :: new ( stdout_raw ( ) ) ) ) ) , 
720805    } 
721806} 
722807
@@ -727,7 +812,7 @@ pub fn cleanup() {
727812    let  mut  initialized = false ; 
728813    let  stdout = STDOUT . get_or_init ( || { 
729814        initialized = true ; 
730-         ReentrantLock :: new ( RefCell :: new ( LineWriter :: with_capacity ( 0 ,  stdout_raw ( ) ) ) ) 
815+         ReentrantLock :: new ( RefCell :: new ( StdioBufWriter :: with_capacity ( 0 ,  stdout_raw ( ) ) ) ) 
731816    } ) ; 
732817
733818    if  !initialized { 
@@ -736,7 +821,7 @@ pub fn cleanup() {
736821        // might have leaked a StdoutLock, which would 
737822        // otherwise cause a deadlock here. 
738823        if  let  Some ( lock)  = stdout. try_lock ( )  { 
739-             * lock. borrow_mut ( )  = LineWriter :: with_capacity ( 0 ,  stdout_raw ( ) ) ; 
824+             * lock. borrow_mut ( )  = StdioBufWriter :: with_capacity ( 0 ,  stdout_raw ( ) ) ; 
740825        } 
741826    } 
742827} 
@@ -1262,7 +1347,17 @@ macro_rules! impl_is_terminal {
12621347    ) * } 
12631348} 
12641349
1265- impl_is_terminal ! ( File ,  Stdin ,  StdinLock <' _>,  Stdout ,  StdoutLock <' _>,  Stderr ,  StderrLock <' _>) ; 
1350+ impl_is_terminal ! ( 
1351+     File , 
1352+     Stdin , 
1353+     StdinLock <' _>, 
1354+     Stdout , 
1355+     StdoutLock <' _>, 
1356+     StdoutRaw , 
1357+     Stderr , 
1358+     StderrLock <' _>, 
1359+     StderrRaw 
1360+ ) ; 
12661361
12671362#[ unstable(  
12681363    feature = "print_internals" ,  
0 commit comments