I would like to create a method sending some data on a struct which implements Tokio's Sink, but I'm having problems working with Pin as self. In essence, I need something like this:
fn send_data(&mut self, data: Item, cx: &mut Context) -> Poll<Result<(), Error>> {
futures_core::ready!(something.poll_ready(cx))?;
something.start_send(data)?;
futures_core::ready!(something.poll_close(cx))
}
The problem is that each call to poll_ready(), start_send() and poll_close() takes self: Pin<&mut Self> and I don't know what something in my use case should be. If I try to use let something = Pin::new(self); then something gets moved after the call to poll_ready() and I cannot use it for subsequent calls (self is also gone at this point). How do I work around this problem?
use futures_core;
use std::pin::Pin;
use tokio::prelude::*; // 0.3.0-alpha.1
struct Test {}
impl Sink<i32> for Test {
type Error = ();
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn start_send(self: Pin<&mut Self>, item: i32) -> Result<(), Self::Error> {
Ok(())
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
}
impl Test {
fn send_data(&mut self, data: i32, cx: &mut Context) -> Poll<Result<(), Error>> {
// what should "something" here be?
futures_core::ready!(something.poll_ready(cx))?;
something.start_send(data)?;
futures_core::ready!(something.poll_close(cx))
}
}
I am very new to Rust myself (just started this week), but I solved a very similar problem earlier today by doing the following:
Create a pinned version of something: let mut something_pinned = Box::pin(something);
Call .as_mut() before each call to poll_ready, start_send, and poll_close.
So in your send_data, it should look something like:
futures_core::ready!(something_pinned.as_mut().poll_ready(cx))?;
something_pinned.as_mut().start_send(data)?;
futures_core::ready!(something_pinned.as_mut().poll_close(cx))
Also, I think you're generally supposed to store "memory" of which of your sub-poll steps have already been completed, eg. so that when your function gets re-called, it doesn't call start_send additional times after having already seen it succeed/become-ready. (though maybe it doesn't cause any actual problems to call it redundantly in this case)
Related
I want to sleep 1 second in poll(), but it gets stuck in Pending.
From what I understand, I pass it &mut cx and it should wake up the current task after 1 second.
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::{Duration};
struct MyDelay {}
impl Future for MyDelay {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
println!("poll");
let sleep = tokio::time::sleep(Duration::from_secs(1));
tokio::pin!(sleep);
sleep.poll(cx)
}
}
#[tokio::main]
async fn main() {
let delay = MyDelay{};
let a = delay.await;
dbg!(a);
}
Play url: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ed6c09df100f1140ddc85b2ae600ab93
Each time you poll you create a new Sleep future, and it starts from scratch.
Instead, you should store the Sleep inside your future. It is easy with pin-project-lite:
pin_project_lite::pin_project! {
struct MyDelay {
#[pin]
sleep: tokio::time::Sleep,
}
}
impl MyDelay {
fn new() -> Self {
Self {
sleep: tokio::time::sleep(Duration::from_secs(1)),
}
}
}
impl Future for MyDelay {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
println!("poll");
let this = self.project();
this.sleep.poll(cx)
}
}
Playground.
Note that the number of times this will be polled is not guaranteed, and may not be constant.
I'm looking to implement a wrapper struct for any stream that returns a certain type, to cut down on the dynamic keywords littering my application. I've come across BoxStream, but have no idea how to make use of it in Stream::poll_next. Here's what I have so far:
use std::pin::Pin;
use std::task::{Context, Poll};
use futures::prelude::stream::BoxStream;
use futures::Stream;
pub struct Row;
pub struct RowCollection<'a> {
stream: BoxStream<'a, Row>,
}
impl RowCollection<'_> {
pub fn new<'a>(stream: BoxStream<Row>) -> RowCollection {
RowCollection { stream }
}
}
impl Stream for RowCollection<'_> {
type Item = Row;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
// I have no idea what to put here, but it needs to get the information from self.stream and return appropriate value
}
}
Dependencies:
futures = "0.3"
Since Box implements Unpin, then BoxStream implements Unpin, and so will RowCollection.
Because of this, you can make use of Pin::get_mut which will give you a &mut RowCollection. From that, you can get a &mut BoxStream. You can re-pin that via Pin::new and then call poll_next on it. This is called pin-projection.
impl Stream for RowCollection<'_> {
type Item = Row;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Pin::new(&mut self.get_mut().stream).poll_next(cx)
}
}
See also:
No method named `poll` found for a type that implements `Future`
I wanted to implement the futures::Sink trait in my struct and kept getting yelled at by the compiler telling me to import and implement the trait. So I came up with this example which surprisingly (to me at least) still doesn't work:
use futures::Sink;
use std::pin::Pin;
use std::task::{Context, Poll};
struct Dummy;
impl Sink<tungstenite::Message> for Dummy {
type Error = tungstenite::Error;
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
fn start_send(self: Pin<&mut Self>, item: tungstenite::Message) -> Result<(), Self::Error> {
todo!()
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
}
#[tokio::main]
async fn main() {
let mut dummy = Dummy;
dummy.start_send(tungstenite::Message::Text("".to_owned()));
}
I get:
error[E0599]: no method named `start_send` found for struct `Dummy` in the current scope
--> src/main.rs:29:11
|
5 | struct Dummy;
| ------------- method `start_send` not found for this
...
29 | dummy.start_send(tungstenite::Message::Text("".to_owned()));
| ^^^^^^^^^^ method not found in `Dummy`
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `start_send`, perhaps you need to implement it:
candidate #1: `futures::Sink`
error: aborting due to previous error
I'm not making a generic struct, there are no bounds issues, no lifetimes. It's just a direct trait impl which the compiler refuses to recognize.
cargo tree | grep futures says all versions are v0.3.13, and here's the docs
I even tried Pin::new(&mut dummy).start_send because of the signature, but still nothing<. I have no idea what's going on here, or what kind of silly mistake did I make...
(By the way, I had a go at the similar impl Stream before this one and had no issues whatsoever)
I even tried Pin::new(&mut dummy).start_send because of the signature, but still nothing<. I have no idea what's going on here, or what kind of silly mistake did I make...
I also tried wrapping it in a Pin, since the start_send() takes in a Pin<&mut Self> as self, and this does seem to work for me.
use futures::sink::Sink;
use std::pin::Pin;
use std::task::{Context, Poll};
struct Message {}
struct Dummy;
impl Sink<Message> for Dummy {
type Error = ();
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
fn start_send(self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
todo!()
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
todo!()
}
}
#[tokio::main]
async fn main() {
let mut dummy = Dummy;
let pin_dummy = Pin::new(&mut dummy);
pin_dummy.start_send(Message {});
}
Rust Playground
This question already has answers here:
How to implement a Future or Stream that polls an async fn?
(2 answers)
Closed 5 months ago.
How to implement Futures::poll the the following code that will call async method with full ownership to the self?
use anyhow::Error;
use futures::Future;
use futures::channel::oneshot;
use futures::task::{Context, Poll};
use std::pin::Pin;
struct MyLongTask {
rx: oneshot::Receiver<()>,
}
impl MyLongTask {
// The method and full ownership to `self` is important to keep!
async fn recv(mut self) -> Result<(), Error> {
self.rx.await.map_err(|_| Error::msg("can't recv"))
}
}
// TryFuture not necessary here
impl Future for MyLongTask {
type Output = Result<(), Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
todo!("how to `self.recv().await` here?")
}
}
fn main() { }
Playground if needed.
You can't call self.recv() inside poll firstly because it does not own self, and secondly because it is not async.
Future::poll is synchronous but must return quickly regardless of whether a return value is ready (that's the whole idea of Poll::Pending).
In your case you should simply delegate the poll to self.rx: (playground)
impl Future for MyLongTask {
type Output = Result<(), Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.rx).poll(cx) {
Poll::Ready(x) => Poll::Ready(x.map_err(|_| Error::msg("can't recv"))),
Poll::Pending => Poll::Pending,
}
}
}
Now instead of using task.recv().await, you can just do task.await.
I'd also suggest you either implement Future or provide the recv method.
Otherwise you could run into trouble later when you change one implementation and forget to change the other.
I have a struct MyAsyncStream and tokio::io::AsyncWrite implementation for it:
impl<S: AsyncRead + AsyncWrite + Unpin> AsyncWrite for MyAsyncStream<S> {
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<Result<usize>> {
....
}
I also have MyAsyncStreamWrapper:
struct MyAsyncStreamWrapper{inner: MyAsyncStream}
Now I want to implement AnotherTrait trait for MyAsyncStreamWrapper, with the following method:
impl AnotherTrait for MyAsyncStreamWrapper {
fn poll_send_to<B>(self: Pin<&Self>, cx: &mut Context<'_>, buf: &[u8], addr: B,) -> Poll<Result<usize, Self::Error>> {
Pin::new(&mut self.inner).poll_write(cx, buf)
}
....
}
In this method implementation, I want to call poll_write on the inner. But, unfortunately they are different on self mutability: Pin<&mut Self> vs Pin<&Self>. As expected it does not compile.
Is there an idiomatic "workaround" for such case? My idea is to wrap inner into Mutex so I could have mutable MyAsyncStream in the non-mutable context:
MyAsyncStreamWrapper{inner: Mutex<RefCell<MyAsyncStream>>}
...
fn poll_send_to<B>(mut self: Pin<&Self>, cx: &mut Context<'_>, buf: &[u8], addr: B,) -> Poll<Result<usize, Self::Error>> {
let rc = self.stream.lock().unwrap();
let ref mut inner = rc.borrow();
let pin = Pin::new(inner);
pin.poll_write(cx, buf);
}
...
But, unfortunately, it also does not compile, with the following error:
pin.poll_write(cx, buf);
^^^^^^^^^^ method not found in `std::pin::Pin<&mut std::cell::RefMut<'_, MyAsyncStream>>`
What is the right way to go?
Dereference then re-borrow seems to work:
use std::cell::RefCell;
use std::pin::Pin;
use std::sync::Mutex;
fn main() {
let a = Mutex::new(RefCell::new(42));
let rc = a.lock().unwrap();
let mut inner = rc.borrow_mut();
let pinned = Pin::new(&mut *inner);
print_type_name(pinned);
}
fn print_type_name<T>(_: T) {
println!("{}", std::any::type_name::<T>());
}
It outputs that the type is core::pin::Pin<&mut i32>.
That being said, using blocking synchronization primitives like Mutex in asynchronous context is probably not a good idea. If possible it is better to let poll_send_to take a Pin<&mut Self> parameter.