I have an async trait method which returns a std Future:
Pin<Box<dyn Future<Output = Result<Vec<ResultType>, Box<(dyn Error + 'static)>>> + Send>>
ResultType
is an associated type of the trait which is Sync + Send
.
Note that this type is not Unpin.
I want to call this from an actix handler, then do something with the result.
For example:
impl StreamHandler<ws::Message, ws::ProtocolError> for MyActor {
fn handle(&mut self, msg: ws::Message) {
let fut = get_future();
let actor_fut = fut
.into_actor(&self)
.map(|r, _actor, ctx| {
ctx.text(r.map(|| ...))
});
ctx.spawn(actor_fut);
}
}
This fails because into_actor
takes ownership of the future, which is not allowed by Pin
. The cleaned error message looks like:
error[E0599]: no method named `into_actor` found for type `Pin<Box<dyn Future<Output = Result<Vec<ResultType>, Box<dyn Error>>> + Send>>` in the current scope
--> src/app_socket.rs:194:26
|
194 | .into_actor(&self)
| ^^^^^^^^^^ method not found in `Pin<Box<dyn Future<Output = Result<Vec<ResultType>, Box<dyn Error>>> + Send>>`
|
= note: the method `into_actor` exists but the following trait bounds were not satisfied:
`&dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapFuture<_>`
`&dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapStream<_>`
`&mut dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapFuture<_>`
`&mut dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapStream<_>`
`&mut Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapFuture<_>`
`&mut Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapStream<_>`
`&Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapFuture<_>`
`&Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapStream<_>`
`dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapFuture<_>`
`dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send : WrapStream<_>`
`Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapFuture<_>`
`Pin<std::boxed::Box<dyn Future<Output = Result<std::vec::Vec<ResultType>, std::boxed::Box<dyn std::error::Error>>> + Send>> : WrapStream<_>`
How can I do this?
The actual problem was not that the future was pinned, but that it implemented the wrong future trait.
This section on Pinning explains that poll
is implemented for Pin<ref T: Future>
.
Hence, the into_actor
signature self: impl Future -> WrapFuture<_>
was fine. The problem was that the async
method returned a future implementing std::future::Future
while into_actor
expected futures01::future::Future
.
Calling .compat()
on the future before calling .into_actor
fixes the problem.
See this post for more detail about converting futures.