-
Notifications
You must be signed in to change notification settings - Fork 653
Refactor Sink trait #765
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
Refactor Sink trait #765
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, thanks! I think some tests are failing though?
I'm a little fuzzy on what the protocol is in terms of how to use a sink, but we can always flesh that out later.
futures-sink/src/channel_impls.rs
Outdated
/// It will contain a value of type `T` if one was passed to `start_send` | ||
/// after the channel was closed. | ||
#[derive(Debug)] | ||
pub struct ChannelClosed<T>(Option<T>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How come this was needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, it was always the case that an error contained a T
. That's not the case anymore, since poll_ready
doesn't have a T
to respond with (previously, the only function that could error was start_send
, which has a T
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm could we mirror the Option
in the original futures-channel crate as well though? (to avoid the introduction of another type)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure-- i debated about this, since it's sort of misleading to the end user, because some functions will only ever return Some
or None
. In the Sink
trait that's not preventable, but it is if you're directly using functions on Channel
. I think I agree that the extra complexity isn't worth it, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh I'd probably be fine either way, I understand now what's going on at least :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the key question to me is whether we can expect start_send
to always be able to give you the value back on an error, in which case the Sink
trait should probably continue to use a wrapper around the error type.
cc @carllerche
@alexcrichton I've pushed another commit fixing up futures-util. |
2fba527
to
7117b21
Compare
} | ||
|
||
fn close(&mut self, _: &mut task::Context) -> Poll<(), SendError<T>> { | ||
fn start_close(&mut self) -> Result<(), Self::SinkError> { | ||
Ok(()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has confused me in the past. I would expect to be able to try to close a channel from the sender side, even if I have multiple senders. Should this instead try to close the channel, instead of being a noop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you open an issue for this? I'd prefer to keep this PR scoped to just refactoring changes, not behavioral ones.
type SinkError = ChannelClosed<T>; | ||
|
||
fn poll_ready(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { | ||
Ok(Async::Ready(())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this also check the inherent poll_ready
? An unbounded channel can still be closed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's closed, it will throw an error in start_send
. However, I think I agree with you that it would be good to allow the client to stop producing values in these cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(note that to accomplish this, i'll be changing the inherent poll_ready
from &mut self
to &self
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, it seems I can't actually do that, because poll_ready
calls poll_unparked
internally, which mutates self.maybe_parked
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a user, I find it surprising that passing tx
would let poll_ready
tell me it was closed, but &tx
wouldn't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't disagree. Can you open an issue for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So just to confirm, we're gonna tackle this in a follow-up PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think that's a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, left a couple of questions but nothing big.
futures-sink/src/channel_impls.rs
Outdated
/// It will contain a value of type `T` if one was passed to `start_send` | ||
/// after the channel was closed. | ||
#[derive(Debug)] | ||
pub struct ChannelClosed<T>(Option<T>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the key question to me is whether we can expect start_send
to always be able to give you the value back on an error, in which case the Sink
trait should probably continue to use a wrapper around the error type.
cc @carllerche
type SinkError = ChannelClosed<T>; | ||
|
||
fn poll_ready(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { | ||
Ok(Async::Ready(())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So just to confirm, we're gonna tackle this in a follow-up PR?
|
||
/// The result of an asynchronous attempt to send a value to a sink. | ||
#[derive(Copy, Clone, Debug, PartialEq)] | ||
pub enum AsyncSink<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahhhhhh so nice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
\o/
@carllerche said in #751:
|
@cramertj ok, that's good enough for me :-) |
Merged! |
yes, it should definitely not be assumed that, once a value is sent, it can always be returned on error. Now, some enum SendError<T> {
Closed(Option<T>), // Must be option to handle returning this on `poll_ready`.
// other variants
}
impl<T> Sink for Sender<T> {
type Item = T;
type Error = SendError<T>;
} This is probably roughly what @cramertj did (but I didn't look in detail). The implementation can document that |
Fix #751