Well either that, or you would need to use a boxed future to wrap the async/await.
well in that case there will be still heap allocations every time. Isnt async_trait just doing that?
Ah I understand now. With a poll-based trait, you can avoid all but one of them with the ReusableBoxFuture
from earlier.
also on top of that I have no clue how to turn Poll into a Future that can be awaited by the last user and where i would get the context thingy
When you implement the Future
trait on a type, you need to define the following method:
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>
The user can then use it from async/await by just calling .await
on your custom struct. This works because any struct that implements Future
can be awaited — the compiler will take care of calling poll
for you when you await something. As for the context thingy, you get it as an argument to the method you are implementing on the trait.
When it comes to other poll-based traits like AsyncRead
, it is awaited by the user through the *Ext
traits. For example, if you implement the poll-based trait AsyncRead
on MyAwesomeSocket
, all methods from AsyncReadExt
are automatically available for MyAwesomeSocket
. The user can then call AsyncReadExt::read
on your socket, which returns a custom struct that implements Future
. The user can then .await
that future like this:
my_awesome_socket.read(some_args_go_here).await;
The above will then turn into something that calls poll
on the future returned by read
, which will in turn call poll_read
on your socket. You can find the source code for the utility struct returned by AsyncReadExt::read
here: tokio/src/io/util/read.rs
.
I cant thank you enough for the detailed answers you provided. For my workflow I will still go with async_trait for now since I need to get this to prod fairly quickly but and allocation cost at this moment doesnt really bother me much But I think I understand the idea.
- create something Like MyRead that is returned from self.read
- implement the Future for that
- its the executors to provide the context
- it is
self
s problem where to store the future returned from.read
aka MyRead - in poll method of MyRead call .poll of the future returned by underlaying future possibly returned by tokio::io and return the resulting Poll back
I am not missing anything right ?
Normally you would not make your own MyRead
future. You would either use the one from Tokio, or you would be sidestepping poll methods entirely. Otherwise it seems right.
Just checked tokio's AsyncReadExt impl for TcpStream which calls which returns a Read of some sort but seems none of those structs are public so I would have to make my own Read future anyway seems like.
How would I sidestep poll ? isnt it the only way if i am to implement poll based futures instead of Box<Pin<dyn Future>>
The privacy of the struct should not be an issue. Anyone can implement AsyncRead
, and all implementors of AsyncRead
get AsyncReadExt
for free. The automatic impl of AsyncReadExt
is part of Tokio, so it can access the private struct.
You sidestep poll by using async_trait like you have been talking about doing.
Oh i see thanks again for all the info
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.