Skip to content

Commit 753966b

Browse files
committed
add Stdin::lines, Stdin::split forwarder methods
Add forwarder methods `Stdin::lines` and `Stdin::split`, which consume and lock a `Stdin` handle, and forward on to the corresponding `BufRead` methods. This should make it easier for beginners to use those iterator constructors without explicitly dealing with locks or lifetimes.
1 parent 8daad74 commit 753966b

File tree

1 file changed

+75
-8
lines changed

1 file changed

+75
-8
lines changed

library/std/src/io/stdio.rs

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::io::prelude::*;
77

88
use crate::cell::{Cell, RefCell};
99
use crate::fmt;
10-
use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter};
10+
use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Lines, Split};
1111
use crate::lazy::SyncOnceCell;
1212
use crate::pin::Pin;
1313
use crate::sync::atomic::{AtomicBool, Ordering};
@@ -195,17 +195,17 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
195195

196196
/// A handle to the standard input stream of a process.
197197
///
198-
/// Each handle is a shared reference to a global buffer of input data to this
199-
/// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods
200-
/// (e.g., `.lines()`). Reads to this handle are otherwise locked with respect
201-
/// to other reads.
198+
/// Each handle is a shared reference to a global buffer of input data to
199+
/// this process. Access is also synchronized via a lock, and explicit
200+
/// control over locking is available via the [`lock`] method.
202201
///
203202
/// This handle implements the `Read` trait, but beware that concurrent reads
204203
/// of `Stdin` must be executed with care.
205204
///
206205
/// Created by the [`io::stdin`] method.
207206
///
208207
/// [`io::stdin`]: stdin
208+
/// [`lock`]: Stdin::lock
209209
///
210210
/// ### Note: Windows Portability Consideration
211211
///
@@ -263,9 +263,16 @@ pub struct StdinLock<'a> {
263263

264264
/// Constructs a new handle to the standard input of the current process.
265265
///
266-
/// Each handle returned is a reference to a shared global buffer whose access
267-
/// is synchronized via a mutex. If you need more explicit control over
268-
/// locking, see the [`Stdin::lock`] method.
266+
/// Each handle returned is a reference to a shared global buffer whose
267+
/// access is synchronized via a mutex. The [`lines`], [`read_line`], and
268+
/// [`split`] methods, as well as all of the [`Read`] methods, implicitly
269+
/// lock the handle. If you need more explicit control over locking, or
270+
/// need to access the underlying [`BufRead`] implementation, see the
271+
/// [`Stdin::lock`] method.
272+
///
273+
/// [`lines`]: Stdin::lines
274+
/// [`read_line`]: Stdin::read_line
275+
/// [`split`]: Stdin::split
269276
///
270277
/// ### Note: Windows Portability Consideration
271278
/// When operating in a console, the Windows implementation of this stream does not support
@@ -367,6 +374,66 @@ impl Stdin {
367374
pub fn read_line(&self, buf: &mut String) -> io::Result<usize> {
368375
self.lock().read_line(buf)
369376
}
377+
378+
// Consumes a `Stdin` and returns a static `StdinLock`. This relies on
379+
// internal knowledge that the `Mutex` reference inside `Stdin` is
380+
// static.
381+
fn into_lock(self) -> StdinLock<'static> {
382+
StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
383+
}
384+
385+
/// Consumes this handle and returns an iterator over the input lines.
386+
///
387+
/// For detailed semantics of this method, see the documentation on
388+
/// [`BufRead::lines`].
389+
///
390+
/// # Examples
391+
///
392+
/// ```no_run
393+
/// #![feature(stdin_forwarders)]
394+
/// use std::io;
395+
///
396+
/// let lines = io::stdin().lines();
397+
/// for line in lines {
398+
/// println!("got a line: {}", line.unwrap());
399+
/// }
400+
/// ```
401+
#[unstable(
402+
feature = "stdin_forwarders",
403+
reason = "it can be useful to get a `Lines` iterator without having \
404+
to explicitly deal with locks and lifetimes",
405+
issue = "none"
406+
)]
407+
pub fn lines(self) -> Lines<StdinLock<'static>> {
408+
self.into_lock().lines()
409+
}
410+
411+
/// Consumes this handle and returns an iterator over input bytes,
412+
/// split at the specified byte value.
413+
///
414+
/// For detailed semantics of this method, see the documentation on
415+
/// [`BufRead::split`].
416+
///
417+
/// # Examples
418+
///
419+
/// ```no_run
420+
/// #![feature(stdin_forwarders)]
421+
/// use std::io;
422+
///
423+
/// let splits = io::stdin().split(b'-');
424+
/// for split in splits {
425+
/// println!("got a chunk: {}", String::from_utf8_lossy(&split.unwrap()));
426+
/// }
427+
/// ```
428+
#[unstable(
429+
feature = "stdin_forwarders",
430+
reason = "it can be useful to get a `Split` iterator without having \
431+
to explicitly deal with locks and lifetimes",
432+
issue = "none"
433+
)]
434+
pub fn split(self, byte: u8) -> Split<StdinLock<'static>> {
435+
self.into_lock().split(byte)
436+
}
370437
}
371438

372439
#[stable(feature = "std_debug", since = "1.16.0")]

0 commit comments

Comments
 (0)