-
Notifications
You must be signed in to change notification settings - Fork 653
Add futures::stream::unfold #209
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
Conversation
Thanks for the PR! I wonder if we could perhaps think of a different name for this? It seems similar to |
My apologies for the delay, I just realized that I actually forgot to send my reply to you ... I agree the name isn't great because it is close to other functions with different semantics. In essence, this functions creates a Apart from the name, do you think the functionality offered is useful (and has a place in the futures crate)? |
Oh no worries! This feels similar to an infinite stream with a I'm also totally fine adding this to this crate, seems like quite appropriate functionality to me! |
The idea was to be able to pass ownership of a (potentially unclonable) object (such as a socket). The user provides the initial I took this approach because it fits well with some tokio functions, like I think a major disadvantage is that it may result in another "level" of tuple, already commonly found in tokio. For example, if the user wants the stream to yield As you pointed out, another design could be not to pass that state around (and have |
Hm the state here is a little different than That may require an |
But if the state was closed over by the I figured I would end up having something like (pseudocode): struct Repeat {
f: F,
future: Future, // Future contains a reference to a part of f environment
} Which would be rejected by Rust (can't have self-referencing structures). This is why I made the future explicitely return back the ownership of T. |
Aha! I see what you mean now, that is indeed quite subtle. I wonder if perhaps this is almost more worth it as a combinator rather than a base construction of a stream. That is, an |
Yes, I guess that should work! I could then have the functionality I originally wanted with something like I'll try to work on the implementation tonight (and try to find a good name, although I am very bad at naming). As a side note, wouldn't your previous comment about the state possibly being captured in the closure's environment apply to the |
Ok! We can figure out naming afterwards, that's fine.
Indeed! I was never a fan of |
OK the implementation is mostly done and revealed an interesting edge-case that I overlooked before. In case of error returned by the user-returned future, we would lose the internal state with no way to get it back (the future should have returned it in the I also added a few tests. The Travis failure looks unrelated to this PR. |
@aturon you wouldn't happen to recognize this combinator would you? I can't quite put my finger on it but it seems like something we've seen before... |
@alexcrichton This combinator is sometimes known as "unfold", where you take a seed and a transformation, and produce from it a stream of values. |
Oh that sounds pretty nifty! @Vaelden want to add this as |
@aturon I would just like to double-check, because since I started this PR I changed the implementation but not the accompanying docs (which I will do ASAP): is "unfold" an adapter, taking a stream of values, a seed and a transformation and creating a new stream; or does it produce a stream from nothing (well ... seed + transformation)? |
@Vaelden It produces a stream from nothing, just as you have it here. Here's a similar function in Haskell. You can think of it as the "reverse" of |
Ah ok so given that, @Vaelden I wonder if it might be best to go back to what you had originally, not as a combinator on the |
@aturon Thanks a lot for the link! It helped me a lot for the documentation. @alexcrichton That's fine no worries! I changed the name, rewrote the doc and rebased on top of master so everything should be fine now (except the name of my base branch that I cannot change from repeat_adapter without creating another PR). |
Oh and I also changed the order of the item in the tuple to match Haskell's implementation: the Future must return |
Thanks @Vaelden! |
This adds an adapter, a bit similar to
Stream::fold
, which allows to go from the "world of futures" to the "world of streams".I felt such adapter was missing (or maybe I just missed it) when trying to use tokio-core, because most helper functions (like
io::write_all
orio::read_exact
) return Futures and didn't work well with streaming protocols (using recursion with.and_then()
finished by overflowing the stack).This adapter allows to write code like:
I am not too happy with the naming (repeat could mean something else) and with the example in the documentation, so I will be happy to change that.
We could also try to have a way to get back ownership of the internal state (right now it is possible by integrating it the Error type for example, but it looks ugly)