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
async message reader with explicit continuations #42
Conversation
I have finished implementing serialization/deserialization with continuations, and found that it fits in very naturally with the existing logic. The latest commit (50e909e) replaces the existing |
Although I haven't had the time to read through the details of this yet, I'm definitely warming up to the approach you're taking. I'm specifically trying to think through how it will integrate with the port of KJ promises that I've started working on. Building on your ideas here, I think it'll be possible to do stuff like this: enum StepResult<T, S> {
TheresMore(S),
Done(T)
}
/// Intermediate state for a reading a T.
trait AsyncReadState<T> {
/// Reads as much as possible without blocking. If done, returns the final T value. Otherwise
/// returns the new intermediate state T.
fn read_step<R: Read>(self, r: &mut R) -> ::std::io::Result<StepResult<T,Self>>;
}
/// Gives back `r` once the T has been completely read.
fn read_async<R, S, T>(r: R, state: S) -> gj::Promise<(R, T)>
where R: Read + 'static,
S: AsyncReadState<T> + 'static,
T: 'static {
....
} The |
I noticed that mio is implemented in terms of |
@dwrensha the API exposed by the PR is pretty much exactly what you described, just with some slightly different naming. I haven't had time to make any progress on the non-blocking serialized reader/writer, but I think the PR is providing a lot of value as it is right now. I hadn't seen gj before, what will it do different than mio? The mio |
Ah so looking at it more, it looks like gj is providing a higher level abstraction over mio. I guess it would be more appropriate to compare it to eventual and eventual_io then. |
rebased |
I'm still trying to digest this. I'm wary of extra complexity this brings to the code, although it does look like you've done a good job adding tests to keep things maintainable. Have you thought at all about the serialize_packed case? I imagine that doing something like this would add even more complexity there. How much more inconvenient would it be to do do what you're trying to accomplish in a separate crate? |
I haven't done much work on the serialize_packed case, except to see that it's non-trivial. Doing this in a separate crate would be inconvenient, because |
What it we figured out a way to make it convenient for third-party crates to implement |
Sorry for not getting back to you sooner, I've been thinking this over the past few days. My first thought was that effort spent abstracting at this layer would be wasted, since so few people would implement a reader. After considering it some more, though, I think it may be more common than I first thought. For instance, #25 is basically getting towards this. I never really considered making a custom implementation of |
I've been thinking about how we might move forward with the user-defined-message-readers plan. I think what we really want is for users to be able to specify the behavior for the |
I've pushed some changes (b1c54c9, included in the 0.3.0 release) that should enable you to customize the behavior of message readers without needing access to the internals of capnproto-rust.
|
Eek. I of course meant to tag @danburkert above. |
Interesting, is this to support gj and futures-rs? By the way, this work culminated in capnp-nonblock, which does the continuation based serialize/deserialize, and wraps it up to make it a little easier to use with mio. You might want to look there, I think I tweaked some of the serialization/deserialization methods. Of course feel free to grab any of that code (I think the license matches). |
Yeah, I'm trying to imagine a world where capnp-rpc-rust is based on futures-rs instead of gj, and it looks like this pull request could help. |
In #66 I've rebased this and made some changes to make it more closely match the style of futures-rs. |
This is a sketch of a possible solution to #38. The strategy taken here is to return a enum type of
Complete
orContinue
whenever reading or writing a message could block.Complete
signals that the operation completed successfully, whileContinue
signals that the operation must be tried again, and carries along with it any necessary continuation state.The initial commit only includes a
read_message
implementation with continuations. The next step will be to implement aread_message_continue
which takes the continuation andRead
object and continues reading the message. I believewrite_message
can be implemented in much the same way, and perhaps with less impact to the code. Finally, I think packed serialization could be extended in much the same way.The motivation to use continuations instead of a higher level abstraction like
Future
s orPromise
s is that Rust doesn't have a standard implementation of these abstractions, so adapting the read/write machinery to one specific implementation would not benefit the others. My goal is that this continuation API is a stepping stone to implementing async message reading and writing in any higher level async abstraction.I'd love to get feedback on this strategy. I will continue filling it out in the meantime.