-
Notifications
You must be signed in to change notification settings - Fork 669
Bring stream combinators over to 0.3 #1022
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
futures-core/src/poll.rs
Outdated
| /// | ||
| /// This macro bakes in propagation of `Pending` signals by returning early. | ||
| #[macro_export] | ||
| macro_rules! try_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.
Heh-- I had added this as ready! in my Sink CL, with try_ready! being the one that included error handling. We definitely want both since we can't use ? anymore-- do you have a naming preference?
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'll switch to ready
| fn as_pin_mut(self) -> Option<PinMut<'a, T>>; | ||
| } | ||
|
|
||
| impl<'a, T> OptionExt<'a, T> for PinMut<'a, 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.
TODO: add to core (both this and assign)
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.
Opened rust-lang/rust#50984
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'll rename to set to match your PR
| } | ||
|
|
||
| unsafe_unpinned!(items -> Vec<S::Item>); | ||
| unsafe_pinned!(stream -> Fuse<S>); |
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 add an unsafe impl<S: Unpin> Unpin for Chunks<S> {} so that the Unpin-edness won't depend on the types of the items?
| } | ||
|
|
||
| unsafe_pinned!(stream -> S); | ||
| unsafe_unpinned!(items -> C); |
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.
unsafe impl<S: Unpin, C> Unpin for Collect<S, C> {}
| // These methods are the only points of access going through `PinMut` | ||
| impl<S: Stream> Concat<S> { | ||
| unsafe_pinned!(stream -> S); | ||
| unsafe_unpinned!(accum -> Option<S::Item>); |
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.
unsafe impl<S: Unpin> Unpin for Concat<S> {}
futures-util/src/stream/fold.rs
Outdated
| return Poll::Ready(accum) | ||
| } | ||
| } else { | ||
| let accum = try_ready!(self.fut().as_pin_mut().unwrap().poll(cx)); |
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 make this unwrap into expect("Fold polled after completion")?
| unsafe_pinned!(stream -> S); | ||
| unsafe_unpinned!(f -> F); | ||
| unsafe_pinned!(fut -> Option<U>); | ||
| } |
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.
unsafe impl<S: Unpin, U: Unpin, F> Unpin for ForEach<S, U, F> {}
| #[must_use = "streams do nothing unless polled"] | ||
| pub struct Fuse<S> { | ||
| stream: S, | ||
| done: bool, |
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.
Not new to this CL, but can you change this to use an Option (or create an issue to follow up and assign me)? That should allow for a more optimized representation, in addition to allowing the stream to drop before the Fuse is ready to be dropped.
| } | ||
|
|
||
| unsafe_pinned!(stream -> S); | ||
| unsafe_unpinned!(inspect -> F); |
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.
unsafe impl<S: Stream + Unpin, F> Unpin for Inspect<S, F> {}
| } | ||
|
|
||
| unsafe_pinned!(stream -> S); | ||
| unsafe_unpinned!(f -> F); |
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.
unsafe impl<S: Unpin, F> Unpin for Map<S, F> {}
|
Can you also update |
| unsafe_pinned!(stream1 -> Fuse<S1>); | ||
| unsafe_pinned!(stream2 -> Fuse<S2>); | ||
| unsafe_unpinned!(queued1 -> Option<S1::Item>); | ||
| unsafe_unpinned!(queued2 -> Option<S2::Item>); |
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.
unsafe impl<S1: Unpin, S2: Unpin> Unpin for Zip<S1, S2> {}
| impl<T, F, Fut> Unfold<T, F, Fut> { | ||
| unsafe_unpinned!(f -> F); | ||
| unsafe_unpinned!(state -> Option<T>); | ||
| unsafe_pinned!(fut -> Option<Fut>); |
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.
unsafe impl<T, F, Fut: Unpin> Unpin for Unfold<T, F, Fut> {}
| /// # } | ||
| /// ``` | ||
| pub fn unfold<T, F, Fut, It>(init: T, f: F) -> Unfold<T, F, Fut> | ||
| where F: FnMut(T) -> Fut, |
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.
Now that borrowed futures are the way of the world, can we change this to use FnMut(&mut T) -> Fut where Fut yields an Option<It>? This matches the itertools::unfold method: https://docs.rs/itertools/0.7.8/itertools/fn.unfold.html
Edit: I'm not sure if that's actually possible to write-- definitely need to sort that out: for<'a> FnMut(&'a mut T) -> Fut::<'a> or something?
Edit2: we might be able to do it with a custom trait:
trait UnfoldFunc<'a, T, Res> {
type Fut: Future<Output = Option<Res>> + 'a;
fn next(&'a mut self, state: &'a mut T) -> Fut;
}and then bound by F: for<'a> UnfoldFunc<'a, T, Res>. I'm not sure how to get <F as UnfoldFunc<'a, T, Res>>::Fut stored in the same place as a <F as UnfoldFunc<'b, T, Res>>::Fut used to be -- seems like we'd need manual erasure of some kind. Maybe it's enough to know that it works for any given lifetime, so we know it must work for a particular lifetime of our choosing that we keep the same across all the invocations.
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 made this nonsense work: cramertj@4bc297b
| impl<S, U, F> Then<S, U, F> { | ||
| unsafe_pinned!(stream -> S); | ||
| unsafe_pinned!(future -> Option<U>); | ||
| unsafe_unpinned!(f -> F); |
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.
unsafe impl<S: Unpin, U: Unpin, F> Unpin for Then<S, U, F> {}
| unsafe_unpinned!(pred -> P); | ||
| unsafe_pinned!(pending_fut -> Option<R>); | ||
| unsafe_unpinned!(pending_item -> Option<S::Item>); | ||
| unsafe_unpinned!(done_taking -> bool); |
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.
unsafe impl<S: Unpin, R: Unpin, P> Unpin for TakeWhile<S, R, P> {}
| unsafe_unpinned!(pred -> P); | ||
| unsafe_pinned!(pending_fut -> Option<R>); | ||
| unsafe_unpinned!(pending_item -> Option<S::Item>); | ||
| unsafe_unpinned!(done_skipping -> bool); |
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.
unsafe impl<S: Unpin, R: Unpin, P> Unpin for SkipWhile<S, R, P> {}
| { | ||
| item: T, | ||
| error: marker::PhantomData<E>, | ||
| } |
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.
unsafe impl<T> Unpin for Repeat<T> {}
| } | ||
|
|
||
| unsafe_pinned!(stream -> Fuse<S>); | ||
| unsafe_unpinned!(peeked -> Option<S::Item>); |
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.
unsafe impl<S: Unpin> Unpin for Peakable<S> {}
|
Out of interest: In the futures RFC thread, your most recent approach is the |
|
@cramertj most review comments addressed. I left @MajorBreakfast we've been pursuing both in parallel, and yes, there are some blockers on the other side. I plan to update the RFC thread soon... |
|
|
As with the future combinators, this PR pushes through all the simple combinators, to explore patterns. I'll do follow-up PRs for the more complicated cases.
Here I've developed a new set of macros for easily adding accessor methods that work on
PinMut<Self>, similar to @withoutboats's derive. For flat structs, this works very well, and safety is trivial to audit.