Expand description
This tiny crate contains helpers to turn a borrowed future into an owned one.
§Motivation
Take tokio::sync::Notify as an example. It’s often useful to call Notify::notified from
the main thread and then pass it to a spawned thread. Doing this guarantees the resulting
Notified is watching for calls to Notify::notify_waiters prior to the thread being
spawned. However this isn’t possible with as notified borrows the Notify.
use std::sync::Arc;
use tokio::sync::Notify;
let notify = Arc::new(Notify::new());
// Spawn a thread that waits to be notified
{
let notify = notify.clone();
// Start listening before we spawn
let notified = notify.notified();
tokio::spawn(async move {
// wait for our listen to complete
notified.await; // <-- fails because we can't move `notified`
});
}
// notify the waiting threads
notify.notify_waiters();At present, there’s no way to do this kind of borrow and then move, and while there are many
crates available to help turn this problem into a self-borrowing one, those solutions require
unsafe code with complicated covariance implications. This crate is instead able to solve this
simple case with no unsafe, and only 1-2 lines of unsafe code for more complex cases with no
covariance problems. Here is the solution to the above problem:
use std::sync::Arc;
use tokio::sync::Notify;
use owned_future::make;
let notify = Arc::new(Notify::new());
// Spawn a thread that waits to be notified
{
// Start listening before we spawn
let get_notified = owned_future::get!(fn(n: &mut Arc<Notify>) -> () {
n.notified()
});
let notified = make(notify.clone(), get_notified);
tokio::spawn(async move {
// wait for our listen to complete
notified.await;
});
}
// notify the waiting threads
notify.notify_waiters();§Technical Details
So how does this work exactly? Well, while rust usually doesn’t let you move a borrowed value,
there’s one exception. Pinned futures. Once async code has been transformed into a Pined
future, it can invoke the borrow operation, but still be freely moved around. Essentially what
this crate does is a prettied up version of this:
let mut wrapped_notified = Box::pin(async move {
let notified = notify.notified();
// This prevents us from driving the future to completion on the first poll
force_pause().await;
future.await
});
// Drive the future up to just past our `force_pause`
wrapped_notified.poll_once()
tokio::spawn(async move {
// wait for our listen to complete
wrapped_notified.await;
});The more complex wrappers have a little bit more machinery to handle auxiliary values and
errors, and the Async* helpers need a little bit of pin-projection and poll handling, but
ultimately the core logic boils down to something like the above.
Macros§
- async_
send_ try_ get - A macro for quickly implementing
crate::AsyncSendTryGetFutwithout capturing. - async_
try_ get - A macro for quickly implementing
crate::AsyncTryGetFutwithout capturing. - get
- A macro for quickly implementing
crate::GetFutwithout capturing. - try_get
- A macro for quickly implementing
crate::TryGetFutwithout capturing.
Structs§
- Async
Send Try - Try to encapsulate an async borrowed future along with it’s owner
- Async
Try - Try to encapsulate an async borrowed future along with it’s owner
Traits§
- Apply
GetFut - An extension trait to call
crate::get - Async
Send TryApply GetFut - An extension trait to call
crate::AsyncSendTry - Async
Send TryGet Fut - A functor trait for trying to get a complex future from an input.
- Async
TryApply GetFut - An extension trait to call
crate::AsyncTry - Async
TryGet Fut - A functor trait for trying to get a complex future from an input.
- GetFut
- A functor trait for getting a simple future from an input.
- TryApply
GetFut - An extension trait to call
crate::try_get - TryGet
Fut - A functor trait for trying to get a complex future from an input.
Functions§
- make
- Encapsulate a borrowed future along with it’s owner
- try_
make - Try to encapsulate a borrowed future along with it’s owner
Type Aliases§
- Async
Send TryOutput - An alias for the output type of
AsyncTry - Async
TryOutput - An alias for the output type of
AsyncTry