From a0143dd0986d8163050067d7e8ed95e23c5c1086 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Thu, 8 Aug 2019 15:54:19 +0200 Subject: [PATCH 01/24] Add book draft --- docs/.gitignore | 1 + docs/book.toml | 6 + docs/src/SUMMARY.md | 23 ++++ docs/src/concepts.md | 15 +++ docs/src/concepts/async-read-write.md | 1 + docs/src/concepts/futures.md | 122 ++++++++++++++++++ docs/src/concepts/streams.md | 1 + docs/src/concepts/tasks.md | 1 + docs/src/glossary.md | 0 docs/src/overview.md | 11 ++ docs/src/overview/async-std.md | 1 + docs/src/overview/async-task.md | 1 + docs/src/overview/stability-guarantees.md | 29 +++++ docs/src/overview/std-and-library-futures.md | 1 + docs/src/patterns.md | 1 + .../patterns/accepting-concurrent-requests.md | 1 + docs/src/patterns/async-read-write.md | 1 + docs/src/patterns/background-tasks.md | 1 + docs/src/patterns/fork-join.md | 1 + docs/src/patterns/proper-shutdown.md | 1 + docs/src/patterns/testing.md | 1 + docs/src/security/index.md | 12 ++ docs/src/security/policy.md | 37 ++++++ docs/src/tutorials/index.md | 1 + docs/src/tutorials/integrating-std-thread.md | 43 ++++++ 25 files changed, 313 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/book.toml create mode 100644 docs/src/SUMMARY.md create mode 100644 docs/src/concepts.md create mode 100644 docs/src/concepts/async-read-write.md create mode 100644 docs/src/concepts/futures.md create mode 100644 docs/src/concepts/streams.md create mode 100644 docs/src/concepts/tasks.md create mode 100644 docs/src/glossary.md create mode 100644 docs/src/overview.md create mode 100644 docs/src/overview/async-std.md create mode 100644 docs/src/overview/async-task.md create mode 100644 docs/src/overview/stability-guarantees.md create mode 100644 docs/src/overview/std-and-library-futures.md create mode 100644 docs/src/patterns.md create mode 100644 docs/src/patterns/accepting-concurrent-requests.md create mode 100644 docs/src/patterns/async-read-write.md create mode 100644 docs/src/patterns/background-tasks.md create mode 100644 docs/src/patterns/fork-join.md create mode 100644 docs/src/patterns/proper-shutdown.md create mode 100644 docs/src/patterns/testing.md create mode 100644 docs/src/security/index.md create mode 100644 docs/src/security/policy.md create mode 100644 docs/src/tutorials/index.md create mode 100644 docs/src/tutorials/integrating-std-thread.md diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..7585238e --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +book diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 00000000..b080e779 --- /dev/null +++ b/docs/book.toml @@ -0,0 +1,6 @@ +[book] +authors = ["The async-std maintainers"] +language = "en" +multilingual = false +src = "src" +title = "Async programming in Rust with async-std" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 00000000..54acb5e9 --- /dev/null +++ b/docs/src/SUMMARY.md @@ -0,0 +1,23 @@ +# Summary + +- [Overview](./overview.md) + - [`async-std`](./overview/async-std.md) + - [`async-task`](./overview/async-task.md) + - [`std::future` and `futures-rs`](./overview/std-and-library-futures.md) + - [Stability guarantees](./overview/stability-guarantees.md) +- [Async concepts using async-std](./concepts.md) + - [Futures](./concepts/futures.md) + - [Tasks](./concepts/tasks.md) + - [Async read/write](./concepts/async-read-write.md) + - [Streams and Channels](./concepts/streams.md) +- [Tutorials](./tutorials/index.md) + - [Integrating std::thread](./tutorials/integrating-std-thread.md) +- [Async Patterns](./patterns.md) + - [Fork/Join](./patterns/fork-join.md) + - [Accepting requests](./patterns/accepting-concurrent-requests.md) + - [Proper Shutdown](./patterns/proper-shutdown.md) + - [Background Tasks](./patterns/background-tasks.md) + - [Testing](./patterns/testing.md) +- [Security practices](./security/index.md) + - [Security disclosures and policy](./security/policy.md) +- [Glossary](./glossary.md) diff --git a/docs/src/concepts.md b/docs/src/concepts.md new file mode 100644 index 00000000..8fbb5a3b --- /dev/null +++ b/docs/src/concepts.md @@ -0,0 +1,15 @@ +# Async concepts using async-std + +[Rust Futures][futures] have the reputation of being hard. We don't think this is the case. They are, in our opinion, one of the easiest concurrency concepts around and have an intuitive explanation. + +However, there are good reasons for that perception. Futures have three concepts at their base that seem to be a constant source of confusion: deferred computation, asynchronicity and independence of execution strategy. + +These concepts are not hard, but something many people are not used to. This base confusion is amplified by many implementations oriented on details and hard to understand. Most explanations of these implementations also target advanced users. We both try to provide easy to understand primitives and approachable overviews of the concepts. + +Futures are a concept that abstracts over how code is run. By themselves, they do nothing. This is a weird concept in an imperative language, where usually one thing happens after the other - right now. + +So how do Futures run? You decide! Futures do nothing without the piece of code _executing_ them. This part is called an _executor_. An _executor_ decides _when_ and _how_ to execute your futures. `async-task` is such an _executor_, `async-std` is a library providing the building blocks. + +Let's start with a little bit of motivation, though. + +[futures]: https://en.wikipedia.org/wiki/Futures_and_promises diff --git a/docs/src/concepts/async-read-write.md b/docs/src/concepts/async-read-write.md new file mode 100644 index 00000000..79354298 --- /dev/null +++ b/docs/src/concepts/async-read-write.md @@ -0,0 +1 @@ +# Async read/write diff --git a/docs/src/concepts/futures.md b/docs/src/concepts/futures.md new file mode 100644 index 00000000..1c4e2d9f --- /dev/null +++ b/docs/src/concepts/futures.md @@ -0,0 +1,122 @@ +# Futures + +> I have looked into the future, everyone is slightly older. + +-- Future of the Left -- The Plot Against Common Sense + +A notable point about Rust is [_fearless concurrency_][fearless-concurrency]. That is the notion that you should be empowered to do concurrent things, without giving up safety. Also, Rust being a low-level language, it's about fearless concurrency _without picking a specific implementation strategy_. This means we _must_ abstract over the strategy, to allow choice _later_, if we want to have any way to share code between users of different strategies. + +Futures abstract over _computation_. They describe the "what", independent of the "where" and the "when". For that, they aim to break code into small, composable actions that can then be executed by a part of our system. Let's take a tour through what it means to compute things to find where we can abstract. + +## Send and Sync + +Luckily, concurrent Rust already has two well-known and effective concepts abstracting over sharing between Rust concurrent parts of a program: Send and Sync. Notably, both the Send and Sync traits abstract over _strategies_ of concurrent work, compose neatly, and don't prescribe an implementation. + +As a quick summary, `Send` abstracts over passing data in a computation over to another concurrent computation (let's call it the receiver), losing access to it on the sender side. In many programming languages, this strategy is commonly implemented, but missing support from the language side expects you to keep up this behaviour yourself. This is a regular source of bugs: senders keeping handles to sent things around and maybe even working with them after sending. Rust mitigates this problem by making this behaviour known. Types can be `Send` or not (by implementing the appropriate marker trait), allowing or disallowing sending them around. + +Note how we avoided any word like _"thread"_, but instead opted for "computation". The full power of `Send` (and subsequently also `Sync`) is that they relieve you of the burden of knowing _what_ shares. At the point of implementation, you only need to know which method of sharing is appropriate for the type at hand. This keeps reasoning local and is not influenced by whatever implementation the user of that type later uses. + +`Sync` is about sharing data between two concurrent parts of a program. This is another common pattern: as writing to a memory location or reading while another party is writing is inherently unsafe, this access needs to be moderated through synchronisation.[^1] There are many common ways of two parties to agree on not using the same part in memory at the same time, for example mutexes and spinlocks. Again, Rust gives you the option of (safely!) not caring. Rust gives you the ability to express that something _needs_ synchronisation while not being specific about the _how_. + +`Send` and `Sync` can be composed in interesting fashions, but that's beyond the scope here. You can find examples in the [Rust Book][rust-book-sync]. + +To sum up: Rust gives us the ability to safely abstract over important properties of concurrent programs: their data sharing. It does so in a very lightweight fashion: the language itself only knows about the two markers `Send` and `Sync` and helps us a little by deriving them itself, when possible. The rest is a library concern. + +## An easy view of computation + +While computation is a subject to write a whole [book][understanding-computation] about, a very simplified view of them suffices for us: + +* computation is a sequence of composable operations +* they can branch based on a decision +* they either run to succession and yield a result or they can yield an error + +## Deferring computation + +As mentioned above `Send` and `Sync` are about data. But programs are not only about data, they also talk about _computing_ the data. And that's what [Futures][futures] do. We are going to have a close look at how that works in the next chapter. Let's look at what Futures allow us to express, in English. Futures go from this plan: + +* Do X +* If X succeeds, do Y + +towards + +* Start doing X +* Once X succeeds, start doing Y + +Remember the talk about "deferred computation" in the intro? That's all it is. Instead of telling the computer what to execute and decide upon _now_, you tell it what to start doing and how to react on potential events the... well... `Future`. + +## Orienting towards the beginning + +Let's have a look at a simple function, specifically the return value: + +```rust +fn compute_value() -> String { + "test".into() +} +``` + +You can call that at any time, so you are in full control on when you call it. But here's the problem: the moment you call it, you transfer control to the called function. It returns a value. + +Note that this return value talks about the past. The past has a drawback: all decisions have been made. It has an advantage: the outcome is visible. We can unwrap the presents of program past and then decide what to do with it. + +But here's a problem: we wanted to abstract over _computation_ to be allowed to let someone else choose how to run it. That's fundamentally incompatible with looking at the results of previous computation all the time. So, let's find a type that describes a computation without running it. Let's look at the function again: + +```rust +fn compute_value() -> String { + "test".into() +} +``` + +Speaking in terms of time, we can only take action _before_ calling the function or _after_ the function returned. This is not desireable, as it takes from us the ability to do something _while_ it runs. When working with parallel code, this would take from us the ability to start a parallel task while the first runs (because we gave away control). + +This is the moment where we could reach for [threads][threads]. But threads are a very specific concurrency primitive and we said that we are searching for an abstraction. + +What we are searching is something that represents ongoing work towards a result in the future. Whenever we say `something` in Rust, we almost always mean a trait. Let's start with an incomplete definition of the `Future` trait: + +```rust +trait Future { + type Output; + + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll; +} +``` + +Ignore `Pin` and `Context` for now, you don't need them for high-level understanding. Looking at it closely, we see the following: it is generic over the `Output`. It provides a function called `poll`, which allows us to check on the state of the current computation. + +Every call to `poll()` can result in one of these two cases: + +1. The future is done, `poll` will return [`Poll::Ready`][poll-ready] +2. The future has not finished executing, it will return [`Poll::Pending`][poll-pending] + +This allows us to externally check if a `Future` has finished doing its work, or is finally done and can give us the value. The most simple way (but not efficient) would be to just constantly poll futures in a loop. There's optimistions here, and this is what a good runtime is does for you. + +Note that calling `poll` after case 1 happened may result in confusing behaviour. See the [futures-docs][futures-docs] for details. + +## Async + +While the `Future` trait has existed in Rust for a while, it was inconvenient to build and describe them. For this, Rust now has a special syntax: `async`. It takes the idea introduced above: if we want to have a function that sets up a deferred computation, we call it an `async` function: + +```rust +async fn compute_value() -> String { + "test".into() +} +``` + +When this function is called, it will produce a `Future` instead of immediately returning a String. (Or, more precisely, generate a type for you that implements `Future`.) + +## Conclusion + +Working from values, we searched for something that expresses _working towards a value available sometime later_. From there, we talked about the concept of polling. + +A `Future` is any data type that does not represent a value, but the ability to _produce a value at some point in the future_. Implementations of this are very varied and detailled depending on use-case, but the interface is simple. + +From here on, we are going to introduce you to two other important concepts: `tasks` and `streams`, to then talk about how we combine the three to build things. + + +[^1]: Two parties reading while it is guaranteed that no one is writing is always safe. + +[poll-ready]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Ready +[poll-pending]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Pending +[futures-docs]: https://doc.rust-lang.org/std/future/trait.Future.html +[fearless-concurrency]: https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html +[understanding-computation]: https://computationbook.com/ +[threads]: https://en.wikipedia.org/wiki/Thread_(computing) diff --git a/docs/src/concepts/streams.md b/docs/src/concepts/streams.md new file mode 100644 index 00000000..80eeccb1 --- /dev/null +++ b/docs/src/concepts/streams.md @@ -0,0 +1 @@ +# Streams diff --git a/docs/src/concepts/tasks.md b/docs/src/concepts/tasks.md new file mode 100644 index 00000000..e33f9980 --- /dev/null +++ b/docs/src/concepts/tasks.md @@ -0,0 +1 @@ +# tasks diff --git a/docs/src/glossary.md b/docs/src/glossary.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/src/overview.md b/docs/src/overview.md new file mode 100644 index 00000000..14110ce5 --- /dev/null +++ b/docs/src/overview.md @@ -0,0 +1,11 @@ +# Overview + +`async-std` and `async-task` along with their [supporting libraries][organization] are a two libraries making your life in async programming easier. They provide fundamental implementations for downstream libraries and applications alike. + +`async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes `async-task` in a model similar to the `thread` module found in the Rust standard lib. The name reflects the approach of this library: it is a closely modeled to the Rust main standard library as possible, replacing all components by async counterparts. You can read more about `async-std` in [the overview chapter][overview-std]. + +`async-task` is a library for implementing asynchronous tasks quickly. For the purpose of this documentation, you will mainly interact with it through the `async_std::task` module. Still, it has some nice properties to be aware of, which you can read up on in the [`async-task` overview chapter][overview-task]. + +[organization]: https://github.com/async-std/async-std +[overview-std]: overview/async-std/ +[overview-task]: overview/async-task/ \ No newline at end of file diff --git a/docs/src/overview/async-std.md b/docs/src/overview/async-std.md new file mode 100644 index 00000000..5b8c6ccf --- /dev/null +++ b/docs/src/overview/async-std.md @@ -0,0 +1 @@ +# async-std diff --git a/docs/src/overview/async-task.md b/docs/src/overview/async-task.md new file mode 100644 index 00000000..117aa2e6 --- /dev/null +++ b/docs/src/overview/async-task.md @@ -0,0 +1 @@ +# async-task diff --git a/docs/src/overview/stability-guarantees.md b/docs/src/overview/stability-guarantees.md new file mode 100644 index 00000000..7eb9b1c2 --- /dev/null +++ b/docs/src/overview/stability-guarantees.md @@ -0,0 +1,29 @@ +# Stability and SemVer + +`async-std` and `async-task` follow https://semver.org/. + +In short: we are versioning our software as `MAJOR.MINOR.PATCH`. We increase the: + +* MAJOR version when there are incompatible API changes, +* MINOR version when we introducece functionality in a backwards-compatible manner +* PATCH version when we make backwards-compatible bug fixes + +## Future expectations + +`async-std` uses the `AsyncRead/AsyncWrite/AsyncSeek/AsyncBufRead` and the `Stream` traits from the `futures-rs` library. We expect those to be conservatively updated and in lockstep. Breaking changes in these traits will lead to a major version upgrade, for which we will provide migration documentation. + +## Minimum version policy + +The current tentative policy is that the minimum Rust version required to use this crate can be increased in minor version updates. For example, if `async-std` 1.0 requires Rust 1.37.0, then `async-std` 1.0.z for all values of z will also require Rust 1.37.0 or newer. However, `async-std` 1.y for y > 0 may require a newer minimum version of Rust. + +In general, this crate will be conservative with respect to the minimum supported version of Rust. With `async/await` being a new feature though, we will track changes in a measured pace. + +## Security fixes + +Security fixes will be applied to _all_ minor branches of this library in all _supported_ major revisions. This policy might change in the future, in which case we give at least _3 month_ of ahead notice. + +## Credits + +This policy is based on [burntsushis regex crate][regex-policy]. + +[regex-policy]: https://github.com/rust-lang/regex#minimum-rust-version-policy diff --git a/docs/src/overview/std-and-library-futures.md b/docs/src/overview/std-and-library-futures.md new file mode 100644 index 00000000..4290f7f9 --- /dev/null +++ b/docs/src/overview/std-and-library-futures.md @@ -0,0 +1 @@ +# `std::future` and `futures-rs` \ No newline at end of file diff --git a/docs/src/patterns.md b/docs/src/patterns.md new file mode 100644 index 00000000..d435f36b --- /dev/null +++ b/docs/src/patterns.md @@ -0,0 +1 @@ +# Async Patterns diff --git a/docs/src/patterns/accepting-concurrent-requests.md b/docs/src/patterns/accepting-concurrent-requests.md new file mode 100644 index 00000000..b984183c --- /dev/null +++ b/docs/src/patterns/accepting-concurrent-requests.md @@ -0,0 +1 @@ +# Accepting requests diff --git a/docs/src/patterns/async-read-write.md b/docs/src/patterns/async-read-write.md new file mode 100644 index 00000000..79354298 --- /dev/null +++ b/docs/src/patterns/async-read-write.md @@ -0,0 +1 @@ +# Async read/write diff --git a/docs/src/patterns/background-tasks.md b/docs/src/patterns/background-tasks.md new file mode 100644 index 00000000..02571b26 --- /dev/null +++ b/docs/src/patterns/background-tasks.md @@ -0,0 +1 @@ +# Background Tasks diff --git a/docs/src/patterns/fork-join.md b/docs/src/patterns/fork-join.md new file mode 100644 index 00000000..4709bb20 --- /dev/null +++ b/docs/src/patterns/fork-join.md @@ -0,0 +1 @@ +# Fork/Join diff --git a/docs/src/patterns/proper-shutdown.md b/docs/src/patterns/proper-shutdown.md new file mode 100644 index 00000000..49ba1f43 --- /dev/null +++ b/docs/src/patterns/proper-shutdown.md @@ -0,0 +1 @@ +# Proper Shutdown diff --git a/docs/src/patterns/testing.md b/docs/src/patterns/testing.md new file mode 100644 index 00000000..f00b526a --- /dev/null +++ b/docs/src/patterns/testing.md @@ -0,0 +1 @@ +# Testing diff --git a/docs/src/security/index.md b/docs/src/security/index.md new file mode 100644 index 00000000..ab625a13 --- /dev/null +++ b/docs/src/security/index.md @@ -0,0 +1,12 @@ +# Security + +Writing a highly perfomant async core library is a task involving some instances of unsafe code. + +We take great care in vetting all unsafe code included in `async-std` and do follow generally accepted practices. + +In the case that you find a security-related bug in our library, please get in touch with our [security contact][security-policy]. + +Patches improving the resilience of the library or the testing setup are happily accepted on our [github org][github]. + +[security-policies]: /security/policy +[github]: https://github.com/async-std/ \ No newline at end of file diff --git a/docs/src/security/policy.md b/docs/src/security/policy.md new file mode 100644 index 00000000..d6285d0e --- /dev/null +++ b/docs/src/security/policy.md @@ -0,0 +1,37 @@ +# Policy + +Safety is one of the core principles of what we do, and to that end, we would like to ensure that async-std has a secure implementation. Thank you for taking the time to responsibly disclose any issues you find. + +All security bugs in async-std distribution should be reported by email to security@ferrous-systems.com. This list is delivered to a small security team. Your email will be acknowledged within 24 hours, and you’ll receive a more detailed response to your email within 48 hours indicating the next steps in handling your report. If you would like, you can encrypt your report using our public key. This key is also On MIT’s keyserver and reproduced below. + +Be sure to use a descriptive subject line to avoid having your report be missed. After the initial reply to your report, the security team will endeavor to keep you informed of the progress being made towards a fix and full announcement. As recommended by [RFPolicy][rf-policy], these updates will be sent at least every five days. In reality, this is more likely to be every 24-48 hours. + +If you have not received a reply to your email within 48 hours, or have not heard from the security team for the past five days, there are a few steps you can take (in order): + +* Contact the current security coordinator TODO directly. +* Contact the back-up contact TODO directly. +* Post on our Community forums + +Please note that the discussion forums are public areas. When escalating in these venues, please do not discuss your issue. Simply say that you’re trying to get a hold of someone from the security team. + +[rf-policy]: https://en.wikipedia.org/wiki/RFPolicy + +## Disclosure policy + +The async-std project has a 5 step disclosure process. + +* The security report is received and is assigned a primary handler. This person will coordinate the fix and release process. +* The problem is confirmed and a list of all affected versions is determined. +* Code is audited to find any potential similar problems. +* Fixes are prepared for all releases which are still under maintenance. These fixes are not committed to the public repository but rather held locally pending the announcement. +* On the embargo date, the changes are pushed to the public repository and new builds are deployed to crates.io. Within 6 hours, a copy of the advisory will be published on the the async.rs blog. + +This process can take some time, especially when coordination is required with maintainers of other projects. Every effort will be made to handle the bug in as timely a manner as possible, however it’s important that we follow the release process above to ensure that the disclosure is handled in a consistent manner. + +## Credits + +This policy is adapted from the [Rust project](https://www.rust-lang.org/policies/security) security policy. + +## PGP Key + +TODO \ No newline at end of file diff --git a/docs/src/tutorials/index.md b/docs/src/tutorials/index.md new file mode 100644 index 00000000..81c8590f --- /dev/null +++ b/docs/src/tutorials/index.md @@ -0,0 +1 @@ +# Tutorials diff --git a/docs/src/tutorials/integrating-std-thread.md b/docs/src/tutorials/integrating-std-thread.md new file mode 100644 index 00000000..fca21584 --- /dev/null +++ b/docs/src/tutorials/integrating-std-thread.md @@ -0,0 +1,43 @@ +# Exercise: Waiting for `std::thread` + +Parallel processing is usually done via [threads]. +Concurrent programming is usually done with systems similar to [async-task]. +These two worlds seem different - and in some regards, they are - though they +are easy to connect. +In this exercise, you will learn how to connect to concurrent/parallel components easily, by connecting a thread to a task. + +## Understanding the problem + +The standard thread API in Rust is `std::thread`. Specifically, it contains the [`spawn`] function, which allows us to start a thread: + +```rust +std::thread::spawn(|| { + println!("in child thread"); +}) +println!("in parent thread"); +``` + +This creates a thread, _immediately_ [schedules] it to run, and continues. This is crucial: once the thread is spawned, it is independent of its _parent thread_. If you want to wait for the thread to end, you need to capture its [`JoinHandle`] and join it with your current thread: + +```rust +let thread = std::thread::spawn(|| { + println!("in child thread"); +}) +thread.join(); +println!("in parent thread"); +``` + +This comes at a cost though: the waiting thread will [block] until the child is done. Wouldn't it be nice if we could just use the `.await` syntax here and leave the opportunity for another task to be scheduled while waiting? + +## Backchannels + + + + + +[threads]: TODO: wikipedia +[async-task]: TODO: link +[`spawn`]: TODO: link +[`JoinHandle`]: TODO: link +[schedules]: TODO: Glossary link +[block]: TODO: Link to blocking \ No newline at end of file From 62bf80282718fc8a83c96202700edac4f27254d4 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Thu, 8 Aug 2019 16:23:24 +0200 Subject: [PATCH 02/24] Remove `async-task` as a subject from the book Link to the docs, the are extensive and useful. --- docs/src/overview.md | 4 ++-- docs/src/overview/async-task.md | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 docs/src/overview/async-task.md diff --git a/docs/src/overview.md b/docs/src/overview.md index 14110ce5..01c42c59 100644 --- a/docs/src/overview.md +++ b/docs/src/overview.md @@ -4,8 +4,8 @@ `async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes `async-task` in a model similar to the `thread` module found in the Rust standard lib. The name reflects the approach of this library: it is a closely modeled to the Rust main standard library as possible, replacing all components by async counterparts. You can read more about `async-std` in [the overview chapter][overview-std]. -`async-task` is a library for implementing asynchronous tasks quickly. For the purpose of this documentation, you will mainly interact with it through the `async_std::task` module. Still, it has some nice properties to be aware of, which you can read up on in the [`async-task` overview chapter][overview-task]. +`async-task` is a library for implementing asynchronous tasks quickly. For the purpose of this documentation, you will mainly interact with it through the `async_std::task` module. Still, it has some nice properties to be aware of, which you can read up on in the [`async-task` crate docs][task-docs]. [organization]: https://github.com/async-std/async-std [overview-std]: overview/async-std/ -[overview-task]: overview/async-task/ \ No newline at end of file +[overview-task]: https://docs.rs/async-task \ No newline at end of file diff --git a/docs/src/overview/async-task.md b/docs/src/overview/async-task.md deleted file mode 100644 index 117aa2e6..00000000 --- a/docs/src/overview/async-task.md +++ /dev/null @@ -1 +0,0 @@ -# async-task From bbaa501474227c276e1e66e0c9ce2884157193e9 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Thu, 8 Aug 2019 16:29:12 +0200 Subject: [PATCH 03/24] Remove async-task chapter link --- docs/src/SUMMARY.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 54acb5e9..33ee1e5b 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -2,7 +2,6 @@ - [Overview](./overview.md) - [`async-std`](./overview/async-std.md) - - [`async-task`](./overview/async-task.md) - [`std::future` and `futures-rs`](./overview/std-and-library-futures.md) - [Stability guarantees](./overview/stability-guarantees.md) - [Async concepts using async-std](./concepts.md) From c8d9ef885510eced353ac2746f6e7b5bd25c7c50 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Fri, 9 Aug 2019 14:27:34 +0200 Subject: [PATCH 04/24] Add a small sentence that async-std does also include Mutex implementations --- docs/src/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/overview.md b/docs/src/overview.md index 01c42c59..1003b1de 100644 --- a/docs/src/overview.md +++ b/docs/src/overview.md @@ -2,7 +2,7 @@ `async-std` and `async-task` along with their [supporting libraries][organization] are a two libraries making your life in async programming easier. They provide fundamental implementations for downstream libraries and applications alike. -`async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes `async-task` in a model similar to the `thread` module found in the Rust standard lib. The name reflects the approach of this library: it is a closely modeled to the Rust main standard library as possible, replacing all components by async counterparts. You can read more about `async-std` in [the overview chapter][overview-std]. +`async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes `async-task` in a model similar to the `thread` module found in the Rust standard lib. The name reflects the approach of this library: it is a closely modeled to the Rust main standard library as possible, replacing all components by async counterparts. This not only includes io primitives, but also `async/await` compatible versions of primitives like `Mutex`. You can read more about `async-std` in [the overview chapter][overview-std]. `async-task` is a library for implementing asynchronous tasks quickly. For the purpose of this documentation, you will mainly interact with it through the `async_std::task` module. Still, it has some nice properties to be aware of, which you can read up on in the [`async-task` crate docs][task-docs]. From 574676aa1a1d3cb0273227c6175f1a6b91587c18 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 12 Aug 2019 12:29:43 +0200 Subject: [PATCH 05/24] Add images --- docs/src/images/horizontal_color.svg | 78 +++++++++++++++++++++++++ docs/src/images/icon_color.svg | 80 ++++++++++++++++++++++++++ docs/src/images/vertical_color.svg | 85 ++++++++++++++++++++++++++++ docs/src/overview.md | 2 + 4 files changed, 245 insertions(+) create mode 100644 docs/src/images/horizontal_color.svg create mode 100644 docs/src/images/icon_color.svg create mode 100644 docs/src/images/vertical_color.svg diff --git a/docs/src/images/horizontal_color.svg b/docs/src/images/horizontal_color.svg new file mode 100644 index 00000000..88bed32c --- /dev/null +++ b/docs/src/images/horizontal_color.svg @@ -0,0 +1,78 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/docs/src/images/icon_color.svg b/docs/src/images/icon_color.svg new file mode 100644 index 00000000..90dccdee --- /dev/null +++ b/docs/src/images/icon_color.svg @@ -0,0 +1,80 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/docs/src/images/vertical_color.svg b/docs/src/images/vertical_color.svg new file mode 100644 index 00000000..14bd065c --- /dev/null +++ b/docs/src/images/vertical_color.svg @@ -0,0 +1,85 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/docs/src/overview.md b/docs/src/overview.md index 1003b1de..9454c0c0 100644 --- a/docs/src/overview.md +++ b/docs/src/overview.md @@ -1,5 +1,7 @@ # Overview +![async-std logo](./images/horizontal_color.svg) + `async-std` and `async-task` along with their [supporting libraries][organization] are a two libraries making your life in async programming easier. They provide fundamental implementations for downstream libraries and applications alike. `async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes `async-task` in a model similar to the `thread` module found in the Rust standard lib. The name reflects the approach of this library: it is a closely modeled to the Rust main standard library as possible, replacing all components by async counterparts. This not only includes io primitives, but also `async/await` compatible versions of primitives like `Mutex`. You can read more about `async-std` in [the overview chapter][overview-std]. From eadd3ed1f6866cfa1651f5820ebbf3801ab356bc Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 12 Aug 2019 13:28:47 +0200 Subject: [PATCH 06/24] Update stability guarantees --- docs/src/overview/stability-guarantees.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/src/overview/stability-guarantees.md b/docs/src/overview/stability-guarantees.md index 7eb9b1c2..ddf8db80 100644 --- a/docs/src/overview/stability-guarantees.md +++ b/docs/src/overview/stability-guarantees.md @@ -8,15 +8,26 @@ In short: we are versioning our software as `MAJOR.MINOR.PATCH`. We increase the * MINOR version when we introducece functionality in a backwards-compatible manner * PATCH version when we make backwards-compatible bug fixes +We will provide migration documentation between major versions. + ## Future expectations -`async-std` uses the `AsyncRead/AsyncWrite/AsyncSeek/AsyncBufRead` and the `Stream` traits from the `futures-rs` library. We expect those to be conservatively updated and in lockstep. Breaking changes in these traits will lead to a major version upgrade, for which we will provide migration documentation. +`async-std` uses its own implementations of the following concepts: + +* `Read` +* `Write` +* `Seek` +* `BufRead` +* `Stream` + +For integration with the ecosystem, all types implementing these traits also have an implementation of the corresponding interfaces in the `futures-rs` library. +Please note that our SemVer guarantees don't extend to usage of those interfaces. We expect those to be conservatively updated and in lockstep. ## Minimum version policy The current tentative policy is that the minimum Rust version required to use this crate can be increased in minor version updates. For example, if `async-std` 1.0 requires Rust 1.37.0, then `async-std` 1.0.z for all values of z will also require Rust 1.37.0 or newer. However, `async-std` 1.y for y > 0 may require a newer minimum version of Rust. -In general, this crate will be conservative with respect to the minimum supported version of Rust. With `async/await` being a new feature though, we will track changes in a measured pace. +In general, this crate will be conservative with respect to the minimum supported version of Rust. With `async/await` being a new feature though, we will track changes in a measured pace initially. ## Security fixes From 1c16d8c462b177fe9d202ddfb305df66be6f9508 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 12 Aug 2019 20:52:46 +0200 Subject: [PATCH 07/24] Set git link for async-task dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ac9cc80c..b0400393 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ rustdoc-args = ["--features docs"] docs = [] [dependencies] -async-task = { path = "../async-task" } +async-task = { git = "git@github.com:async-std/async-task.git" } cfg-if = "0.1.9" crossbeam = "0.7.1" futures-preview = "0.3.0-alpha.17" From e02349473c7249701462df931e07b1d445204090 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 12 Aug 2019 20:53:24 +0200 Subject: [PATCH 08/24] Change docs.rs to docs --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b58b8b10..353ef14c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,5 +16,5 @@ matrix: script: - cargo check --all --benches --bins --examples --tests - cargo test --all - - cargo doc --features docs.rs + - cargo doc --features docs - cargo fmt --all -- --check From 08af9053d0e0e813389226415d389b9338cd3920 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 12 Aug 2019 20:59:51 +0200 Subject: [PATCH 09/24] Fix broken build --- .travis.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 353ef14c..58c94738 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: rust before_script: -- rustup component add rustfmt + - rustup component add rustfmt matrix: fast_finish: true diff --git a/Cargo.toml b/Cargo.toml index b0400393..9c362713 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ rustdoc-args = ["--features docs"] docs = [] [dependencies] -async-task = { git = "git@github.com:async-std/async-task.git" } +async-task = { git = "ssh://git@github.com/async-std/async-task.git" } cfg-if = "0.1.9" crossbeam = "0.7.1" futures-preview = "0.3.0-alpha.17" From 6c7922a404bd792d2fc767e0969af84bf05a967a Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 12 Aug 2019 21:17:21 +0200 Subject: [PATCH 10/24] Add small patterns library --- docs/src/SUMMARY.md | 1 + docs/src/patterns.md | 6 +++++- docs/src/patterns/small-patterns.md | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 docs/src/patterns/small-patterns.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 33ee1e5b..a71a1beb 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -17,6 +17,7 @@ - [Proper Shutdown](./patterns/proper-shutdown.md) - [Background Tasks](./patterns/background-tasks.md) - [Testing](./patterns/testing.md) + - [Collected Small Patterns](./patters/small-patterns.md) - [Security practices](./security/index.md) - [Security disclosures and policy](./security/policy.md) - [Glossary](./glossary.md) diff --git a/docs/src/patterns.md b/docs/src/patterns.md index d435f36b..a19b81b4 100644 --- a/docs/src/patterns.md +++ b/docs/src/patterns.md @@ -1 +1,5 @@ -# Async Patterns +# Patterns + +This section documents small, useful patterns. + +It is intended to be read at a glance, allowing you to get back when you have a problem. \ No newline at end of file diff --git a/docs/src/patterns/small-patterns.md b/docs/src/patterns/small-patterns.md new file mode 100644 index 00000000..586702aa --- /dev/null +++ b/docs/src/patterns/small-patterns.md @@ -0,0 +1,18 @@ +# Small Patterns + +A collection of small, useful patterns. + + + +## Splitting streams + +`async-std` doesn't provide a `split()` method on `io` handles. Instead, splitting a stream into a read and write half can be done like this: + +```rust +use async_std::io; + +async fn echo(stream: io::TcpStream) { + let (reader, writer) = &mut (&stream, &stream); + io::copy(reader, writer).await?; +} +``` \ No newline at end of file From e93c138bf661684df2dcf1646af5b328f004d706 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 12 Aug 2019 21:44:06 +0200 Subject: [PATCH 11/24] Reorder commands --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 58c94738..5a47885a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ matrix: os: windows script: + - cargo fmt --all -- --check - cargo check --all --benches --bins --examples --tests - cargo test --all - cargo doc --features docs - - cargo fmt --all -- --check From 95a2f8ed38ed0161ee041cc3bdbbc49e5f54c0d3 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 12 Aug 2019 21:46:49 +0200 Subject: [PATCH 12/24] Don't mention async-task --- docs/src/concepts.md | 2 +- docs/src/overview.md | 7 ++----- docs/src/overview/stability-guarantees.md | 2 +- docs/src/tutorials/integrating-std-thread.md | 8 ++++---- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/docs/src/concepts.md b/docs/src/concepts.md index 8fbb5a3b..27fef8cc 100644 --- a/docs/src/concepts.md +++ b/docs/src/concepts.md @@ -8,7 +8,7 @@ These concepts are not hard, but something many people are not used to. This bas Futures are a concept that abstracts over how code is run. By themselves, they do nothing. This is a weird concept in an imperative language, where usually one thing happens after the other - right now. -So how do Futures run? You decide! Futures do nothing without the piece of code _executing_ them. This part is called an _executor_. An _executor_ decides _when_ and _how_ to execute your futures. `async-task` is such an _executor_, `async-std` is a library providing the building blocks. +So how do Futures run? You decide! Futures do nothing without the piece of code _executing_ them. This part is called an _executor_. An _executor_ decides _when_ and _how_ to execute your futures. The `async-std::task` module provides you with and interface to such an executor. Let's start with a little bit of motivation, though. diff --git a/docs/src/overview.md b/docs/src/overview.md index 9454c0c0..b40799d4 100644 --- a/docs/src/overview.md +++ b/docs/src/overview.md @@ -2,12 +2,9 @@ ![async-std logo](./images/horizontal_color.svg) -`async-std` and `async-task` along with their [supporting libraries][organization] are a two libraries making your life in async programming easier. They provide fundamental implementations for downstream libraries and applications alike. +`async-std` along with its [supporting libraries][organization] is a library making your life in async programming easier. It provides provide fundamental implementations for downstream libraries and applications alike. The name reflects the approach of this library: it is a closely modeled to the Rust main standard library as possible, replacing all components by async counterparts. -`async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes `async-task` in a model similar to the `thread` module found in the Rust standard lib. The name reflects the approach of this library: it is a closely modeled to the Rust main standard library as possible, replacing all components by async counterparts. This not only includes io primitives, but also `async/await` compatible versions of primitives like `Mutex`. You can read more about `async-std` in [the overview chapter][overview-std]. - -`async-task` is a library for implementing asynchronous tasks quickly. For the purpose of this documentation, you will mainly interact with it through the `async_std::task` module. Still, it has some nice properties to be aware of, which you can read up on in the [`async-task` crate docs][task-docs]. +`async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes an `task` in a model similar to the `thread` module found in the Rust standard lib. But it does not only include io primitives, but also `async/await` compatible versions of primitives like `Mutex`. You can read more about `async-std` in [the overview chapter][overview-std]. [organization]: https://github.com/async-std/async-std [overview-std]: overview/async-std/ -[overview-task]: https://docs.rs/async-task \ No newline at end of file diff --git a/docs/src/overview/stability-guarantees.md b/docs/src/overview/stability-guarantees.md index ddf8db80..e5aa9067 100644 --- a/docs/src/overview/stability-guarantees.md +++ b/docs/src/overview/stability-guarantees.md @@ -1,6 +1,6 @@ # Stability and SemVer -`async-std` and `async-task` follow https://semver.org/. +`async-std` follows https://semver.org/. In short: we are versioning our software as `MAJOR.MINOR.PATCH`. We increase the: diff --git a/docs/src/tutorials/integrating-std-thread.md b/docs/src/tutorials/integrating-std-thread.md index fca21584..c5aa5e1a 100644 --- a/docs/src/tutorials/integrating-std-thread.md +++ b/docs/src/tutorials/integrating-std-thread.md @@ -1,7 +1,7 @@ # Exercise: Waiting for `std::thread` Parallel processing is usually done via [threads]. -Concurrent programming is usually done with systems similar to [async-task]. +In `async-std`, we have similar concept, called a [`task`]. These two worlds seem different - and in some regards, they are - though they are easy to connect. In this exercise, you will learn how to connect to concurrent/parallel components easily, by connecting a thread to a task. @@ -36,8 +36,8 @@ This comes at a cost though: the waiting thread will [block] until the child is [threads]: TODO: wikipedia -[async-task]: TODO: link -[`spawn`]: TODO: link -[`JoinHandle`]: TODO: link +[`task`]: TODO: docs link +[`spawn`]: TODO: docs link +[`JoinHandle`]: TODO: docs link [schedules]: TODO: Glossary link [block]: TODO: Link to blocking \ No newline at end of file From 297d9f189df83a6a8354c02f5a20ceb89615a3d9 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 12 Aug 2019 22:04:58 +0200 Subject: [PATCH 13/24] Begin Glossary --- docs/src/glossary.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/src/glossary.md b/docs/src/glossary.md index e69de29b..caff7e7e 100644 --- a/docs/src/glossary.md +++ b/docs/src/glossary.md @@ -0,0 +1,7 @@ +# Glossary + +### blocking + +"blocked" generally refers to conditions that keep a task from doing its work. For example, it might need data to be sent by a client before continuing. When tasks becomes blocked, usually, other tasks are scheduled. + +Sometimes you hear that you should never call "blocking functions" in an async context. What this refers to is functions that block the current thread and do not yield control back. This keeps the executor from using this thread to schedule another task. \ No newline at end of file From cc19d7e76b6a562eaf9c94dddf51977df6211f49 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 12 Aug 2019 22:17:03 +0200 Subject: [PATCH 14/24] Add draft text of some chapters --- docs/src/concepts/futures.md | 128 +++++++++---------- docs/src/concepts/tasks.md | 82 +++++++++++- docs/src/overview/std-and-library-futures.md | 28 +++- 3 files changed, 170 insertions(+), 68 deletions(-) diff --git a/docs/src/concepts/futures.md b/docs/src/concepts/futures.md index 1c4e2d9f..be04cfe9 100644 --- a/docs/src/concepts/futures.md +++ b/docs/src/concepts/futures.md @@ -1,22 +1,17 @@ # Futures -> I have looked into the future, everyone is slightly older. +A notable point about Rust is [*fearless concurrency*](https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html). That is the notion that you should be empowered to do concurrent things, without giving up safety. Also, Rust being a low-level language, it's about fearless concurrency *without picking a specific implementation strategy*. This means we *must* abstract over the strategy, to allow choice *later*, if we want to have any way to share code between users of different strategies. --- Future of the Left -- The Plot Against Common Sense - -A notable point about Rust is [_fearless concurrency_][fearless-concurrency]. That is the notion that you should be empowered to do concurrent things, without giving up safety. Also, Rust being a low-level language, it's about fearless concurrency _without picking a specific implementation strategy_. This means we _must_ abstract over the strategy, to allow choice _later_, if we want to have any way to share code between users of different strategies. - -Futures abstract over _computation_. They describe the "what", independent of the "where" and the "when". For that, they aim to break code into small, composable actions that can then be executed by a part of our system. Let's take a tour through what it means to compute things to find where we can abstract. +Futures abstract over *computation*. They describe the "what", independent of the "where" and the "when". For that, they aim to break code into small, composable actions that can then be executed by a part of our system. Let's take a tour through what it means to compute things to find where we can abstract. ## Send and Sync -Luckily, concurrent Rust already has two well-known and effective concepts abstracting over sharing between Rust concurrent parts of a program: Send and Sync. Notably, both the Send and Sync traits abstract over _strategies_ of concurrent work, compose neatly, and don't prescribe an implementation. +Luckily, concurrent Rust already has two well-known and effective concepts abstracting over sharing between Rust concurrent parts of a program: Send and Sync. Notably, both the Send and Sync traits abstract over *strategies* of concurrent work, compose neatly, and don't prescribe an implementation. As a quick summary, `Send` abstracts over passing data in a computation over to another concurrent computation (let's call it the receiver), losing access to it on the sender side. In many programming languages, this strategy is commonly implemented, but missing support from the language side expects you to keep up this behaviour yourself. This is a regular source of bugs: senders keeping handles to sent things around and maybe even working with them after sending. Rust mitigates this problem by making this behaviour known. Types can be `Send` or not (by implementing the appropriate marker trait), allowing or disallowing sending them around. -Note how we avoided any word like _"thread"_, but instead opted for "computation". The full power of `Send` (and subsequently also `Sync`) is that they relieve you of the burden of knowing _what_ shares. At the point of implementation, you only need to know which method of sharing is appropriate for the type at hand. This keeps reasoning local and is not influenced by whatever implementation the user of that type later uses. - -`Sync` is about sharing data between two concurrent parts of a program. This is another common pattern: as writing to a memory location or reading while another party is writing is inherently unsafe, this access needs to be moderated through synchronisation.[^1] There are many common ways of two parties to agree on not using the same part in memory at the same time, for example mutexes and spinlocks. Again, Rust gives you the option of (safely!) not caring. Rust gives you the ability to express that something _needs_ synchronisation while not being specific about the _how_. +Note how we avoided any word like *"thread"*, but instead opted for "computation". The full power of `Send` (and subsequently also `Sync`) is that they relieve you of the burden of knowing *what* shares. At the point of implementation, you only need to know which method of sharing is appropriate for the type at hand. This keeps reasoning local and is not influenced by whatever implementation the user of that type later uses. +`Sync` is about sharing data between two concurrent parts of a program. This is another common pattern: as writing to a memory location or reading while another party is writing is inherently unsafe, this access needs to be moderated through synchronisation.[^1] There are many common ways of two parties to agree on not using the same part in memory at the same time, for example mutexes and spinlocks. Again, Rust gives you the option of (safely!) not caring. Rust gives you the ability to express that something *needs* synchronisation while not being specific about the *how*. `Send` and `Sync` can be composed in interesting fashions, but that's beyond the scope here. You can find examples in the [Rust Book][rust-book-sync]. @@ -24,99 +19,100 @@ To sum up: Rust gives us the ability to safely abstract over important propertie ## An easy view of computation -While computation is a subject to write a whole [book][understanding-computation] about, a very simplified view of them suffices for us: - -* computation is a sequence of composable operations -* they can branch based on a decision -* they either run to succession and yield a result or they can yield an error +While computation is a subject to write a whole [book](https://computationbook.com/) about, a very simplified view of them suffices for us: +- computation is a sequence of composable operations +- they can branch based on a decision +- they either run to succession and yield a result or they can yield an error ## Deferring computation -As mentioned above `Send` and `Sync` are about data. But programs are not only about data, they also talk about _computing_ the data. And that's what [Futures][futures] do. We are going to have a close look at how that works in the next chapter. Let's look at what Futures allow us to express, in English. Futures go from this plan: +As mentioned above `Send` and `Sync` are about data. But programs are not only about data, they also talk about *computing* the data. And that's what \[Futures\][futures] do. We are going to have a close look at how that works in the next chapter. Let's look at what Futures allow us to express, in English. Futures go from this plan: -* Do X -* If X succeeds, do Y +- Do X +- If X succeeds, do Y towards -* Start doing X -* Once X succeeds, start doing Y +- Start doing X +- Once X succeeds, start doing Y -Remember the talk about "deferred computation" in the intro? That's all it is. Instead of telling the computer what to execute and decide upon _now_, you tell it what to start doing and how to react on potential events the... well... `Future`. +Remember the talk about "deferred computation" in the intro? That's all it is. Instead of telling the computer what to execute and decide upon *now*, you tell it what to start doing and how to react on potential events the... well... `Future`. ## Orienting towards the beginning Let's have a look at a simple function, specifically the return value: -```rust -fn compute_value() -> String { - "test".into() -} -``` + fn read_file(path: &str) -> Result { + let mut file = File.open(path)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + contents + } You can call that at any time, so you are in full control on when you call it. But here's the problem: the moment you call it, you transfer control to the called function. It returns a value. - Note that this return value talks about the past. The past has a drawback: all decisions have been made. It has an advantage: the outcome is visible. We can unwrap the presents of program past and then decide what to do with it. -But here's a problem: we wanted to abstract over _computation_ to be allowed to let someone else choose how to run it. That's fundamentally incompatible with looking at the results of previous computation all the time. So, let's find a type that describes a computation without running it. Let's look at the function again: +But here's a problem: we wanted to abstract over *computation* to be allowed to let someone else choose how to run it. That's fundamentally incompatible with looking at the results of previous computation all the time. So, let's find a type that describes a computation without running it. Let's look at the function again: -```rust -fn compute_value() -> String { - "test".into() -} -``` + fn read_file(path: &str) -> Result { + let mut file = File.open(path)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + contents + } -Speaking in terms of time, we can only take action _before_ calling the function or _after_ the function returned. This is not desireable, as it takes from us the ability to do something _while_ it runs. When working with parallel code, this would take from us the ability to start a parallel task while the first runs (because we gave away control). - -This is the moment where we could reach for [threads][threads]. But threads are a very specific concurrency primitive and we said that we are searching for an abstraction. +Speaking in terms of time, we can only take action *before* calling the function or *after* the function returned. This is not desirable, as it takes from us the ability to do something *while* it runs. When working with parallel code, this would take from us the ability to start a parallel task while the first runs (because we gave away control). +This is the moment where we could reach for [threads](https://en.wikipedia.org/wiki/Thread_). But threads are a very specific concurrency primitive and we said that we are searching for an abstraction. What we are searching is something that represents ongoing work towards a result in the future. Whenever we say `something` in Rust, we almost always mean a trait. Let's start with an incomplete definition of the `Future` trait: -```rust -trait Future { - type Output; - - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll; -} -``` + trait Future { + type Output; + + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll; + } Ignore `Pin` and `Context` for now, you don't need them for high-level understanding. Looking at it closely, we see the following: it is generic over the `Output`. It provides a function called `poll`, which allows us to check on the state of the current computation. - Every call to `poll()` can result in one of these two cases: -1. The future is done, `poll` will return [`Poll::Ready`][poll-ready] -2. The future has not finished executing, it will return [`Poll::Pending`][poll-pending] +1. The future is done, `poll` will return `[Poll::Ready](https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Ready)` +2. The future has not finished executing, it will return `[Poll::Pending](https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Pending)` This allows us to externally check if a `Future` has finished doing its work, or is finally done and can give us the value. The most simple way (but not efficient) would be to just constantly poll futures in a loop. There's optimistions here, and this is what a good runtime is does for you. - -Note that calling `poll` after case 1 happened may result in confusing behaviour. See the [futures-docs][futures-docs] for details. +Note that calling `poll` after case 1 happened may result in confusing behaviour. See the [futures-docs](https://doc.rust-lang.org/std/future/trait.Future.html) for details. ## Async -While the `Future` trait has existed in Rust for a while, it was inconvenient to build and describe them. For this, Rust now has a special syntax: `async`. It takes the idea introduced above: if we want to have a function that sets up a deferred computation, we call it an `async` function: +While the `Future` trait has existed in Rust for a while, it was inconvenient to build and describe them. For this, Rust now has a special syntax: `async`. The example from above, implemented in `async-std`, would look like this: -```rust -async fn compute_value() -> String { - "test".into() -} -``` -When this function is called, it will produce a `Future` instead of immediately returning a String. (Or, more precisely, generate a type for you that implements `Future`.) + use async_std::fs::File; + + async fn read_file(path: &str) -> Result { + let mut file = File.open(path).await?; + let mut contents = String::new(); + file.read_to_string(&mut contents).await?; + contents + } + +Amazingly little difference, right? All we did is label the function `async` and insert 2 special commands: `.await`. + +This function sets up a deferred computation. When this function is called, it will produce a `Future` instead of immediately returning a String. (Or, more precisely, generate a type for you that implements `Future`.) + +## What does `.await` do? + +The `.await` postfix does exactly what it says on the tin: the moment you use it, the code will wait until the requested action (e.g. opening a file or reading all data in it) is finished. `.await?` is not special, it’s just the application of the `?` operator to the result of `.await`. So, what is gained over the initial code example? We’re getting futures and then immediately waiting for them? + +The `.await` points act as a marker. Here, the code will wait for a `Future` to produce its value. How will a future finish? You don’t need to care! The marker allows the code later *executing* this piece of code (usually called the “runtime”) when it can take some time to care about all the other things it has to do. It will come back to this point when the operation you are doing in the background is done. This is why this style of programming is also called *evented programming*. We are waiting for *things to happen* (e.g. a file to be opened) and then react (by starting to read). + +When executing 2 or more of these functions at the same time, our runtime system is then able to fill the wait time with handling *all the other events* currently going on. ## Conclusion -Working from values, we searched for something that expresses _working towards a value available sometime later_. From there, we talked about the concept of polling. +Working from values, we searched for something that expresses *working towards a value available sometime later*. From there, we talked about the concept of polling. -A `Future` is any data type that does not represent a value, but the ability to _produce a value at some point in the future_. Implementations of this are very varied and detailled depending on use-case, but the interface is simple. - -From here on, we are going to introduce you to two other important concepts: `tasks` and `streams`, to then talk about how we combine the three to build things. +A `Future` is any data type that does not represent a value, but the ability to *produce a value at some point in the future*. Implementations of this are very varied and detailled depending on use-case, but the interface is simple. +Next, we will introduce you to `tasks`, which we need to actually *run* Futures. [^1]: Two parties reading while it is guaranteed that no one is writing is always safe. - -[poll-ready]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Ready -[poll-pending]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Pending -[futures-docs]: https://doc.rust-lang.org/std/future/trait.Future.html -[fearless-concurrency]: https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html -[understanding-computation]: https://computationbook.com/ -[threads]: https://en.wikipedia.org/wiki/Thread_(computing) diff --git a/docs/src/concepts/tasks.md b/docs/src/concepts/tasks.md index e33f9980..189ee136 100644 --- a/docs/src/concepts/tasks.md +++ b/docs/src/concepts/tasks.md @@ -1 +1,81 @@ -# tasks +# Tasks +Now that we know what Futures are, we now want to run them! + +In `async-std`, the `tasks` (TODO: link) module is responsible for this. The simplest way is using the `block_on` function: + +```rust +use async_std::fs::File; +use async_std::task; + +async fn read_file(path: &str) -> Result { + let mut file = File.open(path).await?; + let mut contents = String::new(); + file.read_to_string(&mut contents).await?; + contents +} + +fn main() { + let task = task::spawn(async { + let result = read_file("data.csv"); + match result { + Ok(s) => println!("{}", s), + Err(e) => println!("Error reading file: {:?}", e) + } + }); + println!("Started task!"); + task::block_on(task); + println!("Stopped task!"); +} +``` + +This asks the runtime baked into `async_std` to execute the code that reads a file. Let’s go one by one, though, inside to outside. + +```rust +async { + let result = read_file("data.csv"); + match result { + Ok(s) => println!("{}", s), + Err(e) => println!("Error reading file: {:?}", e) + } +} +``` + +This is an `async` *block*. Async blocks are necessary to call `async` functions, and will instruct the compiler to include all the relevant instructions to do so. In Rust, all blocks return a value and `async` blocks happen to return a value of the kind `Future`. + +But let’s get to the interesting part: + +```rust +task::spawn(async { }) +``` + +`spawn` takes a Future and starts running it on a `Task`. It returns a `JoinHandle`. Futures in Rust are sometimes called *cold* Futures. You need something that starts running them. To run a Future, there may be some additional bookkeeping required, e.g. if it’s running or finished, where it is being placed in memory and what the current state is. This bookkeeping part is abstracted away in a `Task`. A `Task` is similar to a `Thread`, with some minor differences: it will be scheduled by the program instead of the operating system kernel and if it encounters a point where it needs to wait, the program itself responsible for waking it up again. We’ll talk a little bit about that later. An `async_std` task can also has a name and an ID, just like a thread. + +For now, it is enough to know that once you `spawn`ed a task, it will continue running in the background. The `TaskHandle` in itself is a future that will finish once the `Task` ran to conclusion. Much like with `threads` and the `join` function, we can now call `block_on` on the handle to *block* the program (or the calling thread, to be specific) to wait for it to finish. + + +## Tasks in `async_std` + +Tasks in `async_std` are one of the core abstractions. Much like Rust’s `thread`s, they provide some practical functionality over the raw concept. `Tasks` have a relationship to the runtime, but they are in themselves separate. `async_std` tasks have a number of desirable properties: + + +- They are single-allocated +- All tasks have a *backchannel*, which allows them to propagate results and errors to the spawning task through the `TaskHandle` +- The carry desirable metadata for debugging +- They support task local storage + +`async_std` s task api handles setup and teardown of a backing runtime for you and doesn’t rely on a runtime being started. + +## Blocking + +TODO: fill me in + +## Errors and panics + +TODO: fill me in + + +## Conclusion + +`async_std` comes with a useful `Task` type that works with an API similar to `std::thread`. It covers error and panic behaviour in a structured and defined way. + +Tasks are separate concurrent units and sometimes they need to communicate. That’s where `Stream`s come in. diff --git a/docs/src/overview/std-and-library-futures.md b/docs/src/overview/std-and-library-futures.md index 4290f7f9..98cdfb44 100644 --- a/docs/src/overview/std-and-library-futures.md +++ b/docs/src/overview/std-and-library-futures.md @@ -1 +1,27 @@ -# `std::future` and `futures-rs` \ No newline at end of file +# `std::future` and `futures-rs` + +Rust has two kinds of types commonly referred to as `Future`: + + +- the first is `std::future::Future` from Rust’s [standard library](https://doc.rust-lang.org/std/future/trait.Future.html). +- the second is `futures::future::Future` from the [futures-rs crate](https://docs.rs/futures-preview/0.3.0-alpha.17/futures/prelude/trait.Future.html), currently released as `futures-preview`. + +The future defined in the [futures-rs](https://docs.rs/futures-preview/0.3.0-alpha.17/futures/prelude/trait.Future.html) crate was the original implementation of the type. To enable the `async/await` syntax, the core Future trait was moved into Rust’s standard library and became `std::future::Future`. In some sense, the `std``::future::Future` can be seen as a minimal subset of `futures::future::Future`. + +It is critical to understand the difference between `std::future::Future` and `futures::future::Future`, and the approach that `async-std` takes towards them. In itself, `std::future::Future` is not something you want to interact with as a user—except by calling `.await` on it. The inner workings of `std::future::Future` are mostly of interest to people implementing `Future`. Make no mistake—this is very useful! Most of the functionality that used to be defined on `Future` itself has been moved to an extension trait called `[FuturesExt](https://docs.rs/futures-preview/0.3.0-alpha.17/futures/future/trait.FutureExt.html)`. From this information, you might be able to infer that the `futures` library serves as an extension to the core Rust async features. + +In the same tradition as `futures`, `async-std` re-exports the core `std::future::``Future` type. You can get actively opt into the extensions provided by the `futures-preview` crate by adding it your `Cargo.toml` and importing `FuturesExt`. + +## Interfaces and Stability + + `async-std` aims to be a stable and reliable library, at the level of the Rust standard library. This also means that we don't rely on the `futures` library for our interface. Yet, we appreciate that many users have come to like the conveniences that `futures-rs` brings. For that reason, `async-std` implements all `futures` traits for its types. + + Luckily, the approach from above gives you full flexibility. If you care about stability a lot, you can just use `async-std` as is. If you prefer the `futures` library interfaces, you link those in.. Both uses are first class. + +## `async_std::future` + +There’s some support functions that we see as important for working with futures of any kind. These can be found in the `async_std::future` module and are covered by our stability guarantees. + +## Streams and Read/Write/Seek/BufRead traits + +Due to limitations of the Rust compiler, those are currently implemented in `async_std`, but cannot be implemented by users themselves. \ No newline at end of file From 54f3732787ae89ed58e54bffb1cb5b4d67871fab Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 12 Aug 2019 22:20:57 +0200 Subject: [PATCH 15/24] TaskHandle -> JoinHandle --- docs/src/concepts/tasks.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/concepts/tasks.md b/docs/src/concepts/tasks.md index 189ee136..a56cff50 100644 --- a/docs/src/concepts/tasks.md +++ b/docs/src/concepts/tasks.md @@ -45,12 +45,14 @@ This is an `async` *block*. Async blocks are necessary to call `async` functions But let’s get to the interesting part: ```rust + task::spawn(async { }) + ``` `spawn` takes a Future and starts running it on a `Task`. It returns a `JoinHandle`. Futures in Rust are sometimes called *cold* Futures. You need something that starts running them. To run a Future, there may be some additional bookkeeping required, e.g. if it’s running or finished, where it is being placed in memory and what the current state is. This bookkeeping part is abstracted away in a `Task`. A `Task` is similar to a `Thread`, with some minor differences: it will be scheduled by the program instead of the operating system kernel and if it encounters a point where it needs to wait, the program itself responsible for waking it up again. We’ll talk a little bit about that later. An `async_std` task can also has a name and an ID, just like a thread. -For now, it is enough to know that once you `spawn`ed a task, it will continue running in the background. The `TaskHandle` in itself is a future that will finish once the `Task` ran to conclusion. Much like with `threads` and the `join` function, we can now call `block_on` on the handle to *block* the program (or the calling thread, to be specific) to wait for it to finish. +For now, it is enough to know that once you `spawn`ed a task, it will continue running in the background. The `JoinHandle` in itself is a future that will finish once the `Task` ran to conclusion. Much like with `threads` and the `join` function, we can now call `block_on` on the handle to *block* the program (or the calling thread, to be specific) to wait for it to finish. ## Tasks in `async_std` @@ -59,7 +61,7 @@ Tasks in `async_std` are one of the core abstractions. Much like Rust’s `threa - They are single-allocated -- All tasks have a *backchannel*, which allows them to propagate results and errors to the spawning task through the `TaskHandle` +- All tasks have a *backchannel*, which allows them to propagate results and errors to the spawning task through the `JoinHandle` - The carry desirable metadata for debugging - They support task local storage From 52671bde0239559bcfb985823f7dea7d227e4588 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 12 Aug 2019 22:22:10 +0200 Subject: [PATCH 16/24] Fix patterns chapter --- docs/src/SUMMARY.md | 2 +- docs/src/patterns/small-patterns.md | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index a71a1beb..d800c707 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -17,7 +17,7 @@ - [Proper Shutdown](./patterns/proper-shutdown.md) - [Background Tasks](./patterns/background-tasks.md) - [Testing](./patterns/testing.md) - - [Collected Small Patterns](./patters/small-patterns.md) + - [Collected Small Patterns](./patterns/small-patterns.md) - [Security practices](./security/index.md) - [Security disclosures and policy](./security/policy.md) - [Glossary](./glossary.md) diff --git a/docs/src/patterns/small-patterns.md b/docs/src/patterns/small-patterns.md index 586702aa..2250d196 100644 --- a/docs/src/patterns/small-patterns.md +++ b/docs/src/patterns/small-patterns.md @@ -2,8 +2,6 @@ A collection of small, useful patterns. - - ## Splitting streams `async-std` doesn't provide a `split()` method on `io` handles. Instead, splitting a stream into a read and write half can be done like this: From a2e54fcd2990bdfea310acdac95b571485610505 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 12 Aug 2019 23:47:32 +0200 Subject: [PATCH 17/24] Replace crossbeam with crossbeam-channel --- Cargo.toml | 2 +- src/task/blocking.rs | 2 +- src/task/pool.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9c362713..45336f0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ docs = [] [dependencies] async-task = { git = "ssh://git@github.com/async-std/async-task.git" } cfg-if = "0.1.9" -crossbeam = "0.7.1" +crossbeam-channel = "0.3.9" futures-preview = "0.3.0-alpha.17" futures-timer = "0.3.0" lazy_static = "1.3.0" diff --git a/src/task/blocking.rs b/src/task/blocking.rs index da8338e3..9af16013 100644 --- a/src/task/blocking.rs +++ b/src/task/blocking.rs @@ -4,7 +4,7 @@ use std::fmt; use std::pin::Pin; use std::thread; -use crossbeam::channel::{unbounded, Receiver, Sender}; +use crossbeam_channel::{unbounded, Receiver, Sender}; use lazy_static::lazy_static; use crate::future::Future; diff --git a/src/task/pool.rs b/src/task/pool.rs index 0f70f14a..1f36bb01 100644 --- a/src/task/pool.rs +++ b/src/task/pool.rs @@ -6,7 +6,7 @@ use std::pin::Pin; use std::ptr; use std::thread; -use crossbeam::channel::{unbounded, Sender}; +use crossbeam_channel::{unbounded, Sender}; use futures::future::FutureExt; use lazy_static::lazy_static; From 09f032574652cf2134dca49700d56245ac4b12be Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Tue, 13 Aug 2019 20:17:26 +0200 Subject: [PATCH 18/24] Deactivate windows tests for now --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5a47885a..3b6cffcb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ matrix: os: linux - rust: nightly os: osx - - rust: nightly-x86_64-pc-windows-msvc - os: windows +# - rust: nightly-x86_64-pc-windows-msvc +# os: windows script: - cargo fmt --all -- --check From 019c8085f4d0a7836fe198644fbafc09054b7c93 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 14 Aug 2019 03:47:39 +0200 Subject: [PATCH 19/24] Cleanup examples --- examples/list-dir.rs | 5 ++++- examples/print-file.rs | 5 ++++- examples/stdin-echo.rs | 4 +++- examples/stdin-timeout.rs | 4 +++- examples/task-local.rs | 3 ++- examples/tcp-client.rs | 5 ++++- examples/tcp-echo.rs | 4 +++- examples/udp-client.rs | 4 +++- examples/udp-echo.rs | 4 +++- src/fs/dir_entry.rs | 12 ++++++++---- src/fs/read_dir.rs | 4 ++-- src/fs/read_to_string.rs | 11 ++++++----- src/fs/set_permissions.rs | 1 - src/future/pending.rs | 3 ++- src/io/buf_read.rs | 12 +++++++++--- src/io/copy.rs | 3 ++- src/io/read.rs | 12 ++++++++---- src/io/seek.rs | 4 +++- src/io/stderr.rs | 3 ++- src/io/stdin.rs | 11 ++++++----- src/io/stdout.rs | 3 ++- src/io/write.rs | 9 ++++++--- src/net/tcp/listener.rs | 7 +++++-- src/net/tcp/stream.rs | 6 ++++-- src/net/udp/mod.rs | 9 ++++++--- src/os/unix/net/mod.rs | 3 ++- src/prelude.rs | 2 ++ src/stream/empty.rs | 3 ++- src/stream/mod.rs | 3 ++- src/stream/once.rs | 3 ++- src/stream/repeat.rs | 3 ++- src/stream/stream.rs | 9 ++++++--- src/sync/mod.rs | 4 +++- src/sync/mutex.rs | 13 +++++++++---- src/task/local.rs | 15 ++++++++++++--- src/task/pool.rs | 4 ++-- src/task/sleep.rs | 3 ++- 37 files changed, 146 insertions(+), 67 deletions(-) diff --git a/examples/list-dir.rs b/examples/list-dir.rs index 545d68da..10c16d13 100644 --- a/examples/list-dir.rs +++ b/examples/list-dir.rs @@ -4,7 +4,10 @@ use std::env::args; -use async_std::{fs, io, prelude::*, task}; +use async_std::fs; +use async_std::io; +use async_std::prelude::*; +use async_std::task; fn main() -> io::Result<()> { let path = args().nth(1).expect("missing path argument"); diff --git a/examples/print-file.rs b/examples/print-file.rs index 49d02448..9c886359 100644 --- a/examples/print-file.rs +++ b/examples/print-file.rs @@ -4,7 +4,10 @@ use std::env::args; -use async_std::{fs::File, io, prelude::*, task}; +use async_std::fs::File; +use async_std::io; +use async_std::prelude::*; +use async_std::task; const LEN: usize = 4 * 1024 * 1024; // 4 Mb diff --git a/examples/stdin-echo.rs b/examples/stdin-echo.rs index e85bcbd0..6940654d 100644 --- a/examples/stdin-echo.rs +++ b/examples/stdin-echo.rs @@ -2,7 +2,9 @@ #![feature(async_await)] -use async_std::{io, prelude::*, task}; +use async_std::io; +use async_std::prelude::*; +use async_std::task; fn main() -> io::Result<()> { task::block_on(async { diff --git a/examples/stdin-timeout.rs b/examples/stdin-timeout.rs index 188112dc..dde49e5b 100644 --- a/examples/stdin-timeout.rs +++ b/examples/stdin-timeout.rs @@ -4,7 +4,9 @@ use std::time::Duration; -use async_std::{io, prelude::*, task}; +use async_std::io; +use async_std::prelude::*; +use async_std::task; fn main() -> io::Result<()> { task::block_on(async { diff --git a/examples/task-local.rs b/examples/task-local.rs index ed541803..50e14738 100644 --- a/examples/task-local.rs +++ b/examples/task-local.rs @@ -4,7 +4,8 @@ use std::cell::Cell; -use async_std::{task, task_local}; +use async_std::prelude::*; +use async_std::task; task_local! { static VAR: Cell = Cell::new(1); diff --git a/examples/tcp-client.rs b/examples/tcp-client.rs index 83e6a325..7a7b2b6a 100644 --- a/examples/tcp-client.rs +++ b/examples/tcp-client.rs @@ -14,7 +14,10 @@ #![feature(async_await)] -use async_std::{io, net::TcpStream, prelude::*, task}; +use async_Std::prelude::*; +use async_std::io; +use async_std::net::TcpStream; +use async_std::task; fn main() -> io::Result<()> { task::block_on(async { diff --git a/examples/tcp-echo.rs b/examples/tcp-echo.rs index 2c192cfa..a7238d24 100644 --- a/examples/tcp-echo.rs +++ b/examples/tcp-echo.rs @@ -8,8 +8,10 @@ #![feature(async_await)] +use async_stD::task; +use async_std::io; use async_std::net::{TcpListener, TcpStream}; -use async_std::{io, prelude::*, task}; +use async_std::prelude::*; async fn process(stream: TcpStream) -> io::Result<()> { println!("Accepted from: {}", stream.peer_addr()?); diff --git a/examples/udp-client.rs b/examples/udp-client.rs index defc6613..c1a8c924 100644 --- a/examples/udp-client.rs +++ b/examples/udp-client.rs @@ -14,7 +14,9 @@ #![feature(async_await)] -use async_std::{io, net::UdpSocket, task}; +use async_std::io; +use async_std::net::UdpSocket; +use async_std::task; fn main() -> io::Result<()> { task::block_on(async { diff --git a/examples/udp-echo.rs b/examples/udp-echo.rs index 5bb0bb47..0d17c007 100644 --- a/examples/udp-echo.rs +++ b/examples/udp-echo.rs @@ -8,7 +8,9 @@ #![feature(async_await)] -use async_std::{io, net::UdpSocket, task}; +use async_std::io; +use async_std::net::UdpSocket; +use async_std::task; fn main() -> io::Result<()> { task::block_on(async { diff --git a/src/fs/dir_entry.rs b/src/fs/dir_entry.rs index 105f22e4..761f1427 100644 --- a/src/fs/dir_entry.rs +++ b/src/fs/dir_entry.rs @@ -77,7 +77,8 @@ impl DirEntry { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs, prelude::*}; + /// use async_std::fs; + /// use async_std::prelude::*; /// /// let mut dir = fs::read_dir(".").await?; /// @@ -102,7 +103,8 @@ impl DirEntry { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs, prelude::*}; + /// use async_std::fs; + /// use async_std::prelude::*; /// /// let mut dir = fs::read_dir(".").await?; /// @@ -155,7 +157,8 @@ impl DirEntry { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs, prelude::*}; + /// use async_std::fs; + /// use async_Std::prelude::*; /// /// let mut dir = fs::read_dir(".").await?; /// @@ -206,7 +209,8 @@ impl DirEntry { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs, prelude::*}; + /// use async_std::fs; + /// use async_std::prelude::*; /// /// let mut dir = fs::read_dir(".").await?; /// diff --git a/src/fs/read_dir.rs b/src/fs/read_dir.rs index 04923736..7bdd5322 100644 --- a/src/fs/read_dir.rs +++ b/src/fs/read_dir.rs @@ -1,5 +1,4 @@ use std::fs; - use std::path::Path; use std::pin::Pin; use std::sync::Mutex; @@ -34,7 +33,8 @@ use crate::task::{blocking, Context, Poll}; /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # -/// use async_std::{fs, prelude::*}; +/// use async_std::fs; +/// use async_std::prelude::*; /// /// let mut dir = fs::read_dir(".").await?; /// diff --git a/src/fs/read_to_string.rs b/src/fs/read_to_string.rs index 2f771fa2..b6bd858b 100644 --- a/src/fs/read_to_string.rs +++ b/src/fs/read_to_string.rs @@ -21,12 +21,13 @@ use crate::task::blocking; /// /// ```no_run /// # #![feature(async_await)] -/// use async_std::fs::read_to_string; +/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +/// # +/// use async_std::fs; /// -/// # futures::executor::block_on(async { -/// let contents = read_to_string("a.txt").await?; -/// # std::io::Result::Ok(()) -/// # }).unwrap(); +/// let contents = fs::read_to_string("a.txt").await?; +/// # +/// # Ok(()) }) } /// ``` pub async fn read_to_string>(path: P) -> io::Result { let path = path.as_ref().to_owned(); diff --git a/src/fs/set_permissions.rs b/src/fs/set_permissions.rs index e5e1c2ad..96342219 100644 --- a/src/fs/set_permissions.rs +++ b/src/fs/set_permissions.rs @@ -27,7 +27,6 @@ use crate::task::blocking; /// /// let mut perm = fs::metadata("a.txt").await?.permissions(); /// perm.set_readonly(true); -/// /// fs::set_permissions("a.txt", perm).await?; /// # /// # Ok(()) }) } diff --git a/src/future/pending.rs b/src/future/pending.rs index f1ec26e6..f45199f2 100644 --- a/src/future/pending.rs +++ b/src/future/pending.rs @@ -5,9 +5,10 @@ /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # +/// use std::time::Duration; +/// /// use async_std::future::pending; /// use async_std::prelude::*; -/// use std::time::Duration; /// /// let dur = Duration::from_secs(1); /// assert!(pending::<()>().timeout(dur).await.is_err()); diff --git a/src/io/buf_read.rs b/src/io/buf_read.rs index 62530376..40ab337d 100644 --- a/src/io/buf_read.rs +++ b/src/io/buf_read.rs @@ -49,7 +49,9 @@ pub trait BufRead { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, io::BufReader, prelude::*}; + /// use async_std::fs::File; + /// use async_std::io::BufReader; + /// use async_std::prelude::*; /// /// let mut f = BufReader::new(File::open("a.txt").await?); /// @@ -98,7 +100,9 @@ pub trait BufRead { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, io::BufReader, prelude::*}; + /// use async_std::fs::File; + /// use async_std::io::BufReader; + /// use async_std::prelude::*; /// /// let mut f = BufReader::new(File::open("a.txt").await?); /// @@ -137,7 +141,9 @@ pub trait BufRead { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, io::BufReader, prelude::*}; + /// use async_std::fs::File; + /// use async_std::io::BufReader; + /// use async_std::prelude::*; /// /// let mut f = BufReader::new(File::open("a.txt").await?); /// diff --git a/src/io/copy.rs b/src/io/copy.rs index 01894e80..abb45ff7 100644 --- a/src/io/copy.rs +++ b/src/io/copy.rs @@ -31,7 +31,8 @@ use crate::io; /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # -/// use async_std::{io, task}; +/// use async_std::io; +/// use async_std::task; /// /// let mut reader: &[u8] = b"hello"; /// let mut writer = io::stdout(); diff --git a/src/io/read.rs b/src/io/read.rs index ff3dc33f..d33ec0f9 100644 --- a/src/io/read.rs +++ b/src/io/read.rs @@ -55,7 +55,8 @@ pub trait Read { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, prelude::*}; + /// use async_std::fs::File; + /// use async_std::prelude::*; /// /// let mut f = File::open("a.txt").await?; /// @@ -104,7 +105,8 @@ pub trait Read { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, prelude::*}; + /// use async_std::fs::File; + /// use async_std::prelude::*; /// /// let mut f = File::open("a.txt").await?; /// @@ -141,7 +143,8 @@ pub trait Read { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, prelude::*}; + /// use async_std::fs::File; + /// use async_std::prelude::*; /// /// let mut f = File::open("a.txt").await?; /// @@ -193,7 +196,8 @@ pub trait Read { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, prelude::*}; + /// use async_std::fs::File; + /// use async_std::prelude::*; /// /// let mut f = File::open("a.txt").await?; /// diff --git a/src/io/seek.rs b/src/io/seek.rs index 110642cb..49aaed1a 100644 --- a/src/io/seek.rs +++ b/src/io/seek.rs @@ -47,7 +47,9 @@ pub trait Seek { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, io::SeekFrom, prelude::*}; + /// use async_std::fs::File; + /// use async_std::io::SeekFrom; + /// use async_std::prelude::*; /// /// let mut f = File::open("a.txt").await?; /// diff --git a/src/io/stderr.rs b/src/io/stderr.rs index 354a9580..9983f61d 100644 --- a/src/io/stderr.rs +++ b/src/io/stderr.rs @@ -19,7 +19,8 @@ use crate::task::{blocking, Context, Poll}; /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # -/// use async_std::{io, prelude::*}; +/// use async_std::io; +/// use async_std::prelude::*; /// /// let mut stderr = io::stderr(); /// stderr.write_all(b"Hello, world!").await?; diff --git a/src/io/stdin.rs b/src/io/stdin.rs index 4449e217..8747e7e9 100644 --- a/src/io/stdin.rs +++ b/src/io/stdin.rs @@ -93,14 +93,15 @@ impl Stdin { /// /// ```no_run /// # #![feature(async_await)] - /// use async_std::io::stdin; + /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + /// # + /// use async_std::io; /// - /// # futures::executor::block_on(async { - /// let stdin = stdin(); + /// let stdin = io::stdin(); /// let mut line = String::new(); /// stdin.read_line(&mut line).await?; - /// # std::io::Result::Ok(()) - /// # }).unwrap(); + /// # + /// # Ok(()) }) } /// ``` pub async fn read_line(&self, buf: &mut String) -> io::Result { future::poll_fn(|cx| { diff --git a/src/io/stdout.rs b/src/io/stdout.rs index 09116465..9100f241 100644 --- a/src/io/stdout.rs +++ b/src/io/stdout.rs @@ -19,7 +19,8 @@ use crate::task::{blocking, Context, Poll}; /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # -/// use async_std::{io, prelude::*}; +/// use async_std::io; +/// use async_std::prelude::*; /// /// let mut stdout = io::stdout(); /// stdout.write_all(b"Hello, world!").await?; diff --git a/src/io/write.rs b/src/io/write.rs index 9e90588e..356aee63 100644 --- a/src/io/write.rs +++ b/src/io/write.rs @@ -50,7 +50,8 @@ pub trait Write { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, prelude::*}; + /// use async_std::fs::File; + /// use async_std::prelude::*; /// /// let mut f = File::create("a.txt").await?; /// @@ -70,7 +71,8 @@ pub trait Write { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, prelude::*}; + /// use async_std::fs::File; + /// use async_std::prelude::*; /// /// let mut f = File::create("a.txt").await?; /// @@ -115,7 +117,8 @@ pub trait Write { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{fs::File, prelude::*}; + /// use async_std::fs::File; + /// use async_std::prelude::*; /// /// let mut f = File::create("a.txt").await?; /// diff --git a/src/net/tcp/listener.rs b/src/net/tcp/listener.rs index 32a67a86..e85d90b7 100644 --- a/src/net/tcp/listener.rs +++ b/src/net/tcp/listener.rs @@ -33,7 +33,9 @@ use crate::task::{Context, Poll}; /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # -/// use async_std::{io, net::TcpListener, prelude::*}; +/// use async_std::io; +/// use async_std::net::TcpListener; +/// use async_std::prelude::*; /// /// let listener = TcpListener::bind("127.0.0.1:8080").await?; /// let mut incoming = listener.incoming(); @@ -173,7 +175,8 @@ impl TcpListener { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{net::TcpListener, prelude::*}; + /// use async_std::net::TcpListener; + /// use async_std::prelude::*; /// /// let listener = TcpListener::bind("127.0.0.1:0").await?; /// let mut incoming = listener.incoming(); diff --git a/src/net/tcp/stream.rs b/src/net/tcp/stream.rs index 2a36ae57..234467a5 100644 --- a/src/net/tcp/stream.rs +++ b/src/net/tcp/stream.rs @@ -36,7 +36,8 @@ use crate::task::{Context, Poll}; /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # -/// use async_std::{net::TcpStream, prelude::*}; +/// use async_std::net::TcpStream; +/// use async_std::prelude::*; /// /// let mut stream = TcpStream::connect("127.0.0.1:8080").await?; /// stream.write_all(b"hello world").await?; @@ -340,9 +341,10 @@ impl TcpStream { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::net::TcpStream; /// use std::net::Shutdown; /// + /// use async_std::net::TcpStream; + /// /// let stream = TcpStream::connect("127.0.0.1:8080").await?; /// stream.shutdown(Shutdown::Both)?; /// # diff --git a/src/net/udp/mod.rs b/src/net/udp/mod.rs index 50774d66..9fc98500 100644 --- a/src/net/udp/mod.rs +++ b/src/net/udp/mod.rs @@ -117,9 +117,10 @@ impl UdpSocket { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::net::UdpSocket; /// use std::net::IpAddr; /// + /// use async_std::net::UdpSocket; + /// /// let socket = UdpSocket::bind("127.0.0.1:0").await?; /// let addr = socket.local_addr()?; /// # @@ -446,9 +447,10 @@ impl UdpSocket { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::net::UdpSocket; /// use std::net::Ipv4Addr; /// + /// use async_std::net::UdpSocket; + /// /// let interface = Ipv4Addr::new(0, 0, 0, 0); /// let mdns_addr = Ipv4Addr::new(224, 0, 0, 123); /// @@ -475,9 +477,10 @@ impl UdpSocket { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::net::UdpSocket; /// use std::net::{Ipv6Addr, SocketAddr}; /// + /// use async_std::net::UdpSocket; + /// /// let socket_addr = SocketAddr::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).into(), 0); /// let mdns_addr = Ipv6Addr::new(0xFF02, 0, 0, 0, 0, 0, 0, 0x0123) ; /// let socket = UdpSocket::bind(&socket_addr).await?; diff --git a/src/os/unix/net/mod.rs b/src/os/unix/net/mod.rs index 45062c48..1597948f 100644 --- a/src/os/unix/net/mod.rs +++ b/src/os/unix/net/mod.rs @@ -65,9 +65,10 @@ cfg_if! { /// With a pathname: /// /// ```no_run - /// use async_std::os::unix::net::UnixListener; /// use std::path::Path; /// + /// use async_std::os::unix::net::UnixListener; + /// /// let socket = UnixListener::bind("/tmp/socket").await?; /// let addr = socket.local_addr()?; /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/socket"))); diff --git a/src/prelude.rs b/src/prelude.rs index 1f35312a..90df8e5f 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -37,4 +37,6 @@ pub use crate::io::Write as _; #[doc(no_inline)] pub use crate::stream::Stream; #[doc(no_inline)] +pub use crate::task_local; +#[doc(no_inline)] pub use crate::time::Timeout as _; diff --git a/src/stream/empty.rs b/src/stream/empty.rs index eed60648..c03146e8 100644 --- a/src/stream/empty.rs +++ b/src/stream/empty.rs @@ -11,7 +11,8 @@ use crate::task::{Context, Poll}; /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # -/// use async_std::{prelude::*, stream}; +/// use async_std::prelude::*; +/// use async_std::stream; /// /// let mut s = stream::empty::(); /// diff --git a/src/stream/mod.rs b/src/stream/mod.rs index 5100ede5..a760a9b7 100644 --- a/src/stream/mod.rs +++ b/src/stream/mod.rs @@ -10,7 +10,8 @@ //! # #![feature(async_await)] //! # fn main() { async_std::task::block_on(async { //! # -//! use async_std::{prelude::*, stream}; +//! use async_std::prelude::*; +//! use async_std::stream; //! //! let mut s = stream::repeat(9).take(3); //! diff --git a/src/stream/once.rs b/src/stream/once.rs index 36a6ebac..7c1e45b2 100644 --- a/src/stream/once.rs +++ b/src/stream/once.rs @@ -10,7 +10,8 @@ use crate::task::{Context, Poll}; /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # -/// use async_std::{prelude::*, stream}; +/// use async_std::prelude::*; +/// use async_std::stream; /// /// let mut s = stream::once(7); /// diff --git a/src/stream/repeat.rs b/src/stream/repeat.rs index 84847c47..4b4b4422 100644 --- a/src/stream/repeat.rs +++ b/src/stream/repeat.rs @@ -10,7 +10,8 @@ use crate::task::{Context, Poll}; /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # -/// use async_std::{prelude::*, stream}; +/// use async_std::prelude::*; +/// use async_std::stream; /// /// let mut s = stream::repeat(7); /// diff --git a/src/stream/stream.rs b/src/stream/stream.rs index 62e9f4ec..4421d31d 100644 --- a/src/stream/stream.rs +++ b/src/stream/stream.rs @@ -10,7 +10,8 @@ //! # #![feature(async_await)] //! # fn main() { async_std::task::block_on(async { //! # -//! use async_std::{prelude::*, stream}; +//! use async_std::prelude::*; +//! use async_std::stream; //! //! let mut s = stream::repeat(9).take(3); //! @@ -71,7 +72,8 @@ pub trait Stream { /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # - /// use async_std::{prelude::*, stream}; + /// use async_std::prelude::*; + /// use async_std::stream; /// /// let mut s = stream::once(7); /// @@ -92,7 +94,8 @@ pub trait Stream { /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # - /// use async_std::{prelude::*, stream}; + /// use async_std::prelude::*; + /// use async_std::stream; /// /// let mut s = stream::repeat(9).take(3); /// diff --git a/src/sync/mod.rs b/src/sync/mod.rs index ae27f896..1a4b0680 100644 --- a/src/sync/mod.rs +++ b/src/sync/mod.rs @@ -12,9 +12,11 @@ //! # #![feature(async_await)] //! # fn main() { async_std::task::block_on(async { //! # -//! use async_std::{sync::Mutex, task}; //! use std::sync::Arc; //! +//! use async_std::sync::Mutex; +//! use async_std::task; +//! //! let m1 = Arc::new(Mutex::new(0)); //! let m2 = m1.clone(); //! diff --git a/src/sync/mutex.rs b/src/sync/mutex.rs index d629a290..d0f110b6 100644 --- a/src/sync/mutex.rs +++ b/src/sync/mutex.rs @@ -27,9 +27,11 @@ const BLOCKED: usize = 1 << 1; /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # -/// use async_std::{sync::Mutex, task}; /// use std::sync::Arc; /// +/// use async_std::sync::Mutex; +/// use async_std::task; +/// /// let m = Arc::new(Mutex::new(0)); /// let mut tasks = vec![]; /// @@ -84,9 +86,11 @@ impl Mutex { /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # - /// use async_std::{sync::Mutex, task}; /// use std::sync::Arc; /// + /// use async_std::sync::Mutex; + /// use async_std::task; + /// /// let m1 = Arc::new(Mutex::new(10)); /// let m2 = m1.clone(); /// @@ -197,9 +201,11 @@ impl Mutex { /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # - /// use async_std::{sync::Mutex, task}; /// use std::sync::Arc; /// + /// use async_std::sync::Mutex; + /// use async_std::task; + /// /// let m1 = Arc::new(Mutex::new(10)); /// let m2 = m1.clone(); /// @@ -229,7 +235,6 @@ impl Mutex { /// # Examples /// /// ``` - /// # #![feature(async_await)] /// use async_std::sync::Mutex; /// /// let mutex = Mutex::new(10); diff --git a/src/task/local.rs b/src/task/local.rs index f853a83d..eb34801f 100644 --- a/src/task/local.rs +++ b/src/task/local.rs @@ -21,9 +21,12 @@ use super::pool; /// /// ``` /// # #![feature(async_await)] -/// use async_std::{task, task_local}; +/// # /// use std::cell::Cell; /// +/// use async_std::task; +/// use async_std::prelude::*; +/// /// task_local! { /// static VAL: Cell = Cell::new(5); /// } @@ -90,9 +93,12 @@ impl LocalKey { /// /// ``` /// # #![feature(async_await)] - /// use async_std::{task, task_local}; + /// # /// use std::cell::Cell; /// + /// use async_std::task; + /// use async_std::prelude::*; + /// /// task_local! { /// static NUMBER: Cell = Cell::new(5); /// } @@ -127,9 +133,12 @@ impl LocalKey { /// /// ``` /// # #![feature(async_await)] - /// use async_std::{task, task_local}; + /// # /// use std::cell::Cell; /// + /// use async_std::task; + /// use async_std::prelude::*; + /// /// task_local! { /// static VAL: Cell = Cell::new(5); /// } diff --git a/src/task/pool.rs b/src/task/pool.rs index 1f36bb01..331b03c2 100644 --- a/src/task/pool.rs +++ b/src/task/pool.rs @@ -32,9 +32,9 @@ use crate::io; /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # -/// use async_std::task::current; +/// use async_std::task; /// -/// println!("The name of this task is {:?}", current().name()); +/// println!("The name of this task is {:?}", task::current().name()); /// # /// # }) } /// ``` diff --git a/src/task/sleep.rs b/src/task/sleep.rs index 2739d875..a0392be6 100644 --- a/src/task/sleep.rs +++ b/src/task/sleep.rs @@ -18,9 +18,10 @@ use crate::time::Timeout; /// # #![feature(async_await)] /// # fn main() { async_std::task::block_on(async { /// # -/// use async_std::task; /// use std::time::Duration; /// +/// use async_std::task; +/// /// task::sleep(Duration::from_secs(1)).await; /// # /// # }) } From d287237f7b0c1c68db38adb6c2db29355744a669 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 14 Aug 2019 03:58:58 +0200 Subject: [PATCH 20/24] Deny warnings on Travis --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3b6cffcb..06bc7c6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,8 @@ language: rust +env: + - RUSTFLAGS="-D warnings" + before_script: - rustup component add rustfmt From e459bd048e43c716738609c16aeda212bb5c58f0 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 14 Aug 2019 04:22:37 +0200 Subject: [PATCH 21/24] Cleanup and docs --- examples/line-count.rs | 5 ++--- examples/tcp-client.rs | 2 +- examples/tcp-echo.rs | 2 +- src/fs/dir_entry.rs | 2 +- src/fs/file.rs | 7 +++---- src/io/buf_read.rs | 13 ++++++------- src/io/copy.rs | 1 - src/lib.rs | 2 ++ src/net/mod.rs | 2 +- src/net/udp/mod.rs | 4 +--- src/os/unix/net/datagram.rs | 8 ++++---- src/sync/rwlock.rs | 4 ++-- src/task/task.rs | 2 +- 13 files changed, 25 insertions(+), 29 deletions(-) diff --git a/examples/line-count.rs b/examples/line-count.rs index a01cb5e1..367789a2 100644 --- a/examples/line-count.rs +++ b/examples/line-count.rs @@ -13,9 +13,8 @@ fn main() -> io::Result<()> { let path = args().nth(1).expect("missing path argument"); task::block_on(async { - let file = BufReader::new(File::open(&path).await?); - - let mut lines = file.lines(); + let file = File::open(&path).await?; + let mut lines = BufReader::new(file).lines(); let mut count = 0u64; while let Some(line) = lines.next().await { diff --git a/examples/tcp-client.rs b/examples/tcp-client.rs index 7a7b2b6a..b6c0ae71 100644 --- a/examples/tcp-client.rs +++ b/examples/tcp-client.rs @@ -14,9 +14,9 @@ #![feature(async_await)] -use async_Std::prelude::*; use async_std::io; use async_std::net::TcpStream; +use async_std::prelude::*; use async_std::task; fn main() -> io::Result<()> { diff --git a/examples/tcp-echo.rs b/examples/tcp-echo.rs index a7238d24..08164397 100644 --- a/examples/tcp-echo.rs +++ b/examples/tcp-echo.rs @@ -8,10 +8,10 @@ #![feature(async_await)] -use async_stD::task; use async_std::io; use async_std::net::{TcpListener, TcpStream}; use async_std::prelude::*; +use async_std::task; async fn process(stream: TcpStream) -> io::Result<()> { println!("Accepted from: {}", stream.peer_addr()?); diff --git a/src/fs/dir_entry.rs b/src/fs/dir_entry.rs index 761f1427..b2312c00 100644 --- a/src/fs/dir_entry.rs +++ b/src/fs/dir_entry.rs @@ -158,7 +158,7 @@ impl DirEntry { /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # /// use async_std::fs; - /// use async_Std::prelude::*; + /// use async_std::prelude::*; /// /// let mut dir = fs::read_dir(".").await?; /// diff --git a/src/fs/file.rs b/src/fs/file.rs index 6f6b8981..330c61f7 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -338,9 +338,8 @@ impl File { /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # /// use async_std::fs::File; - /// use async_std::prelude::*; /// - /// let mut file = File::create("a.txt").await?; + /// let file = File::create("a.txt").await?; /// file.set_len(10).await?; /// # /// # Ok(()) }) } @@ -438,9 +437,9 @@ impl File { /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # /// use async_std::fs::File; - /// use async_std::prelude::*; /// - /// let mut file = File::create("a.txt").await?; + /// let file = File::create("a.txt").await?; + /// /// let mut perms = file.metadata().await?.permissions(); /// perms.set_readonly(true); /// file.set_permissions(perms).await?; diff --git a/src/io/buf_read.rs b/src/io/buf_read.rs index 40ab337d..fa010ed8 100644 --- a/src/io/buf_read.rs +++ b/src/io/buf_read.rs @@ -53,10 +53,10 @@ pub trait BufRead { /// use async_std::io::BufReader; /// use async_std::prelude::*; /// - /// let mut f = BufReader::new(File::open("a.txt").await?); + /// let mut file = BufReader::new(File::open("a.txt").await?); /// /// let mut buf = vec![0; 1024]; - /// let n = f.read_until(b'\n', &mut buf).await?; + /// let n = file.read_until(b'\n', &mut buf).await?; /// # /// # Ok(()) }) } /// ``` @@ -104,10 +104,10 @@ pub trait BufRead { /// use async_std::io::BufReader; /// use async_std::prelude::*; /// - /// let mut f = BufReader::new(File::open("a.txt").await?); + /// let mut file = BufReader::new(File::open("a.txt").await?); /// /// let mut buf = String::new(); - /// f.read_line(&mut buf).await?; + /// file.read_line(&mut buf).await?; /// # /// # Ok(()) }) } /// ``` @@ -145,9 +145,8 @@ pub trait BufRead { /// use async_std::io::BufReader; /// use async_std::prelude::*; /// - /// let mut f = BufReader::new(File::open("a.txt").await?); - /// - /// let mut lines = f.lines(); + /// let file = File::open("a.txt").await?; + /// let mut lines = BufReader::new(file).lines(); /// let mut count = 0; /// /// for line in lines.next().await { diff --git a/src/io/copy.rs b/src/io/copy.rs index abb45ff7..829bf0c5 100644 --- a/src/io/copy.rs +++ b/src/io/copy.rs @@ -32,7 +32,6 @@ use crate::io; /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # /// use async_std::io; -/// use async_std::task; /// /// let mut reader: &[u8] = b"hello"; /// let mut writer = io::stdout(); diff --git a/src/lib.rs b/src/lib.rs index ceb58a99..2cefbc9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,8 @@ #![feature(async_await)] #![cfg_attr(feature = "docs", feature(doc_cfg))] #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] +#![doc(test(attr(deny(rust_2018_idioms, warnings))))] +#![doc(test(attr(allow(unused_extern_crates, unused_variables))))] #![doc(html_logo_url = "https://async.rs/images/logo--hero.svg")] pub mod fs; diff --git a/src/net/mod.rs b/src/net/mod.rs index 00d752f4..6ec9439e 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -26,7 +26,7 @@ //! socket.send_to(&buf[..n], &peer).await?; //! } //! # -//! # Ok(()) }) } +//! # }) } //! ``` pub use tcp::{Incoming, TcpListener, TcpStream}; diff --git a/src/net/udp/mod.rs b/src/net/udp/mod.rs index 9fc98500..04f1c55f 100644 --- a/src/net/udp/mod.rs +++ b/src/net/udp/mod.rs @@ -42,7 +42,7 @@ use crate::task::Poll; /// socket.send_to(&buf[..n], &peer).await?; /// } /// # -/// # Ok(()) }) } +/// # }) } /// ``` #[derive(Debug)] pub struct UdpSocket { @@ -117,8 +117,6 @@ impl UdpSocket { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use std::net::IpAddr; - /// /// use async_std::net::UdpSocket; /// /// let socket = UdpSocket::bind("127.0.0.1:0").await?; diff --git a/src/os/unix/net/datagram.rs b/src/os/unix/net/datagram.rs index 8886689e..8ad24c58 100644 --- a/src/os/unix/net/datagram.rs +++ b/src/os/unix/net/datagram.rs @@ -181,7 +181,7 @@ impl UnixDatagram { /// # /// use async_std::os::unix::net::UnixDatagram; /// - /// let mut socket = UnixDatagram::unbound()?; + /// let socket = UnixDatagram::unbound()?; /// socket.connect("/tmp/socket").await?; /// let peer = socket.peer_addr()?; /// # @@ -203,7 +203,7 @@ impl UnixDatagram { /// # /// use async_std::os::unix::net::UnixDatagram; /// - /// let mut socket = UnixDatagram::unbound()?; + /// let socket = UnixDatagram::unbound()?; /// let mut buf = vec![0; 1024]; /// let (n, peer) = socket.recv_from(&mut buf).await?; /// # @@ -271,7 +271,7 @@ impl UnixDatagram { /// # /// use async_std::os::unix::net::UnixDatagram; /// - /// let mut socket = UnixDatagram::unbound()?; + /// let socket = UnixDatagram::unbound()?; /// socket.send_to(b"hello world", "/tmp/socket").await?; /// # /// # Ok(()) }) } @@ -304,7 +304,7 @@ impl UnixDatagram { /// # /// use async_std::os::unix::net::UnixDatagram; /// - /// let mut socket = UnixDatagram::unbound()?; + /// let socket = UnixDatagram::unbound()?; /// socket.connect("/tmp/socket").await?; /// socket.send(b"hello world").await?; /// # diff --git a/src/sync/rwlock.rs b/src/sync/rwlock.rs index a345ff9a..647a3bc3 100644 --- a/src/sync/rwlock.rs +++ b/src/sync/rwlock.rs @@ -220,7 +220,7 @@ impl RwLock { /// /// let lock = RwLock::new(1); /// - /// let mut n = lock.read().await; + /// let n = lock.read().await; /// assert_eq!(*n, 1); /// /// assert!(lock.try_read().is_some()); @@ -385,7 +385,7 @@ impl RwLock { /// /// let lock = RwLock::new(1); /// - /// let mut n = lock.read().await; + /// let n = lock.read().await; /// assert_eq!(*n, 1); /// /// assert!(lock.try_write().is_none()); diff --git a/src/task/task.rs b/src/task/task.rs index 834b2ac4..03947ae3 100644 --- a/src/task/task.rs +++ b/src/task/task.rs @@ -184,7 +184,7 @@ impl Tag { let new = mem::transmute::>(new_raw); drop(new); } - }; + } mem::transmute::<&AtomicUsize, &Option>(&self.raw_metadata) .as_ref() From dd408877506897e11c20eac4a942ff92433fdb5c Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 14 Aug 2019 15:35:46 +0200 Subject: [PATCH 22/24] Formatting --- src/io/buf_read.rs | 2 +- src/io/buf_reader.rs | 4 ++-- src/io/seek.rs | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/io/buf_read.rs b/src/io/buf_read.rs index fa010ed8..a7bfeed6 100644 --- a/src/io/buf_read.rs +++ b/src/io/buf_read.rs @@ -1,4 +1,3 @@ -use std::io; use std::mem; use std::pin::Pin; use std::str; @@ -7,6 +6,7 @@ use cfg_if::cfg_if; use futures::io::AsyncBufRead; use crate::future::Future; +use crate::io; use crate::task::{Context, Poll}; cfg_if! { diff --git a/src/io/buf_reader.rs b/src/io/buf_reader.rs index fb90c8dd..bf9adce3 100644 --- a/src/io/buf_reader.rs +++ b/src/io/buf_reader.rs @@ -1,10 +1,10 @@ -use std::io::{IoSliceMut, Read as _, SeekFrom}; +use std::io::{IoSliceMut, Read as _}; use std::pin::Pin; use std::{cmp, fmt}; use futures::io::{AsyncBufRead, AsyncRead, AsyncSeek, Initializer}; -use crate::io; +use crate::io::{self, SeekFrom}; use crate::task::{Context, Poll}; const DEFAULT_CAPACITY: usize = 8 * 1024; diff --git a/src/io/seek.rs b/src/io/seek.rs index 49aaed1a..00ac6414 100644 --- a/src/io/seek.rs +++ b/src/io/seek.rs @@ -1,11 +1,10 @@ -use std::io::SeekFrom; use std::pin::Pin; use cfg_if::cfg_if; use futures::io::AsyncSeek; use crate::future::Future; -use crate::io; +use crate::io::{self, SeekFrom}; use crate::task::{Context, Poll}; cfg_if! { From 13835b0a78edba7657df308549f8f0e7933f4c94 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 14 Aug 2019 15:57:51 +0200 Subject: [PATCH 23/24] Formatting --- src/prelude.rs | 4 +++- src/time/mod.rs | 4 +++- src/time/timeout.rs | 4 +++- tests/task_local.rs | 3 ++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/prelude.rs b/src/prelude.rs index 90df8e5f..eabd92f8 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -10,9 +10,11 @@ //! # #![feature(async_await)] //! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { //! # -//! use async_std::{io, prelude::*}; //! use std::time::Duration; //! +//! use async_std::io; +//! use async_std::prelude::*; +//! //! let stdin = io::stdin(); //! let mut line = String::new(); //! let dur = Duration::from_secs(5); diff --git a/src/time/mod.rs b/src/time/mod.rs index 78a554ac..f8f389cd 100644 --- a/src/time/mod.rs +++ b/src/time/mod.rs @@ -12,9 +12,11 @@ //! # #![feature(async_await)] //! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { //! # -//! use async_std::{io, prelude::*}; //! use std::time::Duration; //! +//! use async_std::io; +//! use async_std::prelude::*; +//! //! let stdin = io::stdin(); //! let mut line = String::new(); //! diff --git a/src/time/timeout.rs b/src/time/timeout.rs index ef60f0f6..9f21bcc4 100644 --- a/src/time/timeout.rs +++ b/src/time/timeout.rs @@ -54,9 +54,11 @@ pub trait Timeout: Future + Sized { /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # - /// use async_std::{io, prelude::*}; /// use std::time::Duration; /// + /// use async_std::io; + /// use async_std::prelude::*; + /// /// let stdin = io::stdin(); /// let mut line = String::new(); /// diff --git a/tests/task_local.rs b/tests/task_local.rs index eb18637c..e910b079 100644 --- a/tests/task_local.rs +++ b/tests/task_local.rs @@ -2,7 +2,8 @@ use std::sync::atomic::{AtomicBool, Ordering}; -use async_std::{task, task_local}; +use async_std::task; +use async_std::task_local; #[test] fn drop_local() { From f8633ab1952f83c078e1fa65af464be45f35aaaa Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Wed, 14 Aug 2019 17:56:05 +0200 Subject: [PATCH 24/24] Fix git location --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 45336f0d..f675ec49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ rustdoc-args = ["--features docs"] docs = [] [dependencies] -async-task = { git = "ssh://git@github.com/async-std/async-task.git" } +async-task = { git = "ssh://git@github.com/async-rs/async-task.git" } cfg-if = "0.1.9" crossbeam-channel = "0.3.9" futures-preview = "0.3.0-alpha.17"