0.3.0-alpha.3
requires a recent nightly (2018-08-13 or newer):
$ rustup update
Compatibility layer
A compatibility layer between 0.3 and 0.1 was developed. It is now possible to convert an 0.3 future into an 0.1 future and vice versa. Similar conversions for streams and sinks are also supported. Additionally, it is now possible to run 0.3 futures and async functions on Tokio’s executor. We have a dedicated blog post coming up that explains this in more detail.
Spawning
Spawn
trait
The std::task::Executor
trait is now called std::task::Spawn
. We chose to rename the trait to Spawn
because the functionality exposed by this trait is not the ability to execute, but the ability to spawn.
As a consequence of this renaming, some functions on Context
were adjusted:
impl<'a> Context<'a> {
pub fn new(local_waker: &'a LocalWaker, spawner: &'a mut dyn Spawn) -> Context<'a> { ... }
pub fn spawner(&mut self) -> &mut dyn Spawn { ... }
pub fn with_spawner<'b, Sp: Spawn>(&'b mut self, spawner: &'b mut Sp) -> Context<'b> { ... }
// ...
}
Spawn macros
This release of futures-rs introduces the spawn!
and spawn_with_handle!
macros for use in async functions, closures and blocks. Both macros let you spawn a task that polls the given future to completion. The task is spawned via the current context’s spawner.
spawn!
lets you spawn futures with Output = ()
:
#![feature(async_await, await_macro, futures_api)]
use futures::spawn;
spawn!(future).unwrap();
spawn_with_handle!
lets you spawn futures with any Output: Send
type and returns a future that resolves to the output of the spawned future:
use futures::spawn_with_handle;
let join_handle = spawn_with_handle!(future).unwrap();
let output = await!(join_handle);
spawn!
is slightly cheaper than spawn_with_handle!
since it doesn’t need to provide a way to get the output.
Should spawning fail, a SpawnError
error is returned which contains information about why it failed.
So what futures can be spawned? There are some requirements: The future needs to be Send
and 'static
and the output needs to be Send
. Here’s why:
- The
'static
lifetime means that the future cannot contain any non-static references. This is required so that the spawned task can be run independently to the task that spawns it. - The
Send
bounds mean that the future and its output can be sent to other threads. This is required so that multithreaded executors can run the spawned task on any thread they choose.
Note: You can still execute non-Send
, non-'static
futures concurrently via the join!
macro.
Spawn methods
For use outside of async functions, there’s also something new: The SpawnExt
trait. It provides the methods spawn
and spawn_with_handle
:
use futures::task::SpawnExt;
// spawn()
spawner.spawn(future).unwrap();
// spawn_with_handle()
let join_handle = spawner.spawn_with_handle(future).unwrap();
Inside poll
, you can use these methods by accessing the context’s spawner via Context::spawner
:
fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<T> {
cx.spawner().spawn(future).unwrap();
}
The plan: spawn
with dyn Future
We plan to eventually replace SpawnExt::spawn
with Spawn::spawn
. This method will live directly in the Spawn
trait defined in libcore. It’s signature will look like this:
fn spawn(
&mut self,
future: dyn Future<Output = ()> + Send + 'static,
) -> Result<(), SpawnError>
This method can’t be implemented just yet due to compiler limitations:
- Arbitrary self types are currently not object-safe:
Future::poll
usesPinMut
as arbitrary self type. This unfortunately makes it impossible to create trait objects forFuture
. Therefore,Box<dyn Future>
and&dyn Future
are currently not supported. - Unsized rvalues are not yet available: Trait objects (
dyn Trait
) are!Sized
because the size of a trait object depends on the size of the concrete type behind it and can therefore only be known at runtime. Currently we often useBox<dyn Trait>
which stores the trait object on the heap to circumvent that. The unsized rvalues feature will make it possible to store!Sized
types on the stack.
To circumvent these limitations, we currently have FutureObj
and Spawn::spawn_obj
. These are, however, just a temporary solution until we can introduce the planned spawn
method. The planned spawn
method will make it possible to have one fewer heap allocation because the future is kept on the stack for as long as possible.
pin-utils
crate
The pin macros now live in their own crate, the pin-utils
crate. The macros are general purpose and can be used in any project that uses the pinning API.
The crate includes the macros for (un)pin projections unsafe_pinned!
and unsafe_unpinned!
and the macro for stack pinning pin_mut!
:
let foo = Foo { ... };
pin_mut!(foo); // PinMut<Foo>
Version 0.1.0-alpha.1
is now available on crates.io and the API docs are available on docs.rs.
Further changes
A complete list of changes can be found in our changelog.
A big thanks goes to every one who contributed to this release! This includes @tinaun, @Nemo157, @cramertj and @MajorBreakfast and our new contributors @gbonik and @dbcfd!