Essential combinators

We saw a few of the most important combinators in thefutures andstreams overviews. Here we’ll take alook at a few more. It’s also worth spending some time with the traitdocumentation to familiarize yourself with the full range of combinatorsavailable (cheatsheet).

Some concrete futures and streams

Any value can be turned into an immediately complete future. There are a fewfunctions in the future module for creating such a future:

  • ok, which is analogous to Result::Ok: it treats the value you give it as an immediately successful future.
  • err, which is analogous to Result::Err: it treats the value you give it as an immediately failed future.
  • result, which lifts a result to an immediately-complete future.
    For streams, there are a few equivalents of an “immediately ready” stream:

  • iter, which creates a stream that yields the same items as the underlyingiterator. The iterator produces Result values, and the first error terminatesthe stream with that error.

  • once, which creates a single-element stream from a Result.
    In addition to these constructors, there’s also a function, lazy, whichallows you to construct a future given a closure that will produce that futurelater, on demand.

IntoFuture

A crucial API to know about is the IntoFuture trait, which is a trait forvalues that can be converted into futures. Most APIs that you think of as takingfutures actually work with this trait instead. The key reason: the trait isimplemented for Result, allowing you to return Result values in many placesthat futures are expected.

Adapters

Like Iterator, the Future, Stream and Sink traits all come equippedwith a broad range of “adapter” methods. These methods all consume the receivingobject and return a new, wrapped one. For futures, you can use adapters to:

Finally, an object that is both a stream and a sink can be broken into separatestream and sink objects using the split adapter.

All adapters are zero-cost, meaning that no memory is allocated internally andthe implementation will optimize to what you would have otherwise written byhand.

Error handling

Futures, streams and sinks all treat error handling as a core concern: they areall equipped with an associated error type, and the various adapter methodsinterpret errors in sensible ways. For example:

  • The sequencing combinators then, and_then, or_else, map, andmap_err all chain errors similarly to the Result type in the standardlibrary. So, for example, if you chain futures using and_then and thefirst future fails with an error, the chained future is never run.

  • Combinators like select and join also deal with errors. Forselect, the first future to complete in any way yields an answer,propagating the error, but also giving access to the other future should youwant to keep working with it. For join, if any future produces an error,the entire join produces that error.

By default, futures don’t have any special handling for panics. In most cases,though, futures are ultimately run as tasks within a thread pool, where you’llwant to catch any panic they produce and propagate that elsewhere. Thecatch_unwind adapter can be used to reify a panic into a Result withouttaking down the worker thread.

Next up: Returning futures