Add `reqwest` and `scraper` dependencies to the `trpl` crate. Wrap them
in `trpl` re-exports which keep the API surface low.
Rewrite the whole first section to use `race` along with those `trpl`
re-exports to show a more “real” example of async code right form the
start, including actual concurrency, unlike the previous introduction.
Update 17.03 to account for having introduced `race` already, and update
listing numbers for rewritten 17.01.
The *inclues* for them were fixed already, but not these!
The `block_on` name is what both Tokio and smol use, but it is a bit
obscure from the point of view of introducing this material. `run` says
much more clearly what it does *for the level we care about here*, I
think.
Eliminate `trpl::timeout` entirely. Instead, just build the `timeout`
directly (as the rest of the section already did). Restructure the
listings as well, eliminating duplication and extraneous bits.
Use `IntervalStream` and `ReceiverStream` to show the composition of
multiple streams, along with throttling and timeouts. This will also
provide a useful foundation for discussing the relationships between
futures, tasks, and threads in the final sections of the book, since
you can accomplish the same basic API by simply substituting threads
for tasks—but with different tradeoffs!
- Rexport `tokio::fs::read_to_string` as `trpl::read_to_string`.
- Add a no-listing example for the mutable borrow example. This will
keep us honest that the code there itself compiles just fine!
- Update the implementation for `race` to use `futures::future::Either`
instead of duplicating the type, and update the test not to try to use
equality.
- Add a `pub use` for `tokio::task::yield_now`.
Create a `trpl::race` function which simplifies the `select` API by
ignoring the future which resolves second. Use the `race` function to
show how you can implement an even simpler `timeout` function on top of
it, i.e. showing how futures can compose nicely. With that in place,
there is enough to be able to “work up to it” in the body of the text.
Up to this point, the chapter has stuck to `join` and `join3`, as simple
function-based APIs. The `join_all` API is obviously more convenient
than those *if you can use it*, but being able to use it requires having
something which `impl Iterator` of a given type, and therefore demands a
homogeneous type, which motivates introducing `Box::pin`.
That in turn is quite annoying to work with and requires `Output =
<same>` for all the futures in the collection, because of how `join_all`
is typed (Rust does not have the ability to do do variadic types, which
is what would be necessary for `join_all` to work the way we might
want). Thus, we get a motivation for `futures::join!`, which unlike
`join_all` *can* work with heterogeneous types.
This fills out a fair bit of the text here and adds a lot of the listing
support, and outlines what remains to do text-wise.
- Incorporate a good discusion of the need to make sure that the `tx`
in this example gets dropped.
- Add more listings which show borrowing vs. moving a `tx`, covering
the full territory in that example.
- Add and test more re-exports in `trpl`.
I made a conscious choice here *not* to use `future::join_all()` because
that ends up getting into a discussion of `Pin`. I left a TODO item here
for now because I think it is probably worth getting into, and that
could be a good thing to transition to *after* this section.