tokio_stdin/
lib.rs

1//! *NOTE:* This library is no longer necessary. As of `tokio` 0.1.6, it is now possible to read
2//! from stdin without the overhead of spawning a separate thread with the `tokio::io::stdin`
3//! function.
4//!
5//! Read from stdin as a Tokio stream by spawning a separate thread.
6//!
7//! ```rust
8//! extern crate futures;
9//! extern crate tokio_stdin;
10//!
11//! fn main() {
12//!     use futures::Stream;
13//!
14//!     tokio_stdin::spawn_stdin_stream_unbounded().wait();
15//! }
16//! ```
17//!
18//! As far as I know, this is currently the recommended way to do this. On Dec 29, 2016,
19//! alexcrichton [commented](https://github.com/alexcrichton/tokio-process/issues/7):
20//!
21//! > In general for small CLI tools and such what you probably want to do is to use channels to
22//! > communicate to foreign threads. You can have a thread per stdin/stdout/stderr with a
23//! > `futures::sync::mpsc` that the main thread communicates with.
24//!
25//! This crate locks stdin while it's running, so trying to read from stdin in another part of your
26//! code will probably cause a deadlock.
27//!
28//! See the `count_keys` example for a simple use of this.
29#![deny(missing_docs)]
30#![deny(warnings)]
31// TODO `futures::stream::iter` is deprecated but will be restored as `futures::stream::iter_result`
32#![allow(deprecated)]
33extern crate futures;
34
35use futures::stream::iter;
36use futures::sync::mpsc::{channel, unbounded, Receiver, SendError, UnboundedReceiver};
37use futures::{Future, Sink, Stream};
38use std::io::{self, Read};
39use std::thread;
40
41#[derive(Debug)]
42enum Error {
43    Stdin(std::io::Error),
44    Channel(SendError<u8>),
45}
46
47/// Spawn a new thread that reads from stdin and passes messages back using a bounded channel.
48pub fn spawn_stdin_stream_bounded(buffer: usize) -> Receiver<u8> {
49    let (channel_sink, channel_stream) = channel(buffer);
50    let stdin_sink = channel_sink.sink_map_err(Error::Channel);
51
52    thread::spawn(move || {
53        let stdin = io::stdin();
54        let stdin_lock = stdin.lock();
55        iter(stdin_lock.bytes())
56            .map_err(Error::Stdin)
57            .forward(stdin_sink)
58            .wait()
59            .unwrap();
60    });
61
62    channel_stream
63}
64
65/// Spawn a new thread that reads from stdin and passes messages back using an unbounded channel.
66pub fn spawn_stdin_stream_unbounded() -> UnboundedReceiver<u8> {
67    let (channel_sink, channel_stream) = unbounded();
68    let stdin_sink = channel_sink.sink_map_err(Error::Channel);
69
70    thread::spawn(move || {
71        let stdin = io::stdin();
72        let stdin_lock = stdin.lock();
73        iter(stdin_lock.bytes())
74            .map_err(Error::Stdin)
75            .forward(stdin_sink)
76            .wait()
77            .unwrap();
78    });
79
80    channel_stream
81}