@@ -261,6 +261,21 @@ pub struct StdinLock<'a> {
261261 inner : MutexGuard < ' a , BufReader < StdinRaw > > ,
262262}
263263
264+ /// Owned locked [`Stdin`] handle, returned by [`Stdin::into_lock`] and
265+ /// [`io::stdin_locked`].
266+ ///
267+ /// This is exactly like [`StdinLock`], except that it can outlive the
268+ /// [`Stdin`] handle that was used to create it. See the [`StdinLock`]
269+ /// documentation for more details.
270+ ///
271+ /// ### Note: Windows Portability Consideration
272+ ///
273+ /// When operating in a console, the Windows implementation of this stream does not support
274+ /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
275+ /// an error.
276+ #[ unstable( feature = "stdio_locked" , issue = "none" ) ]
277+ pub type StdinOwnedLock = StdinLock < ' static > ;
278+
264279/// Constructs a new handle to the standard input of the current process.
265280///
266281/// Each handle returned is a reference to a shared global buffer whose access
@@ -310,6 +325,48 @@ pub fn stdin() -> Stdin {
310325 }
311326}
312327
328+ /// Constructs a new locked handle to the standard input of the current
329+ /// process.
330+ ///
331+ /// Each handle returned is a guard granting locked access to a shared
332+ /// global buffer whose access is synchronized via a mutex. If you need
333+ /// more explicit control over locking, for example, in a multi-threaded
334+ /// program, use the [`io::stdin`] function to obtain an unlocked handle,
335+ /// along with the [`Stdin::lock`] method.
336+ ///
337+ /// The lock is released when the returned guard goes out of scope. The
338+ /// returned guard also implements the [`Read`] and [`BufRead`] traits for
339+ /// accessing the underlying data.
340+ ///
341+ /// **Note**: The mutex locked by this handle is not reentrant. Even in a
342+ /// single-threaded program, calling other code that accesses [`Stdin`]
343+ /// could cause a deadlock or panic, if this locked handle is held across
344+ /// that call.
345+ ///
346+ /// ### Note: Windows Portability Consideration
347+ /// When operating in a console, the Windows implementation of this stream does not support
348+ /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
349+ /// an error.
350+ ///
351+ /// # Examples
352+ ///
353+ /// ```no_run
354+ /// #![feature(stdio_locked)]
355+ /// use std::io::{self, Read};
356+ ///
357+ /// fn main() -> io::Result<()> {
358+ /// let mut buffer = String::new();
359+ /// let mut handle = io::stdin_locked();
360+ ///
361+ /// handle.read_to_string(&mut buffer)?;
362+ /// Ok(())
363+ /// }
364+ /// ```
365+ #[ unstable( feature = "stdio_locked" , issue = "none" ) ]
366+ pub fn stdin_locked ( ) -> StdinOwnedLock {
367+ stdin ( ) . into_lock ( )
368+ }
369+
313370impl Stdin {
314371 /// Locks this handle to the standard input stream, returning a readable
315372 /// guard.
@@ -334,7 +391,7 @@ impl Stdin {
334391 /// ```
335392 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
336393 pub fn lock ( & self ) -> StdinLock < ' _ > {
337- StdinLock { inner : self . inner . lock ( ) . unwrap_or_else ( |e| e . into_inner ( ) ) }
394+ self . lock_any ( )
338395 }
339396
340397 /// Locks this handle and reads a line of input, appending it to the specified buffer.
@@ -367,6 +424,43 @@ impl Stdin {
367424 pub fn read_line ( & self , buf : & mut String ) -> io:: Result < usize > {
368425 self . lock ( ) . read_line ( buf)
369426 }
427+
428+ // Locks this handle with any lifetime. This depends on the
429+ // implementation detail that the underlying `Mutex` is static.
430+ fn lock_any < ' a > ( & self ) -> StdinLock < ' a > {
431+ StdinLock { inner : self . inner . lock ( ) . unwrap_or_else ( |e| e. into_inner ( ) ) }
432+ }
433+
434+ /// Consumes this handle to the standard input stream, locking the
435+ /// shared global buffer associated with the stream and returning a
436+ /// readable guard.
437+ ///
438+ /// The lock is released when the returned guard goes out of scope. The
439+ /// returned guard also implements the [`Read`] and [`BufRead`] traits
440+ /// for accessing the underlying data.
441+ ///
442+ /// It is often simpler to directly get a locked handle using the
443+ /// [`stdin_locked`] function instead, unless nearby code also needs to
444+ /// use an unlocked handle.
445+ ///
446+ /// # Examples
447+ ///
448+ /// ```no_run
449+ /// #![feature(stdio_locked)]
450+ /// use std::io::{self, Read};
451+ ///
452+ /// fn main() -> io::Result<()> {
453+ /// let mut buffer = String::new();
454+ /// let mut handle = io::stdin().into_lock();
455+ ///
456+ /// handle.read_to_string(&mut buffer)?;
457+ /// Ok(())
458+ /// }
459+ /// ```
460+ #[ unstable( feature = "stdio_locked" , issue = "none" ) ]
461+ pub fn into_lock ( self ) -> StdinOwnedLock {
462+ self . lock_any ( )
463+ }
370464}
371465
372466#[ stable( feature = "std_debug" , since = "1.16.0" ) ]
@@ -507,6 +601,20 @@ pub struct StdoutLock<'a> {
507601 inner : ReentrantMutexGuard < ' a , RefCell < LineWriter < StdoutRaw > > > ,
508602}
509603
604+ /// Owned locked [`Stdout`] handle, returned by [`Stdout::into_lock`] and
605+ /// [`io::stdout_locked`].
606+ ///
607+ /// This is exactly like [`StdoutLock`], except that it can outlive the
608+ /// [`Stdout`] handle that was used to create it. See the [`StdoutLock`]
609+ /// documentation for more details.
610+ ///
611+ /// ### Note: Windows Portability Consideration
612+ /// When operating in a console, the Windows implementation of this stream does not support
613+ /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
614+ /// an error.
615+ #[ unstable( feature = "stdio_locked" , issue = "none" ) ]
616+ pub type StdoutOwnedLock = StdoutLock < ' static > ;
617+
510618static STDOUT : SyncOnceCell < ReentrantMutex < RefCell < LineWriter < StdoutRaw > > > > = SyncOnceCell :: new ( ) ;
511619
512620/// Constructs a new handle to the standard output of the current process.
@@ -558,6 +666,42 @@ pub fn stdout() -> Stdout {
558666 }
559667}
560668
669+ /// Constructs a new locked handle to the standard output of the current
670+ /// process.
671+ ///
672+ /// Each handle returned is a guard granting locked access to a shared
673+ /// global buffer whose access is synchronized via a mutex. If you need
674+ /// more explicit control over locking, for example, in a multi-threaded
675+ /// program, use the [`io::stdout`] function to obtain an unlocked handle,
676+ /// along with the [`Stdout::lock`] method.
677+ ///
678+ /// The lock is released when the returned guard goes out of scope. The
679+ /// returned guard also implements the [`Write`] trait for writing data.
680+ ///
681+ /// ### Note: Windows Portability Consideration
682+ /// When operating in a console, the Windows implementation of this stream does not support
683+ /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
684+ /// an error.
685+ ///
686+ /// # Examples
687+ ///
688+ /// ```no_run
689+ /// #![feature(stdio_locked)]
690+ /// use std::io::{self, Write};
691+ ///
692+ /// fn main() -> io::Result<()> {
693+ /// let mut handle = io::stdout_locked();
694+ ///
695+ /// handle.write_all(b"hello world")?;
696+ ///
697+ /// Ok(())
698+ /// }
699+ /// ```
700+ #[ unstable( feature = "stdio_locked" , issue = "none" ) ]
701+ pub fn stdout_locked ( ) -> StdoutLock < ' static > {
702+ stdout ( ) . into_lock ( )
703+ }
704+
561705pub fn cleanup ( ) {
562706 if let Some ( instance) = STDOUT . get ( ) {
563707 // Flush the data and disable buffering during shutdown
@@ -595,8 +739,45 @@ impl Stdout {
595739 /// ```
596740 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
597741 pub fn lock ( & self ) -> StdoutLock < ' _ > {
742+ self . lock_any ( )
743+ }
744+
745+ // Locks this handle with any lifetime. This depends on the
746+ // implementation detail that the underlying `ReentrantMutex` is
747+ // static.
748+ fn lock_any < ' a > ( & self ) -> StdoutLock < ' a > {
598749 StdoutLock { inner : self . inner . lock ( ) }
599750 }
751+
752+ /// Consumes this handle to the standard output stream, locking the
753+ /// shared global buffer associated with the stream and returning a
754+ /// writable guard.
755+ ///
756+ /// The lock is released when the returned lock goes out of scope. The
757+ /// returned guard also implements the [`Write`] trait for writing data.
758+ ///
759+ /// It is often simpler to directly get a locked handle using the
760+ /// [`io::stdout_locked`] function instead, unless nearby code also
761+ /// needs to use an unlocked handle.
762+ ///
763+ /// # Examples
764+ ///
765+ /// ```no_run
766+ /// #![feature(stdio_locked)]
767+ /// use std::io::{self, Write};
768+ ///
769+ /// fn main() -> io::Result<()> {
770+ /// let mut handle = io::stdout().into_lock();
771+ ///
772+ /// handle.write_all(b"hello world")?;
773+ ///
774+ /// Ok(())
775+ /// }
776+ /// ```
777+ #[ unstable( feature = "stdio_locked" , issue = "none" ) ]
778+ pub fn into_lock ( self ) -> StdoutOwnedLock {
779+ self . lock_any ( )
780+ }
600781}
601782
602783#[ stable( feature = "std_debug" , since = "1.16.0" ) ]
@@ -717,6 +898,20 @@ pub struct StderrLock<'a> {
717898 inner : ReentrantMutexGuard < ' a , RefCell < StderrRaw > > ,
718899}
719900
901+ /// Owned locked [`Stderr`] handle, returned by [`Stderr::into_lock`] and
902+ /// [`io::stderr_locked`].
903+ ///
904+ /// This is exactly like [`StderrLock`], except that it can outlive the the
905+ /// [`Stderr`] handle that was used to create it. See the [`StderrLock`]
906+ /// documentation for more details.
907+ ///
908+ /// ### Note: Windows Portability Consideration
909+ /// When operating in a console, the Windows implementation of this stream does not support
910+ /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
911+ /// an error.
912+ #[ unstable( feature = "stdio_locked" , issue = "none" ) ]
913+ pub type StderrOwnedLock = StderrLock < ' static > ;
914+
720915/// Constructs a new handle to the standard error of the current process.
721916///
722917/// This handle is not buffered.
@@ -769,6 +964,35 @@ pub fn stderr() -> Stderr {
769964 }
770965}
771966
967+ /// Constructs a new locked handle to the standard error of the current
968+ /// process.
969+ ///
970+ /// This handle is not buffered.
971+ ///
972+ /// ### Note: Windows Portability Consideration
973+ /// When operating in a console, the Windows implementation of this stream does not support
974+ /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
975+ /// an error.
976+ ///
977+ /// # Example
978+ ///
979+ /// ```no_run
980+ /// #![feature(stdio_locked)]
981+ /// use std::io::{self, Write};
982+ ///
983+ /// fn main() -> io::Result<()> {
984+ /// let mut handle = io::stderr_locked();
985+ ///
986+ /// handle.write_all(b"hello world")?;
987+ ///
988+ /// Ok(())
989+ /// }
990+ /// ```
991+ #[ unstable( feature = "stdio_locked" , issue = "none" ) ]
992+ pub fn stderr_locked ( ) -> StderrOwnedLock {
993+ stderr ( ) . into_lock ( )
994+ }
995+
772996impl Stderr {
773997 /// Locks this handle to the standard error stream, returning a writable
774998 /// guard.
@@ -792,8 +1016,42 @@ impl Stderr {
7921016 /// ```
7931017 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
7941018 pub fn lock ( & self ) -> StderrLock < ' _ > {
1019+ self . lock_any ( )
1020+ }
1021+
1022+ // Locks this handle with any lifetime. This depends on the
1023+ // implementation detail that the underlying `ReentrantMutex` is
1024+ // static.
1025+ fn lock_any < ' a > ( & self ) -> StderrLock < ' a > {
7951026 StderrLock { inner : self . inner . lock ( ) }
7961027 }
1028+
1029+ /// Locks and consumes this handle to the standard error stream,
1030+ /// returning a writable guard.
1031+ ///
1032+ /// The lock is released when the returned guard goes out of scope. The
1033+ /// returned guard also implements the [`Write`] trait for writing
1034+ /// data.
1035+ ///
1036+ /// # Examples
1037+ ///
1038+ /// ```
1039+ /// #![feature(stdio_locked)]
1040+ /// use std::io::{self, Write};
1041+ ///
1042+ /// fn foo() -> io::Result<()> {
1043+ /// let stderr = io::stderr();
1044+ /// let mut handle = stderr.into_lock();
1045+ ///
1046+ /// handle.write_all(b"hello world")?;
1047+ ///
1048+ /// Ok(())
1049+ /// }
1050+ /// ```
1051+ #[ unstable( feature = "stdio_locked" , issue = "none" ) ]
1052+ pub fn into_lock ( self ) -> StderrOwnedLock {
1053+ self . lock_any ( )
1054+ }
7971055}
7981056
7991057#[ stable( feature = "std_debug" , since = "1.16.0" ) ]
0 commit comments