Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Impl poll_readable and poll_writable. #37

Closed
wants to merge 1 commit into from

Conversation

dvc94ch
Copy link
Contributor

@dvc94ch dvc94ch commented Oct 8, 2020

pub struct ListenStream {
    listener: Async<TcpListener>,
}

impl Stream for ListenStream {
    type Item = Result<Async<TcpStream>, std::io::Error>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
        loop {
            match self.listener.accept().now_or_never() {
                Some(Ok((stream, _))) => {
                    return Poll::Ready(Some(Ok(stream)));
                }
                Some(Err(err)) => {
                    return Poll::Ready(Some(Err(err)));
                }
                None => {
                    match self.listener.poll_readable(cx) {
                        Poll::Ready(Ok(())) => continue,
                        Poll::Pending => return Poll::Pending,
                        Poll::Ready(Err(err)) => return Poll::Ready(Some(Err(err))),
                    }
                }
            }
        }
    }
}

Closes #36

```rust
pub struct ListenStream {
    listener: Async<TcpListener>,
}

impl Stream for ListenStream {
    type Item = Result<Async<TcpStream>, std::io::Error>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
        loop {
            match self.listener.accept().now_or_never() {
                Some(Ok((stream, _))) => {
                    return Poll::Ready(Some(Ok(stream)));
                }
                Some(Err(err)) => {
                    return Poll::Ready(Some(Err(err)));
                }
                None => {
                    match self.listener.poll_readable(cx) {
                        Poll::Ready(Ok(())) => continue,
                        Poll::Pending => return Poll::Pending,
                        Poll::Ready(Err(err)) => return Poll::Ready(Some(Err(err))),
                    }
                }
            }
        }
    }
}
```
@ghost
Copy link

ghost commented Oct 8, 2020

Thanks for the PR! I have only glossed over it now but will come back to it later. Just leaving a thought so I don't forget...

I think calls to poll_readable()/poll_writable() should return Poll::Ready if (and only if) the reactor has delivered an event since the last call to the same method. Do you agree?

Secondly, I'm not sure if poll_readable()/poll_writable() should take Pin<&mut Self> or &mut self as an argument. It seems the futures create always uses Pin<&mut Self> for everything, so I wonder if are any potential problems with &mut self. If we're not sure, perhaps Pin<&mut Self> is the safer bet. @taiki-e, do you perhaps have an opinion?

@dvc94ch
Copy link
Contributor Author

dvc94ch commented Oct 8, 2020

I think calls to poll_readable()/poll_writable() should return Poll::Ready if (and only if) the reactor has delivered an event since the last call to the same method. Do you agree?

Not sure if it makes a large difference, but essentially as long as the stream is readable it should return Poll::Ready I guess.

The reason I went with &mut is to avoid having to mess around with pin_mut!.

@ghost
Copy link

ghost commented Oct 8, 2020

The reason I went with &mut is to avoid having to mess around with pin_mut!.

Not sure if that makes it any better, but you can also use Pin::new() for !Unpin types (and most, if not all, will be in this case).

@dvc94ch
Copy link
Contributor Author

dvc94ch commented Oct 8, 2020

readable and writable return !Unpin futures, so by extension any caller needs to use pin_mut!.

@taiki-e
Copy link
Collaborator

taiki-e commented Oct 8, 2020

Secondly, I'm not sure if poll_readable()/poll_writable() should take Pin<&mut Self> or &mut self as an argument. It seems the futures create always uses Pin<&mut Self> for everything, so I wonder if are any potential problems with &mut self. If we're not sure, perhaps Pin<&mut Self> is the safer bet.

Async always implements Unpin, so it shouldn't need self: Pin. (self: Pin is only needed in cases where type is ?Unpin because Self: Unpin is needed to call a &mut self method while pinned.)

Comment on lines +728 to +729
let readable = self.source.readable();
pin!(readable);
Copy link
Collaborator

@taiki-e taiki-e Oct 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not good to create and destruct a new future each time poll is called. The state of the future will be reset each time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand, but I don't see a different solution without changing the api to be poll based instead of async.

Copy link
Collaborator

@taiki-e taiki-e Oct 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I thought we can do that by splitting Source::ready into fn poll_ready that returns Poll and async fn ready that calls poll_fn(|cx| self.poll_ready(cx, dir)), but it seems difficult as ready takes &self.

So, I think the solution (at this time) is probably not to provide poll_{readable, writable} on the async-io side, but to store the future returned by {readable, writable} on the user side.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can help with this tomorrow :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fyi storing the future doesn't work, at least not without unsafe code as the future takes &self, you'd need to construct a self referential struct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

expose register_reader and register_writer so that manual futures can be implemented
2 participants