Skip to main content

futures_util/stream/stream/
flatten_unordered.rs

1use alloc::sync::Arc;
2use core::{
3    cell::UnsafeCell,
4    convert::identity,
5    fmt,
6    marker::PhantomData,
7    num::NonZeroUsize,
8    pin::Pin,
9    sync::atomic::{AtomicU8, Ordering},
10};
11
12use pin_project_lite::pin_project;
13
14use futures_core::{
15    future::Future,
16    ready,
17    stream::{FusedStream, Stream},
18    task::{Context, Poll, Waker},
19};
20#[cfg(feature = "sink")]
21use futures_sink::Sink;
22use futures_task::{waker, ArcWake};
23
24use crate::stream::FuturesUnordered;
25
26/// Stream for the [`flatten_unordered`](super::StreamExt::flatten_unordered)
27/// method.
28pub type FlattenUnordered<St> = FlattenUnorderedWithFlowController<St, ()>;
29
30/// There is nothing to poll and stream isn't being polled/waking/woken at the moment.
31const NONE: u8 = 0;
32
33/// Inner streams need to be polled.
34const NEED_TO_POLL_INNER_STREAMS: u8 = 1;
35
36/// The base stream needs to be polled.
37const NEED_TO_POLL_STREAM: u8 = 0b10;
38
39/// Both base stream and inner streams need to be polled.
40const NEED_TO_POLL_ALL: u8 = NEED_TO_POLL_INNER_STREAMS | NEED_TO_POLL_STREAM;
41
42/// The current stream is being polled at the moment.
43const POLLING: u8 = 0b100;
44
45/// Stream is being woken at the moment.
46const WAKING: u8 = 0b1000;
47
48/// The stream was waked and will be polled.
49const WOKEN: u8 = 0b10000;
50
51/// Internal polling state of the stream.
52#[derive(Clone, Debug)]
53struct SharedPollState {
54    state: Arc<AtomicU8>,
55}
56
57impl SharedPollState {
58    /// Constructs new `SharedPollState` with the given state.
59    fn new(value: u8) -> Self {
60        Self { state: Arc::new(AtomicU8::new(value)) }
61    }
62
63    /// Attempts to start polling, returning stored state in case of success.
64    /// Returns `None` if either waker is waking at the moment.
65    fn start_polling(&self) -> Option<(u8, PollStateBomb<'_, impl FnOnce(&Self) -> u8>)> {
66        #[allow(deprecated)] // fetch_update was renamed to try_update in rust 1.95.0
67        let value = self
68            .state
69            .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |value| {
70                if value & WAKING == NONE {
71                    Some(POLLING)
72                } else {
73                    None
74                }
75            })
76            .ok()?;
77        let bomb = PollStateBomb::new(self, Self::reset);
78
79        Some((value, bomb))
80    }
81
82    /// Attempts to start the waking process and performs bitwise or with the given value.
83    ///
84    /// If some waker is already in progress or stream is already woken/being polled, waking process won't start, however
85    /// state will be disjuncted with the given value.
86    fn start_waking(
87        &self,
88        to_poll: u8,
89    ) -> Option<(u8, PollStateBomb<'_, impl FnOnce(&Self) -> u8>)> {
90        #[allow(deprecated)] // fetch_update was renamed to try_update in rust 1.95.0
91        let value = self
92            .state
93            .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |value| {
94                let mut next_value = value | to_poll;
95                if value & (WOKEN | POLLING) == NONE {
96                    next_value |= WAKING;
97                }
98
99                if next_value != value {
100                    Some(next_value)
101                } else {
102                    None
103                }
104            })
105            .ok()?;
106
107        // Only start the waking process if we're not in the polling/waking phase and the stream isn't woken already
108        if value & (WOKEN | POLLING | WAKING) == NONE {
109            let bomb = PollStateBomb::new(self, Self::stop_waking);
110
111            Some((value, bomb))
112        } else {
113            None
114        }
115    }
116
117    /// Sets current state to
118    /// - `!POLLING` allowing to use wakers
119    /// - `WOKEN` if the state was changed during `POLLING` phase as waker will be called,
120    ///   or `will_be_woken` flag supplied
121    /// - `!WAKING` as
122    ///   * Wakers called during the `POLLING` phase won't propagate their calls
123    ///   * `POLLING` phase can't start if some of the wakers are active
124    ///     So no wrapped waker can touch the inner waker's cell, it's safe to poll again.
125    fn stop_polling(&self, to_poll: u8, will_be_woken: bool) -> u8 {
126        #[allow(deprecated)] // fetch_update was renamed to try_update in rust 1.95.0
127        self.state
128            .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |mut value| {
129                let mut next_value = to_poll;
130
131                value &= NEED_TO_POLL_ALL;
132                if value != NONE || will_be_woken {
133                    next_value |= WOKEN;
134                }
135                next_value |= value;
136
137                Some(next_value & !POLLING & !WAKING)
138            })
139            .unwrap()
140    }
141
142    /// Toggles state to non-waking, allowing to start polling.
143    fn stop_waking(&self) -> u8 {
144        #[allow(deprecated)] // fetch_update was renamed to try_update in rust 1.95.0
145        let value = self
146            .state
147            .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |value| {
148                let next_value = value & !WAKING | WOKEN;
149
150                if next_value != value {
151                    Some(next_value)
152                } else {
153                    None
154                }
155            })
156            .unwrap_or_else(identity);
157
158        debug_assert!(value & (WOKEN | POLLING | WAKING) == WAKING);
159        value
160    }
161
162    /// Resets current state allowing to poll the stream and wake up wakers.
163    fn reset(&self) -> u8 {
164        self.state.swap(NEED_TO_POLL_ALL, Ordering::SeqCst)
165    }
166}
167
168/// Used to execute some function on the given state when dropped.
169struct PollStateBomb<'a, F: FnOnce(&SharedPollState) -> u8> {
170    state: &'a SharedPollState,
171    drop: Option<F>,
172}
173
174impl<'a, F: FnOnce(&SharedPollState) -> u8> PollStateBomb<'a, F> {
175    /// Constructs new bomb with the given state.
176    fn new(state: &'a SharedPollState, drop: F) -> Self {
177        Self { state, drop: Some(drop) }
178    }
179
180    /// Deactivates bomb, forces it to not call provided function when dropped.
181    fn deactivate(mut self) {
182        self.drop.take();
183    }
184}
185
186impl<F: FnOnce(&SharedPollState) -> u8> Drop for PollStateBomb<'_, F> {
187    fn drop(&mut self) {
188        if let Some(drop) = self.drop.take() {
189            (drop)(self.state);
190        }
191    }
192}
193
194/// Will update state with the provided value on `wake_by_ref` call
195/// and then, if there is a need, call `inner_waker`.
196struct WrappedWaker {
197    inner_waker: UnsafeCell<Option<Waker>>,
198    poll_state: SharedPollState,
199    need_to_poll: u8,
200}
201
202unsafe impl Send for WrappedWaker {}
203unsafe impl Sync for WrappedWaker {}
204
205impl WrappedWaker {
206    /// Replaces given waker's inner_waker for polling stream/futures which will
207    /// update poll state on `wake_by_ref` call. Use only if you need several
208    /// contexts.
209    ///
210    /// ## Safety
211    ///
212    /// This function will modify waker's `inner_waker` via `UnsafeCell`, so
213    /// it should be used only during `POLLING` phase by one thread at the time.
214    unsafe fn replace_waker(self_arc: &mut Arc<Self>, cx: &Context<'_>) {
215        unsafe { *self_arc.inner_waker.get() = cx.waker().clone().into() }
216    }
217
218    /// Attempts to start the waking process for the waker with the given value.
219    /// If succeeded, then the stream isn't yet woken and not being polled at the moment.
220    fn start_waking(&self) -> Option<(u8, PollStateBomb<'_, impl FnOnce(&SharedPollState) -> u8>)> {
221        self.poll_state.start_waking(self.need_to_poll)
222    }
223}
224
225impl ArcWake for WrappedWaker {
226    fn wake_by_ref(self_arc: &Arc<Self>) {
227        if let Some((_, state_bomb)) = self_arc.start_waking() {
228            // Safety: now state is not `POLLING`
229            let waker_opt = unsafe { self_arc.inner_waker.get().as_ref().unwrap() };
230
231            if let Some(inner_waker) = waker_opt.clone() {
232                // Stop waking to allow polling stream
233                drop(state_bomb);
234
235                // Wake up inner waker
236                inner_waker.wake();
237            }
238        }
239    }
240}
241
242pin_project! {
243    /// Future which polls optional inner stream.
244    ///
245    /// If it's `Some`, it will attempt to call `poll_next` on it,
246    /// returning `Some((item, next_item_fut))` in case of `Poll::Ready(Some(...))`
247    /// or `None` in case of `Poll::Ready(None)`.
248    ///
249    /// If `poll_next` will return `Poll::Pending`, it will be forwarded to
250    /// the future and current task will be notified by waker.
251    #[must_use = "futures do nothing unless you `.await` or poll them"]
252    struct PollStreamFut<St> {
253        #[pin]
254        stream: Option<St>,
255    }
256}
257
258impl<St> PollStreamFut<St> {
259    /// Constructs new `PollStreamFut` using given `stream`.
260    fn new(stream: impl Into<Option<St>>) -> Self {
261        Self { stream: stream.into() }
262    }
263}
264
265impl<St: Stream + Unpin> Future for PollStreamFut<St> {
266    type Output = Option<(St::Item, Self)>;
267
268    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
269        let mut stream = self.project().stream;
270
271        let item = if let Some(stream) = stream.as_mut().as_pin_mut() {
272            ready!(stream.poll_next(cx))
273        } else {
274            None
275        };
276        let next_item_fut = Self::new(stream.get_mut().take());
277        let out = item.map(|item| (item, next_item_fut));
278
279        Poll::Ready(out)
280    }
281}
282
283pin_project! {
284    /// Stream for the [`flatten_unordered`](super::StreamExt::flatten_unordered)
285    /// method with ability to specify flow controller.
286    #[project = FlattenUnorderedWithFlowControllerProj]
287    #[must_use = "streams do nothing unless polled"]
288    pub struct FlattenUnorderedWithFlowController<St, Fc> where St: Stream {
289        #[pin]
290        inner_streams: FuturesUnordered<PollStreamFut<St::Item>>,
291        #[pin]
292        stream: St,
293        poll_state: SharedPollState,
294        limit: Option<NonZeroUsize>,
295        is_stream_done: bool,
296        inner_streams_waker: Arc<WrappedWaker>,
297        stream_waker: Arc<WrappedWaker>,
298        flow_controller: PhantomData<Fc>
299    }
300}
301
302impl<St, Fc> fmt::Debug for FlattenUnorderedWithFlowController<St, Fc>
303where
304    St: Stream + fmt::Debug,
305    St::Item: Stream + fmt::Debug,
306{
307    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308        f.debug_struct("FlattenUnorderedWithFlowController")
309            .field("poll_state", &self.poll_state)
310            .field("inner_streams", &self.inner_streams)
311            .field("limit", &self.limit)
312            .field("stream", &self.stream)
313            .field("is_stream_done", &self.is_stream_done)
314            .field("flow_controller", &self.flow_controller)
315            .finish()
316    }
317}
318
319impl<St, Fc> FlattenUnorderedWithFlowController<St, Fc>
320where
321    St: Stream,
322    Fc: FlowController<St::Item, <St::Item as Stream>::Item>,
323    St::Item: Stream + Unpin,
324{
325    pub(crate) fn new(stream: St, limit: Option<usize>) -> Self {
326        let poll_state = SharedPollState::new(NEED_TO_POLL_STREAM);
327
328        Self {
329            inner_streams: FuturesUnordered::new(),
330            stream,
331            is_stream_done: false,
332            limit: limit.and_then(NonZeroUsize::new),
333            inner_streams_waker: Arc::new(WrappedWaker {
334                inner_waker: UnsafeCell::new(None),
335                poll_state: poll_state.clone(),
336                need_to_poll: NEED_TO_POLL_INNER_STREAMS,
337            }),
338            stream_waker: Arc::new(WrappedWaker {
339                inner_waker: UnsafeCell::new(None),
340                poll_state: poll_state.clone(),
341                need_to_poll: NEED_TO_POLL_STREAM,
342            }),
343            poll_state,
344            flow_controller: PhantomData,
345        }
346    }
347
348    delegate_access_inner!(stream, St, ());
349}
350
351/// Returns the next flow step based on the received item.
352pub trait FlowController<I, O> {
353    /// Handles an item producing `FlowStep` describing the next flow step.
354    fn next_step(item: I) -> FlowStep<I, O>;
355}
356
357impl<I, O> FlowController<I, O> for () {
358    fn next_step(item: I) -> FlowStep<I, O> {
359        FlowStep::Continue(item)
360    }
361}
362
363/// Describes the next flow step.
364#[derive(Debug, Clone)]
365pub enum FlowStep<C, R> {
366    /// Just yields an item and continues standard flow.
367    Continue(C),
368    /// Immediately returns an underlying item from the function.
369    Return(R),
370}
371
372impl<St, Fc> FlattenUnorderedWithFlowControllerProj<'_, St, Fc>
373where
374    St: Stream,
375{
376    /// Checks if current `inner_streams` bucket size is greater than optional limit.
377    fn is_exceeded_limit(&self) -> bool {
378        self.limit.map_or(false, |limit| self.inner_streams.len() >= limit.get())
379    }
380}
381
382impl<St, Fc> FusedStream for FlattenUnorderedWithFlowController<St, Fc>
383where
384    St: FusedStream,
385    Fc: FlowController<St::Item, <St::Item as Stream>::Item>,
386    St::Item: Stream + Unpin,
387{
388    fn is_terminated(&self) -> bool {
389        self.stream.is_terminated() && self.inner_streams.is_empty()
390    }
391}
392
393impl<St, Fc> Stream for FlattenUnorderedWithFlowController<St, Fc>
394where
395    St: Stream,
396    Fc: FlowController<St::Item, <St::Item as Stream>::Item>,
397    St::Item: Stream + Unpin,
398{
399    type Item = <St::Item as Stream>::Item;
400
401    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
402        let mut next_item = None;
403        let mut need_to_poll_next = NONE;
404
405        let mut this = self.as_mut().project();
406
407        // Attempt to start polling, in case some waker is holding the lock, wait in loop
408        let (mut poll_state_value, state_bomb) = loop {
409            if let Some(value) = this.poll_state.start_polling() {
410                break value;
411            }
412        };
413
414        // Safety: now state is `POLLING`.
415        unsafe {
416            WrappedWaker::replace_waker(this.stream_waker, cx);
417            WrappedWaker::replace_waker(this.inner_streams_waker, cx)
418        };
419
420        if poll_state_value & NEED_TO_POLL_STREAM != NONE {
421            let mut stream_waker = None;
422
423            // Here we need to poll the base stream.
424            //
425            // To improve performance, we will attempt to place as many items as we can
426            // to the `FuturesUnordered` bucket before polling inner streams
427            loop {
428                if this.is_exceeded_limit() || *this.is_stream_done {
429                    // We either exceeded the limit or the stream is exhausted
430                    if !*this.is_stream_done {
431                        // The stream needs to be polled in the next iteration
432                        need_to_poll_next |= NEED_TO_POLL_STREAM;
433                    }
434
435                    break;
436                } else {
437                    let mut cx = Context::from_waker(
438                        stream_waker.get_or_insert_with(|| waker(this.stream_waker.clone())),
439                    );
440
441                    match this.stream.as_mut().poll_next(&mut cx) {
442                        Poll::Ready(Some(item)) => {
443                            let next_item_fut = match Fc::next_step(item) {
444                                // Propagates an item immediately (the main use-case is for errors)
445                                FlowStep::Return(item) => {
446                                    need_to_poll_next |= NEED_TO_POLL_STREAM
447                                        | (poll_state_value & NEED_TO_POLL_INNER_STREAMS);
448                                    poll_state_value &= !NEED_TO_POLL_INNER_STREAMS;
449
450                                    next_item = Some(item);
451
452                                    break;
453                                }
454                                // Yields an item and continues processing (normal case)
455                                FlowStep::Continue(inner_stream) => {
456                                    PollStreamFut::new(inner_stream)
457                                }
458                            };
459                            // Add new stream to the inner streams bucket
460                            this.inner_streams.as_mut().push(next_item_fut);
461                            // Inner streams must be polled afterward
462                            poll_state_value |= NEED_TO_POLL_INNER_STREAMS;
463                        }
464                        Poll::Ready(None) => {
465                            // Mark the base stream as done
466                            *this.is_stream_done = true;
467                        }
468                        Poll::Pending => {
469                            break;
470                        }
471                    }
472                }
473            }
474        }
475
476        if poll_state_value & NEED_TO_POLL_INNER_STREAMS != NONE {
477            let inner_streams_waker = waker(this.inner_streams_waker.clone());
478            let mut cx = Context::from_waker(&inner_streams_waker);
479
480            match this.inner_streams.as_mut().poll_next(&mut cx) {
481                Poll::Ready(Some(Some((item, next_item_fut)))) => {
482                    // Push next inner stream item future to the list of inner streams futures
483                    this.inner_streams.as_mut().push(next_item_fut);
484                    // Take the received item
485                    next_item = Some(item);
486                    // On the next iteration, inner streams must be polled again
487                    need_to_poll_next |= NEED_TO_POLL_INNER_STREAMS;
488                }
489                Poll::Ready(Some(None)) => {
490                    // On the next iteration, inner streams must be polled again
491                    need_to_poll_next |= NEED_TO_POLL_INNER_STREAMS;
492                }
493                _ => {}
494            }
495        }
496
497        // We didn't have any `poll_next` panic, so it's time to deactivate the bomb
498        state_bomb.deactivate();
499
500        // Call the waker at the end of polling if
501        let mut force_wake =
502            // we need to poll the stream and didn't reach the limit yet
503            need_to_poll_next & NEED_TO_POLL_STREAM != NONE && !this.is_exceeded_limit()
504            // or we need to poll the inner streams again
505            || need_to_poll_next & NEED_TO_POLL_INNER_STREAMS != NONE;
506
507        // Stop polling and swap the latest state
508        poll_state_value = this.poll_state.stop_polling(need_to_poll_next, force_wake);
509        // If state was changed during `POLLING` phase, we also need to manually call a waker
510        force_wake |= poll_state_value & NEED_TO_POLL_ALL != NONE;
511
512        let is_done = *this.is_stream_done && this.inner_streams.is_empty();
513
514        if next_item.is_some() || is_done {
515            Poll::Ready(next_item)
516        } else {
517            if force_wake {
518                cx.waker().wake_by_ref();
519            }
520
521            Poll::Pending
522        }
523    }
524}
525
526// Forwarding impl of Sink from the underlying stream
527#[cfg(feature = "sink")]
528impl<St, Item, Fc> Sink<Item> for FlattenUnorderedWithFlowController<St, Fc>
529where
530    St: Stream + Sink<Item>,
531{
532    type Error = St::Error;
533
534    delegate_sink!(stream, Item);
535}