blob: d535a61b451f70b326a01878fb2a12b9cbdf7648 [file] [log] [blame]
use futures::channel::mpsc;
use futures::executor; //standard executors to provide a context for futures and streams
use futures::executor::ThreadPool;
use futures::StreamExt;
fn main() {
let pool = ThreadPool::new().expect("Failed to build pool");
let (tx, rx) = mpsc::unbounded::<i32>();
// Create a future by an async block, where async is responsible for an
// implementation of Future. At this point no executor has been provided
// to this future, so it will not be running.
let fut_values = async {
// Create another async block, again where the Future implementation
// is generated by async. Since this is inside of a parent async block,
// it will be provided with the executor of the parent block when the parent
// block is executed.
//
// This executor chaining is done by Future::poll whose second argument
// is a std::task::Context. This represents our executor, and the Future
// implemented by this async block can be polled using the parent async
// block's executor.
let fut_tx_result = async move {
(0..100).for_each(|v| {
tx.unbounded_send(v).expect("Failed to send");
})
};
// Use the provided thread pool to spawn the generated future
// responsible for transmission
pool.spawn_ok(fut_tx_result);
let fut_values = rx.map(|v| v * 2).collect();
// Use the executor provided to this async block to wait for the
// future to complete.
fut_values.await
};
// Actually execute the above future, which will invoke Future::poll and
// subsequently chain appropriate Future::poll and methods needing executors
// to drive all futures. Eventually fut_values will be driven to completion.
let values: Vec<i32> = executor::block_on(fut_values);
println!("Values={values:?}");
}