Skip to content

Commit

Permalink
Lib.rs Example and Async Block Callout (#1203)
Browse files Browse the repository at this point in the history
Add a more complete example to lib.rs, and callout that examples and snippets
in the crate use an async block.
  • Loading branch information
Danny Browning authored and cramertj committed Nov 14, 2019
1 parent 6b4ddd9 commit 260f76b
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Expand Up @@ -10,4 +10,6 @@ members = [
"futures-task",
"futures-util",
"futures-test",
"futures/examples/functional",
"futures/examples/imperative"
]
1 change: 1 addition & 0 deletions futures/Cargo.toml
Expand Up @@ -32,6 +32,7 @@ futures-util = { path = "../futures-util", version = "0.3.1", default-features =

[dev-dependencies]
pin-utils = "0.1.0-alpha.4"
futures-executor = { path = "../futures-executor", version = "0.3.1", features = ["thread-pool"] }
futures-test = { path = "../futures-test", version = "0.3.1" }
tokio = "0.1.11"
assert_matches = "1.3.0"
Expand Down
19 changes: 19 additions & 0 deletions futures/examples/functional/Cargo.toml
@@ -0,0 +1,19 @@
[package]
name = "futures-example-functional"
edition = "2018"
version = "0.3.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
license = "MIT OR Apache-2.0"
readme = "../README.md"
keywords = ["futures", "async", "future"]
repository = "https://github.com/rust-lang-nursery/futures-rs"
homepage = "https://rust-lang-nursery.github.io/futures-rs"
documentation = "https://docs.rs/futures/0.3.0"
description = """
An implementation of futures and streams featuring zero allocations,
composability, and iterator-like interfaces.
"""
categories = ["asynchronous"]

[dependencies]
futures = { path = "../../", version = "0.3.0", features = ["thread-pool"] }
48 changes: 48 additions & 0 deletions futures/examples/functional/src/main.rs
@@ -0,0 +1,48 @@
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
// subsequenty 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);
}
19 changes: 19 additions & 0 deletions futures/examples/imperative/Cargo.toml
@@ -0,0 +1,19 @@
[package]
name = "futures-example-imperative"
edition = "2018"
version = "0.3.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
license = "MIT OR Apache-2.0"
readme = "../README.md"
keywords = ["futures", "async", "future"]
repository = "https://github.com/rust-lang-nursery/futures-rs"
homepage = "https://rust-lang-nursery.github.io/futures-rs"
documentation = "https://docs.rs/futures/0.3.0"
description = """
An implementation of futures and streams featuring zero allocations,
composability, and iterator-like interfaces.
"""
categories = ["asynchronous"]

[dependencies]
futures = { path = "../../", version = "0.3.0", features = ["thread-pool"] }
48 changes: 48 additions & 0 deletions futures/examples/imperative/src/main.rs
@@ -0,0 +1,48 @@
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, mut rx) = mpsc::unbounded::<i32>();

// Create a future by an async block, where async is responsible for generating
// 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 Future is implemented 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 transmission
pool.spawn_ok(fut_tx_result);

let mut pending = vec![];
// Use the provided executor to wait for the next value
// of the stream to be available.
while let Some(v) = rx.next().await {
pending.push(v * 2);
};

pending
};

// Actually execute the above future, which will invoke Future::poll and
// subsequenty 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);
}
57 changes: 57 additions & 0 deletions futures/src/lib.rs
Expand Up @@ -20,6 +20,63 @@
//! threading. Large asynchronous computations are built up using futures,
//! streams and sinks, and then spawned as independent tasks that are run to
//! completion, but *do not block* the thread running them.
//!
//! The following example describes how the task system context is built and used
//! within macros and keywords such as async and await!.
//!
//! ```rust
//! # 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
//! // subsequenty 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);
//! }
//! ```
//!
//! The majority of examples and code snippets in this crate assume that they are
//! inside an async block as written above.

#![cfg_attr(feature = "cfg-target-has-atomic", feature(cfg_target_has_atomic))]
#![cfg_attr(feature = "read-initializer", feature(read_initializer))]
Expand Down

0 comments on commit 260f76b

Please sign in to comment.