Description
Some places in the code base use Box::pin(...)
only to create a future that satisfies Pin requirements. One example from components/channeler/src/connect_pool.rs
:
async fn conn_attempt<RA, C, ET>(
friend_public_key: PublicKey,
address: RA,
mut client_connector: C,
mut encrypt_transform: ET,
canceler: oneshot::Receiver<()>,
) -> Option<RawConn>
where
RA: Eq,
C: FutTransform<Input = (RA, PublicKey), Output = Option<RawConn>> + Clone,
ET: FutTransform<Input = (PublicKey, RawConn), Output = Option<RawConn>> + Clone,
{
// TODO: How to remove this Box::pin?
let connect_fut = Box::pin(async move {
let raw_conn = await!(client_connector.transform((address, friend_public_key.clone())))?;
await!(encrypt_transform.transform((friend_public_key.clone(), raw_conn)))
});
// We either finish connecting, or got canceled in the middle:
select! {
connect_fut = connect_fut.fuse() => connect_fut,
_ = canceler.fuse() => None,
}
}
Box::pin(...)
is a runtime tradeoff we make only to satisfy the compiler. Is there a way to write this code without using Box::pin(...)
, and also without using unsafe tricks? It seems to me that we should be able to pin the future to the stack somehow, but I'm not sure if we are supposed to do this.
This is not high priority, but I was curious about this problem for a while. There are other places in the code that have the same problem, you can probably find them by searching for "Box::pin". (Note that there are some legitimate uses of Box::pin around the code too).
@pzmarzly : Do you think you can check this out?