@@ -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