Skip to main content

asupersync/stream/
mod.rs

1//! Async stream processing primitives.
2//!
3//! This module provides the [`Stream`] trait and related combinators for
4//! processing asynchronous sequences of values.
5//!
6//! # Core Traits
7//!
8//! - [`Stream`]: The async equivalent of [`Iterator`], producing values over time
9//! - [`StreamExt`]: Extension trait providing combinator methods
10//!
11//! Neither trait adds a global `Send`, `Sync`, `Unpin`, or `'static` bound.
12//! Individual operations state the bounds they need. In particular,
13//! [`StreamExt::next`] requires `Unpin`; address-sensitive streams can instead
14//! be held behind a pinned pointer and polled through [`Stream::poll_next`].
15//! Cancellation and drop behavior is adapter-specific: dropping a combinator
16//! drops the state it owns unless that combinator documents a drain contract.
17//!
18//! # Combinators
19//!
20//! ## Transformation
21//! - [`Map`]: Transforms each item with a closure
22//! - [`Filter`]: Yields only items matching a predicate
23//! - [`FilterMap`]: Combines filter and map in one step
24//! - [`Then`]: Async map (runs future per item)
25//! - [`Enumerate`]: Adds index to items
26//! - [`Inspect`]: Runs closure on items without consuming
27//!
28//! ## Selection
29//! - [`Take`]: Limits stream to n items
30//! - [`TakeWhile`]: Limits stream while predicate is true
31//! - [`Skip`]: Skips n items
32//! - [`SkipWhile`]: Skips while predicate is true
33//! - [`Fuse`]: Fuses the stream
34//!
35//! ## Combination
36//! - [`Chain`]: Yields all items from one stream then another
37//! - [`Zip`]: Pairs items from two streams
38//! - [`Merge`]: Interleaves items from multiple streams
39//!
40//! ## Splitting
41//! - [`Partition`]: Splits one stream into two by a predicate, with a bounded
42//!   per-lane buffer and an explicit head-of-line backpressure contract
43//!
44//! ## Stateful
45//! - [`Scan`]: Yields intermediate accumulator values (like `Iterator::scan`)
46//! - [`Peekable`]: Look at the next item without consuming it
47//!
48//! ## Rate Control
49//! - [`Throttle`]: Rate-limits to at most one item per period
50//! - [`Debounce`]: Suppresses rapid bursts, yielding after a quiet period
51//!
52//! ## Buffering
53//! - [`Buffered`]: Runs multiple futures while preserving order
54//! - [`BufferUnordered`]: Runs multiple futures without ordering guarantees
55//! - [`TryBuffered`]: Ordered buffering of fallible futures, stopping at the first `Err`
56//! - [`Chunks`]: Groups items into fixed-size batches
57//! - [`ReadyChunks`]: Returns immediately available items
58//!
59//! The three future-buffering combinators expose deterministic pressure
60//! telemetry via `telemetry_snapshot(id)`, returning a
61//! [`StreamTelemetrySnapshot`] in the same idiom as
62//! [`SyncTelemetrySnapshot`](crate::sync::SyncTelemetrySnapshot).
63//!
64//! ## Terminal Operations
65//! - [`Collect`]: Collects all items into a collection
66//! - [`StreamExt::collect_into`]: Collects into a caller-supplied collection, reusing its allocation
67//! - [`Fold`]: Reduces items into a single value
68//! - [`ForEach`]: Executes a closure for each item
69//! - [`Count`]: Counts the number of items
70//! - [`Any`]: Checks if any item matches a predicate
71//! - [`All`]: Checks if all items match a predicate
72//!
73//! ## Bounded Concurrency
74//!
75//! These take a [`Cx`](crate::Cx) and run each item as a **region task**, so
76//! in-flight work is drained rather than dropped on cancellation or error.
77//! Prefer [`BufferUnordered`] when the per-item work is pure and holds no
78//! obligation — it is lighter and needs no `Send + 'static` bounds.
79//!
80//! - [`for_each_concurrent`]: Applies an async function with at most `limit` items in flight
81//! - [`try_for_each_concurrent`]: Same, stopping at the first failure and draining the rest
82//!
83//! ## Error Handling
84//! - [`TryCollect`]: Collects items from a stream of Results
85//! - [`TryFold`]: Folds a stream of Results
86//! - [`TryForEach`]: Executes a fallible closure for each item
87//!
88//! # Examples
89//!
90//! <!-- core-api-doctest: stream-ext -->
91//! ```
92//! use asupersync::{Cx, main};
93//! use asupersync::stream::{StreamExt, iter};
94//!
95//! #[main]
96//! async fn main(cx: &Cx) {
97//!     cx.checkpoint().expect("example starts active");
98//!     let sum = iter(vec![1, 2, 3, 4, 5])
99//!         .filter(|x| *x % 2 == 0)
100//!         .map(|x| x * 2)
101//!         .fold(0, |acc, x| acc + x)
102//!         .await;
103//!     assert_eq!(sum, 12); // (2*2) + (4*2) = 12
104//! }
105//! ```
106
107/// Redacted, deterministic pressure telemetry for future-buffering stream
108/// combinators.
109///
110/// The caller supplies `combinator_id`, so the runtime does not need ambient
111/// global registration — the same rule as
112/// [`SyncTelemetrySnapshot`](crate::sync::SyncTelemetrySnapshot). Snapshots
113/// report only aggregate pressure and lifecycle state, never item values.
114///
115/// # Determinism
116///
117/// Every field is derived from combinator state that the polling schedule fully
118/// determines. Under the lab runtime, the same seed therefore produces the same
119/// sequence of snapshots at the same observation points.
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
121pub struct StreamTelemetrySnapshot {
122    /// Caller-provided stable combinator identifier.
123    pub combinator_id: u64,
124    /// Combinator kind: `"buffered"`, `"buffer_unordered"`, or `"try_buffered"`.
125    pub combinator_kind: &'static str,
126    /// Maximum number of futures the combinator will run concurrently.
127    pub limit: usize,
128    /// Futures currently admitted and not yet yielded.
129    pub in_flight: usize,
130    /// Slots immediately available for new admissions.
131    pub available: usize,
132    /// Completed results parked behind head-of-line ordering: futures that
133    /// have resolved but whose output cannot be yielded yet because an earlier
134    /// future is still pending. Structurally zero for `buffer_unordered`,
135    /// which yields completions immediately.
136    pub ready_results: usize,
137    /// Monotonic count of distinct polling-task wakers observed. Rapid growth
138    /// is the waker-churn signal: the combinator is being moved between tasks
139    /// or executors instead of being polled from a stable home.
140    pub waker_epoch: u64,
141    /// Whether the combinator will admit no further futures: the source is
142    /// exhausted, or (for `try_buffered`) the stream already yielded its
143    /// terminal `Err`.
144    pub closed: bool,
145}
146
147mod any_all;
148mod broadcast_stream;
149mod buffered;
150mod chain;
151mod chunks;
152mod collect;
153mod count;
154mod debounce;
155mod enumerate;
156mod filter;
157mod fold;
158mod for_each;
159mod for_each_concurrent;
160mod forward;
161mod fuse;
162mod inspect;
163mod iter;
164mod map;
165mod merge;
166mod next;
167mod partition;
168mod peekable;
169mod receiver_stream;
170mod scan;
171mod skip;
172mod stream;
173mod take;
174mod then;
175mod throttle;
176mod try_buffered;
177mod try_stream;
178mod watch_stream;
179mod zip;
180
181pub use any_all::{All, Any};
182pub use broadcast_stream::{BroadcastStream, BroadcastStreamRecvError};
183pub use buffered::{BufferUnordered, Buffered};
184pub use chain::Chain;
185pub use chunks::{Chunks, ReadyChunks};
186pub use collect::Collect;
187pub use count::Count;
188pub use debounce::Debounce;
189pub use enumerate::Enumerate;
190pub use filter::{Filter, FilterMap};
191pub use fold::Fold;
192pub use for_each::{ForEach, ForEachAsync};
193pub use for_each_concurrent::{for_each_concurrent, try_for_each_concurrent};
194pub use forward::{SinkStream, forward, into_sink};
195pub use fuse::Fuse;
196pub use inspect::Inspect;
197pub use iter::{Iter, iter};
198pub use map::Map;
199pub use merge::{Merge, merge};
200pub use next::Next;
201pub use partition::{Partition, partition};
202pub use peekable::Peekable;
203pub use receiver_stream::ReceiverStream;
204pub use scan::Scan;
205pub use skip::{Skip, SkipWhile};
206pub use stream::Stream;
207pub use take::{Take, TakeWhile};
208pub use then::Then;
209pub use throttle::Throttle;
210pub use try_buffered::TryBuffered;
211pub use try_stream::{TryCollect, TryFold, TryForEach, TryStreamError};
212pub use watch_stream::WatchStream;
213pub use zip::Zip;
214
215use std::future::Future;
216use std::time::Duration;
217
218/// Extension trait providing combinator methods for streams.
219///
220/// This trait is automatically implemented for all types that implement [`Stream`].
221/// Consuming adapters require `Self: Sized`; borrowed terminal operations may
222/// add `Unpin`, and concurrent region operations add their own `Send` and
223/// lifetime bounds. Implementing `StreamExt` does not change the marker traits
224/// or lifetime of the underlying stream.
225pub trait StreamExt: Stream {
226    /// Returns the next item from the stream.
227    ///
228    /// Dropping the returned future before it resolves releases the mutable
229    /// borrow, so the stream can be polled again. It does not roll back state
230    /// changes made by an earlier `poll_next` call; losslessness therefore
231    /// depends on the underlying stream's documented cancellation contract.
232    /// Address-sensitive (`!Unpin`) streams must be pinned and polled through
233    /// [`Stream::poll_next`] instead of this convenience method.
234    ///
235    /// ```compile_fail
236    /// use asupersync::stream::{Stream, StreamExt};
237    /// use std::marker::PhantomPinned;
238    /// use std::pin::Pin;
239    /// use std::task::{Context, Poll};
240    ///
241    /// struct AddressSensitive {
242    ///     _pin: PhantomPinned,
243    /// }
244    ///
245    /// impl Stream for AddressSensitive {
246    ///     type Item = ();
247    ///
248    ///     fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<()>> {
249    ///         let _ = self;
250    ///         Poll::Ready(None)
251    ///     }
252    /// }
253    ///
254    /// let mut stream = AddressSensitive { _pin: PhantomPinned };
255    /// let _next = stream.next(); // `AddressSensitive` does not implement `Unpin`.
256    /// ```
257    fn next(&mut self) -> Next<'_, Self>
258    where
259        Self: Unpin,
260    {
261        Next::new(self)
262    }
263
264    /// Transforms each item using a closure.
265    fn map<T, F>(self, f: F) -> Map<Self, F>
266    where
267        Self: Sized,
268        F: FnMut(Self::Item) -> T,
269    {
270        Map::new(self, f)
271    }
272
273    /// Transforms each item using an async closure.
274    fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
275    where
276        Self: Sized,
277        F: FnMut(Self::Item) -> Fut,
278        Fut: Future,
279    {
280        Then::new(self, f)
281    }
282
283    /// Chains this stream with another stream.
284    fn chain<S2>(self, other: S2) -> Chain<Self, S2>
285    where
286        Self: Sized,
287        S2: Stream<Item = Self::Item>,
288    {
289        Chain::new(self, other)
290    }
291
292    /// Interleaves this stream with another stream of the same concrete type.
293    ///
294    /// For heterogeneous stream types, use [`chain`](Self::chain), [`zip`](Self::zip),
295    /// or the free [`merge`] function with an iterator of streams.
296    fn merge(self, other: Self) -> Merge<Self>
297    where
298        Self: Sized,
299    {
300        merge([self, other])
301    }
302
303    /// Zips this stream with another stream, yielding pairs.
304    fn zip<S2>(self, other: S2) -> Zip<Self, S2>
305    where
306        Self: Sized,
307        S2: Stream,
308    {
309        Zip::new(self, other)
310    }
311
312    /// Yields only items that match the predicate.
313    fn filter<P>(self, predicate: P) -> Filter<Self, P>
314    where
315        Self: Sized,
316        P: FnMut(&Self::Item) -> bool,
317    {
318        Filter::new(self, predicate)
319    }
320
321    /// Filters and transforms items in one step.
322    fn filter_map<T, F>(self, f: F) -> FilterMap<Self, F>
323    where
324        Self: Sized,
325        F: FnMut(Self::Item) -> Option<T>,
326    {
327        FilterMap::new(self, f)
328    }
329
330    /// Splits this stream into two by `predicate`.
331    ///
332    /// The first returned stream yields items for which `predicate` returned
333    /// `true`, the second yields the rest. Each item is delivered to exactly
334    /// one half; the predicate runs once per item.
335    ///
336    /// `lane_capacity` bounds how many items may be buffered for the half that
337    /// is not currently being polled. Once that buffer is full, the polling
338    /// half stalls until its peer drains — so **both halves must be consumed**,
339    /// or the unwanted one dropped. See [`partition`] for the full backpressure
340    /// and wakeup contract.
341    ///
342    /// # Panics
343    ///
344    /// Panics if `lane_capacity` is zero.
345    fn partition<P>(
346        self,
347        predicate: P,
348        lane_capacity: usize,
349    ) -> (Partition<Self, P>, Partition<Self, P>)
350    where
351        Self: Sized + Unpin,
352        P: FnMut(&Self::Item) -> bool,
353    {
354        partition(self, predicate, lane_capacity)
355    }
356
357    /// Takes the first `n` items.
358    fn take(self, n: usize) -> Take<Self>
359    where
360        Self: Sized,
361    {
362        Take::new(self, n)
363    }
364
365    /// Takes items while the predicate is true.
366    fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
367    where
368        Self: Sized,
369        P: FnMut(&Self::Item) -> bool,
370    {
371        TakeWhile::new(self, predicate)
372    }
373
374    /// Skips the first `n` items.
375    fn skip(self, n: usize) -> Skip<Self>
376    where
377        Self: Sized,
378    {
379        Skip::new(self, n)
380    }
381
382    /// Skips items while the predicate is true.
383    fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
384    where
385        Self: Sized,
386        P: FnMut(&Self::Item) -> bool,
387    {
388        SkipWhile::new(self, predicate)
389    }
390
391    /// Enumerates items with their index.
392    fn enumerate(self) -> Enumerate<Self>
393    where
394        Self: Sized,
395    {
396        Enumerate::new(self)
397    }
398
399    /// Fuses the stream to handle None gracefully.
400    fn fuse(self) -> Fuse<Self>
401    where
402        Self: Sized,
403    {
404        Fuse::new(self)
405    }
406
407    /// Inspects items without modifying the stream.
408    fn inspect<F>(self, f: F) -> Inspect<Self, F>
409    where
410        Self: Sized,
411        F: FnMut(&Self::Item),
412    {
413        Inspect::new(self, f)
414    }
415
416    /// Buffers up to `n` futures, preserving output order.
417    fn buffered(self, n: usize) -> Buffered<Self>
418    where
419        Self: Sized,
420        Self::Item: std::future::Future,
421    {
422        Buffered::new(self, n)
423    }
424
425    /// Buffers up to `n` futures, yielding results as they complete.
426    fn buffer_unordered(self, n: usize) -> BufferUnordered<Self>
427    where
428        Self: Sized,
429        Self::Item: std::future::Future,
430    {
431        BufferUnordered::new(self, n)
432    }
433
434    /// Buffers up to `n` fallible futures in order, stopping at the first `Err`.
435    ///
436    /// Outputs are yielded in **source order**, so the terminating error is the
437    /// first `Err` in the source sequence rather than the first to complete.
438    /// That makes the outcome independent of completion timing.
439    ///
440    /// In-flight futures are dropped when the stream short-circuits; they are
441    /// plain futures, not region tasks. Use
442    /// [`try_for_each_concurrent`] when the per-item work
443    /// holds obligations and must be drained instead of dropped.
444    ///
445    /// # Example
446    ///
447    /// ```ignore
448    /// use asupersync::stream::{iter, StreamExt};
449    ///
450    /// async fn first_four(jobs: Vec<Job>) -> Result<Vec<Out>, Error> {
451    ///     // 4 jobs run at once; results arrive in job order, and the first
452    ///     // failing job in that order ends the stream.
453    ///     iter(jobs).map(run).try_buffered(4).try_collect().await
454    /// }
455    /// # struct Job; struct Out; struct Error;
456    /// # async fn run(_j: Job) -> Result<Out, Error> { std::future::pending().await }
457    /// ```
458    fn try_buffered(self, n: usize) -> TryBuffered<Self>
459    where
460        Self: Sized,
461        Self::Item: std::future::Future,
462    {
463        TryBuffered::new(self, n)
464    }
465
466    /// Collects all items into a collection.
467    fn collect<C>(self) -> Collect<Self, C>
468    where
469        Self: Sized,
470        C: Default + Extend<Self::Item>,
471    {
472        Collect::new(self, C::default())
473    }
474
475    /// Collects all items into `collection`, reusing its existing allocation.
476    ///
477    /// This is [`collect`](Self::collect) with a caller-supplied starting
478    /// collection instead of `C::default()`. Use it to append to an existing
479    /// buffer, or to recycle one allocation across repeated drains rather than
480    /// allocating a fresh collection each time.
481    ///
482    /// Items already present in `collection` are preserved; stream items are
483    /// appended via [`Extend`].
484    ///
485    /// # Example
486    ///
487    /// ```ignore
488    /// use asupersync::stream::{iter, StreamExt};
489    ///
490    /// async fn drain_into(buf: Vec<i32>) -> Vec<i32> {
491    ///     // Reuses `buf`'s allocation instead of allocating a fresh Vec, and
492    ///     // appends after whatever it already held.
493    ///     iter(vec![4, 5, 6]).collect_into(buf).await
494    /// }
495    /// ```
496    fn collect_into<C>(self, collection: C) -> Collect<Self, C>
497    where
498        Self: Sized,
499        C: Default + Extend<Self::Item>,
500    {
501        Collect::new(self, collection)
502    }
503
504    /// Collects items into fixed-size chunks.
505    fn chunks(self, size: usize) -> Chunks<Self>
506    where
507        Self: Sized,
508    {
509        Chunks::new(self, size)
510    }
511
512    /// Yields immediately available items up to a maximum chunk size.
513    fn ready_chunks(self, size: usize) -> ReadyChunks<Self>
514    where
515        Self: Sized,
516    {
517        ReadyChunks::new(self, size)
518    }
519
520    /// Folds all items into a single value.
521    fn fold<Acc, F>(self, init: Acc, f: F) -> Fold<Self, F, Acc>
522    where
523        Self: Sized,
524        F: FnMut(Acc, Self::Item) -> Acc,
525    {
526        Fold::new(self, init, f)
527    }
528
529    /// Executes a closure for each item.
530    fn for_each<F>(self, f: F) -> ForEach<Self, F>
531    where
532        Self: Sized,
533        F: FnMut(Self::Item),
534    {
535        ForEach::new(self, f)
536    }
537
538    /// Executes an async closure for each item.
539    fn for_each_async<F, Fut>(self, f: F) -> ForEachAsync<Self, F, Fut>
540    where
541        Self: Sized,
542        F: FnMut(Self::Item) -> Fut,
543        Fut: Future<Output = ()>,
544    {
545        ForEachAsync::new(self, f)
546    }
547
548    /// Counts the number of items in the stream.
549    fn count(self) -> Count<Self>
550    where
551        Self: Sized,
552    {
553        Count::new(self)
554    }
555
556    /// Checks if any item matches the predicate.
557    fn any<P>(self, predicate: P) -> Any<Self, P>
558    where
559        Self: Sized,
560        P: FnMut(&Self::Item) -> bool,
561    {
562        Any::new(self, predicate)
563    }
564
565    /// Checks if all items match the predicate.
566    fn all<P>(self, predicate: P) -> All<Self, P>
567    where
568        Self: Sized,
569        P: FnMut(&Self::Item) -> bool,
570    {
571        All::new(self, predicate)
572    }
573
574    /// Collects items from a stream of Results, short-circuiting on error.
575    fn try_collect<T, E, C>(self) -> TryCollect<Self, C>
576    where
577        Self: Stream<Item = Result<T, E>> + Sized,
578        C: Default + Extend<T>,
579    {
580        TryCollect::new(self, C::default())
581    }
582
583    /// Folds a stream of Results, short-circuiting on error.
584    fn try_fold<T, E, Acc, F>(self, init: Acc, f: F) -> TryFold<Self, F, Acc>
585    where
586        Self: Stream<Item = Result<T, E>> + Sized,
587        F: FnMut(Acc, T) -> Result<Acc, E>,
588    {
589        TryFold::new(self, init, f)
590    }
591
592    /// Executes a fallible closure for each item, short-circuiting on error.
593    fn try_for_each<F, E>(self, f: F) -> TryForEach<Self, F>
594    where
595        Self: Sized,
596        F: FnMut(Self::Item) -> Result<(), E>,
597    {
598        TryForEach::new(self, f)
599    }
600
601    /// Yields intermediate accumulator values, like [`Iterator::scan`].
602    ///
603    /// For each item, calls `f(&mut state, item)`. If `f` returns
604    /// `Some(value)`, the value is yielded. If `f` returns `None`,
605    /// the stream terminates.
606    fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
607    where
608        Self: Sized,
609        F: FnMut(&mut St, Self::Item) -> Option<B>,
610    {
611        Scan::new(self, initial_state, f)
612    }
613
614    /// Creates a peekable stream that supports looking at the next
615    /// item without consuming it.
616    fn peekable(self) -> Peekable<Self>
617    where
618        Self: Sized,
619    {
620        Peekable::new(self)
621    }
622
623    /// Rate-limits the stream to at most one item per `period`.
624    ///
625    /// The first item passes through immediately. Subsequent items
626    /// that arrive within the suppression window are dropped.
627    fn throttle(self, period: Duration) -> Throttle<Self>
628    where
629        Self: Sized,
630    {
631        Throttle::new(self, period)
632    }
633
634    /// Debounces the stream, emitting only after a quiet period.
635    ///
636    /// When items arrive, they are buffered. If no new item arrives
637    /// for `period`, the most recent item is yielded. When the
638    /// underlying stream ends, any buffered item is flushed immediately.
639    fn debounce(self, period: Duration) -> Debounce<Self>
640    where
641        Self: Sized,
642        Self::Item: Unpin,
643    {
644        Debounce::new(self, period)
645    }
646}
647
648// Blanket implementation for all Stream types
649impl<S: Stream + ?Sized> StreamExt for S {}
650
651#[cfg(test)]
652mod tests {
653    #![allow(
654        clippy::pedantic,
655        clippy::nursery,
656        clippy::expect_fun_call,
657        clippy::map_unwrap_or,
658        clippy::cast_possible_wrap,
659        clippy::future_not_send
660    )]
661    use super::*;
662    use crate::channel::{broadcast, mpsc, watch};
663    use crate::cx::Cx;
664    use std::cell::RefCell;
665    use std::future::Future;
666    use std::pin::Pin;
667
668    use std::task::{Context, Poll, Waker};
669
670    fn noop_waker() -> Waker {
671        std::task::Waker::noop().clone()
672    }
673
674    fn init_test(name: &str) {
675        crate::test_utils::init_test_logging();
676        crate::test_phase!(name);
677    }
678
679    #[test]
680    fn stream_ext_chaining() {
681        init_test("stream_ext_chaining");
682
683        // Test that combinators can be chained
684        let stream = iter(vec![1i32, 2, 3, 4, 5, 6])
685            .filter(|&x: &i32| x % 2 == 0)
686            .map(|x: i32| x * 10);
687
688        let mut collect = stream.collect::<Vec<_>>();
689        let waker = noop_waker();
690        let mut cx = Context::from_waker(&waker);
691
692        match Pin::new(&mut collect).poll(&mut cx) {
693            Poll::Ready(result) => {
694                let ok = result == vec![20, 40, 60];
695                crate::assert_with_log!(ok, "collected", vec![20, 40, 60], result);
696            }
697            Poll::Pending => panic!("expected Ready"),
698        }
699        crate::test_complete!("stream_ext_chaining");
700    }
701
702    #[test]
703    fn stream_ext_fold_chain() {
704        init_test("stream_ext_fold_chain");
705
706        let stream = iter(vec![1i32, 2, 3, 4, 5]).map(|x: i32| x * 2);
707
708        let mut fold = stream.fold(0i32, |acc, x| acc + x);
709        let waker = noop_waker();
710        let mut cx = Context::from_waker(&waker);
711
712        match Pin::new(&mut fold).poll(&mut cx) {
713            Poll::Ready(sum) => {
714                let ok = sum == 30;
715                crate::assert_with_log!(ok, "sum", 30, sum);
716            }
717            Poll::Pending => panic!("expected Ready"),
718        }
719        crate::test_complete!("stream_ext_fold_chain");
720    }
721
722    #[test]
723    fn test_stream_next() {
724        init_test("test_stream_next");
725        let mut stream = iter(vec![1, 2, 3]);
726        let waker = noop_waker();
727        let mut cx = Context::from_waker(&waker);
728
729        let mut next = stream.next();
730        let poll = Pin::new(&mut next).poll(&mut cx);
731        crate::assert_with_log!(
732            poll == Poll::Ready(Some(1)),
733            "next 1",
734            Poll::Ready(Some(1)),
735            poll
736        );
737
738        let mut next = stream.next();
739        let poll = Pin::new(&mut next).poll(&mut cx);
740        crate::assert_with_log!(
741            poll == Poll::Ready(Some(2)),
742            "next 2",
743            Poll::Ready(Some(2)),
744            poll
745        );
746
747        let mut next = stream.next();
748        let poll = Pin::new(&mut next).poll(&mut cx);
749        crate::assert_with_log!(
750            poll == Poll::Ready(Some(3)),
751            "next 3",
752            Poll::Ready(Some(3)),
753            poll
754        );
755
756        let mut next = stream.next();
757        let poll = Pin::new(&mut next).poll(&mut cx);
758        crate::assert_with_log!(
759            poll == Poll::Ready(None::<i32>),
760            "next done",
761            Poll::Ready(None::<i32>),
762            poll
763        );
764        crate::test_complete!("test_stream_next");
765    }
766
767    #[test]
768    fn test_stream_map() {
769        init_test("test_stream_map");
770        let stream = iter(vec![1, 2, 3]);
771        let mut mapped = stream.map(|x| x * 2);
772        let waker = noop_waker();
773        let mut cx = Context::from_waker(&waker);
774
775        let poll = Pin::new(&mut mapped).poll_next(&mut cx);
776        crate::assert_with_log!(
777            poll == Poll::Ready(Some(2)),
778            "map 1",
779            Poll::Ready(Some(2)),
780            poll
781        );
782        let poll = Pin::new(&mut mapped).poll_next(&mut cx);
783        crate::assert_with_log!(
784            poll == Poll::Ready(Some(4)),
785            "map 2",
786            Poll::Ready(Some(4)),
787            poll
788        );
789        let poll = Pin::new(&mut mapped).poll_next(&mut cx);
790        crate::assert_with_log!(
791            poll == Poll::Ready(Some(6)),
792            "map 3",
793            Poll::Ready(Some(6)),
794            poll
795        );
796        let poll = Pin::new(&mut mapped).poll_next(&mut cx);
797        crate::assert_with_log!(
798            poll == Poll::Ready(None::<i32>),
799            "map done",
800            Poll::Ready(None::<i32>),
801            poll
802        );
803        crate::test_complete!("test_stream_map");
804    }
805
806    #[test]
807    fn test_stream_filter() {
808        init_test("test_stream_filter");
809        let stream = iter(vec![1, 2, 3, 4, 5, 6]);
810        let mut filtered = stream.filter(|x| x % 2 == 0);
811        let waker = noop_waker();
812        let mut cx = Context::from_waker(&waker);
813
814        let poll = Pin::new(&mut filtered).poll_next(&mut cx);
815        crate::assert_with_log!(
816            poll == Poll::Ready(Some(2)),
817            "filter 1",
818            Poll::Ready(Some(2)),
819            poll
820        );
821        let poll = Pin::new(&mut filtered).poll_next(&mut cx);
822        crate::assert_with_log!(
823            poll == Poll::Ready(Some(4)),
824            "filter 2",
825            Poll::Ready(Some(4)),
826            poll
827        );
828        let poll = Pin::new(&mut filtered).poll_next(&mut cx);
829        crate::assert_with_log!(
830            poll == Poll::Ready(Some(6)),
831            "filter 3",
832            Poll::Ready(Some(6)),
833            poll
834        );
835        let poll = Pin::new(&mut filtered).poll_next(&mut cx);
836        crate::assert_with_log!(
837            poll == Poll::Ready(None::<i32>),
838            "filter done",
839            Poll::Ready(None::<i32>),
840            poll
841        );
842        crate::test_complete!("test_stream_filter");
843    }
844
845    #[test]
846    fn test_stream_filter_map() {
847        init_test("test_stream_filter_map");
848        let stream = iter(vec!["1", "two", "3", "four"]);
849        let mut parsed = stream.filter_map(|s| s.parse::<i32>().ok());
850        let waker = noop_waker();
851        let mut cx = Context::from_waker(&waker);
852
853        let poll = Pin::new(&mut parsed).poll_next(&mut cx);
854        crate::assert_with_log!(
855            poll == Poll::Ready(Some(1)),
856            "filter_map 1",
857            Poll::Ready(Some(1)),
858            poll
859        );
860        let poll = Pin::new(&mut parsed).poll_next(&mut cx);
861        crate::assert_with_log!(
862            poll == Poll::Ready(Some(3)),
863            "filter_map 2",
864            Poll::Ready(Some(3)),
865            poll
866        );
867        let poll = Pin::new(&mut parsed).poll_next(&mut cx);
868        crate::assert_with_log!(
869            poll == Poll::Ready(None::<i32>),
870            "filter_map done",
871            Poll::Ready(None::<i32>),
872            poll
873        );
874        crate::test_complete!("test_stream_filter_map");
875    }
876
877    #[test]
878    fn test_stream_take() {
879        init_test("test_stream_take");
880        let stream = iter(vec![1, 2, 3, 4, 5]);
881        let mut taken = stream.take(3);
882        let waker = noop_waker();
883        let mut cx = Context::from_waker(&waker);
884
885        let poll = Pin::new(&mut taken).poll_next(&mut cx);
886        crate::assert_with_log!(
887            poll == Poll::Ready(Some(1)),
888            "take 1",
889            Poll::Ready(Some(1)),
890            poll
891        );
892        let poll = Pin::new(&mut taken).poll_next(&mut cx);
893        crate::assert_with_log!(
894            poll == Poll::Ready(Some(2)),
895            "take 2",
896            Poll::Ready(Some(2)),
897            poll
898        );
899        let poll = Pin::new(&mut taken).poll_next(&mut cx);
900        crate::assert_with_log!(
901            poll == Poll::Ready(Some(3)),
902            "take 3",
903            Poll::Ready(Some(3)),
904            poll
905        );
906        let poll = Pin::new(&mut taken).poll_next(&mut cx);
907        crate::assert_with_log!(
908            poll == Poll::Ready(None::<i32>),
909            "take done",
910            Poll::Ready(None::<i32>),
911            poll
912        );
913        crate::test_complete!("test_stream_take");
914    }
915
916    #[test]
917    fn test_stream_skip() {
918        init_test("test_stream_skip");
919        let stream = iter(vec![1, 2, 3, 4, 5]);
920        let mut skipped = stream.skip(2);
921        let waker = noop_waker();
922        let mut cx = Context::from_waker(&waker);
923
924        let poll = Pin::new(&mut skipped).poll_next(&mut cx);
925        crate::assert_with_log!(
926            poll == Poll::Ready(Some(3)),
927            "skip 1",
928            Poll::Ready(Some(3)),
929            poll
930        );
931        let poll = Pin::new(&mut skipped).poll_next(&mut cx);
932        crate::assert_with_log!(
933            poll == Poll::Ready(Some(4)),
934            "skip 2",
935            Poll::Ready(Some(4)),
936            poll
937        );
938        let poll = Pin::new(&mut skipped).poll_next(&mut cx);
939        crate::assert_with_log!(
940            poll == Poll::Ready(Some(5)),
941            "skip 3",
942            Poll::Ready(Some(5)),
943            poll
944        );
945        let poll = Pin::new(&mut skipped).poll_next(&mut cx);
946        crate::assert_with_log!(
947            poll == Poll::Ready(None::<i32>),
948            "skip done",
949            Poll::Ready(None::<i32>),
950            poll
951        );
952        crate::test_complete!("test_stream_skip");
953    }
954
955    #[test]
956    fn test_stream_enumerate() {
957        init_test("test_stream_enumerate");
958        let stream = iter(vec!["a", "b", "c"]);
959        let mut enumerated = stream.enumerate();
960        let waker = noop_waker();
961        let mut cx = Context::from_waker(&waker);
962
963        let poll = Pin::new(&mut enumerated).poll_next(&mut cx);
964        crate::assert_with_log!(
965            poll == Poll::Ready(Some((0, "a"))),
966            "enum 0",
967            Poll::Ready(Some((0, "a"))),
968            poll
969        );
970        let poll = Pin::new(&mut enumerated).poll_next(&mut cx);
971        crate::assert_with_log!(
972            poll == Poll::Ready(Some((1, "b"))),
973            "enum 1",
974            Poll::Ready(Some((1, "b"))),
975            poll
976        );
977        let poll = Pin::new(&mut enumerated).poll_next(&mut cx);
978        crate::assert_with_log!(
979            poll == Poll::Ready(Some((2, "c"))),
980            "enum 2",
981            Poll::Ready(Some((2, "c"))),
982            poll
983        );
984        let poll = Pin::new(&mut enumerated).poll_next(&mut cx);
985        crate::assert_with_log!(
986            poll == Poll::Ready(None::<(usize, &str)>),
987            "enum done",
988            Poll::Ready(None::<(usize, &str)>),
989            poll
990        );
991        crate::test_complete!("test_stream_enumerate");
992    }
993
994    #[test]
995    fn test_stream_then() {
996        init_test("test_stream_then");
997        // We need a runtime or manual polling for async map.
998        // But Then combinator returns a Stream.
999        // We can poll it manually.
1000
1001        let stream = iter(vec![1, 2]);
1002        let mut processed = Box::pin(stream.then(|x| async move { x * 10 }));
1003        let waker = noop_waker();
1004        let mut cx = Context::from_waker(&waker);
1005
1006        // First item
1007        let poll = processed.as_mut().poll_next(&mut cx);
1008        let ok = matches!(poll, Poll::Ready(Some(10)));
1009        crate::assert_with_log!(ok, "then 1", "Poll::Ready(Some(10))", poll);
1010
1011        // Second item
1012        let poll = processed.as_mut().poll_next(&mut cx);
1013        crate::assert_with_log!(
1014            poll == Poll::Ready(Some(20)),
1015            "then 2",
1016            Poll::Ready(Some(20)),
1017            poll
1018        );
1019
1020        // End
1021        let poll = processed.as_mut().poll_next(&mut cx);
1022        crate::assert_with_log!(
1023            poll == Poll::Ready(None::<i32>),
1024            "then done",
1025            Poll::Ready(None::<i32>),
1026            poll
1027        );
1028        crate::test_complete!("test_stream_then");
1029    }
1030
1031    #[test]
1032    fn test_stream_inspect() {
1033        init_test("test_stream_inspect");
1034        let stream = iter(vec![1, 2, 3]);
1035        let items = RefCell::new(Vec::new());
1036        let mut inspected = stream.inspect(|x| items.borrow_mut().push(*x));
1037        let waker = noop_waker();
1038        let mut cx = Context::from_waker(&waker);
1039
1040        let poll = Pin::new(&mut inspected).poll_next(&mut cx);
1041        crate::assert_with_log!(
1042            poll == Poll::Ready(Some(1)),
1043            "inspect 1",
1044            Poll::Ready(Some(1)),
1045            poll
1046        );
1047        let items_now = items.borrow().clone();
1048        crate::assert_with_log!(items_now == vec![1], "items", vec![1], items_now);
1049
1050        let poll = Pin::new(&mut inspected).poll_next(&mut cx);
1051        crate::assert_with_log!(
1052            poll == Poll::Ready(Some(2)),
1053            "inspect 2",
1054            Poll::Ready(Some(2)),
1055            poll
1056        );
1057        let items_now = items.borrow().clone();
1058        crate::assert_with_log!(items_now == vec![1, 2], "items", vec![1, 2], items_now);
1059
1060        let poll = Pin::new(&mut inspected).poll_next(&mut cx);
1061        crate::assert_with_log!(
1062            poll == Poll::Ready(Some(3)),
1063            "inspect 3",
1064            Poll::Ready(Some(3)),
1065            poll
1066        );
1067        let items_now = items.borrow().clone();
1068        crate::assert_with_log!(
1069            items_now == vec![1, 2, 3],
1070            "items",
1071            vec![1, 2, 3],
1072            items_now
1073        );
1074
1075        let poll = Pin::new(&mut inspected).poll_next(&mut cx);
1076        crate::assert_with_log!(
1077            poll == Poll::Ready(None::<i32>),
1078            "inspect done",
1079            Poll::Ready(None::<i32>),
1080            poll
1081        );
1082        crate::test_complete!("test_stream_inspect");
1083    }
1084
1085    #[test]
1086    fn test_receiver_stream() {
1087        init_test("test_receiver_stream");
1088
1089        let cx: Cx = Cx::for_testing();
1090        let (tx, rx) = mpsc::channel(10);
1091        let mut stream = ReceiverStream::new(cx, rx);
1092
1093        tx.try_send(1).unwrap();
1094        tx.try_send(2).unwrap();
1095        drop(tx);
1096
1097        let waker = noop_waker();
1098        let mut cx_task = Context::from_waker(&waker);
1099
1100        let poll = Pin::new(&mut stream).poll_next(&mut cx_task);
1101        crate::assert_with_log!(
1102            poll == Poll::Ready(Some(1)),
1103            "recv 1",
1104            Poll::Ready(Some(1)),
1105            poll
1106        );
1107        let poll = Pin::new(&mut stream).poll_next(&mut cx_task);
1108        crate::assert_with_log!(
1109            poll == Poll::Ready(Some(2)),
1110            "recv 2",
1111            Poll::Ready(Some(2)),
1112            poll
1113        );
1114        let poll = Pin::new(&mut stream).poll_next(&mut cx_task);
1115        crate::assert_with_log!(
1116            poll == Poll::Ready(None::<i32>),
1117            "recv done",
1118            Poll::Ready(None::<i32>),
1119            poll
1120        );
1121        crate::test_complete!("test_receiver_stream");
1122    }
1123
1124    #[test]
1125    fn test_watch_stream() {
1126        init_test("test_watch_stream");
1127
1128        let cx: Cx = Cx::for_testing();
1129        let (tx, rx) = watch::channel(0);
1130        let mut stream = WatchStream::new(cx, rx);
1131        let waker = noop_waker();
1132        let mut cx_task = Context::from_waker(&waker);
1133
1134        // Initial value
1135        let poll = Pin::new(&mut stream).poll_next(&mut cx_task);
1136        crate::assert_with_log!(
1137            poll == Poll::Ready(Some(0)),
1138            "watch 0",
1139            Poll::Ready(Some(0)),
1140            poll
1141        );
1142
1143        // Update value
1144        tx.send(1).unwrap();
1145        let poll = Pin::new(&mut stream).poll_next(&mut cx_task);
1146        crate::assert_with_log!(
1147            poll == Poll::Ready(Some(1)),
1148            "watch 1",
1149            Poll::Ready(Some(1)),
1150            poll
1151        );
1152        crate::test_complete!("test_watch_stream");
1153    }
1154
1155    #[test]
1156    fn test_broadcast_stream() {
1157        init_test("test_broadcast_stream");
1158
1159        let cx: Cx = Cx::for_testing();
1160        let (tx, rx) = broadcast::channel(10);
1161        let mut stream = BroadcastStream::new(cx.clone(), rx);
1162        let waker = noop_waker();
1163        let mut cx_task = Context::from_waker(&waker);
1164
1165        tx.send(&cx, 1).unwrap();
1166        tx.send(&cx, 2).unwrap();
1167
1168        let poll = Pin::new(&mut stream).poll_next(&mut cx_task);
1169        crate::assert_with_log!(
1170            poll == Poll::Ready(Some(Ok::<i32, BroadcastStreamRecvError>(1))),
1171            "broadcast 1",
1172            Poll::Ready(Some(Ok::<i32, BroadcastStreamRecvError>(1))),
1173            poll
1174        );
1175        let poll = Pin::new(&mut stream).poll_next(&mut cx_task);
1176        crate::assert_with_log!(
1177            poll == Poll::Ready(Some(Ok::<i32, BroadcastStreamRecvError>(2))),
1178            "broadcast 2",
1179            Poll::Ready(Some(Ok::<i32, BroadcastStreamRecvError>(2))),
1180            poll
1181        );
1182        crate::test_complete!("test_broadcast_stream");
1183    }
1184
1185    #[test]
1186    fn test_forward() {
1187        init_test("test_forward");
1188
1189        let cx: Cx = Cx::for_testing();
1190        let (tx_out, rx_out) = mpsc::channel(10);
1191        let input = iter(vec![1, 2, 3]);
1192
1193        futures_lite::future::block_on(async {
1194            forward(&cx, input, tx_out).await.unwrap();
1195        });
1196
1197        let mut output = ReceiverStream::new(cx, rx_out);
1198        let waker = noop_waker();
1199        let mut cx_task = Context::from_waker(&waker);
1200
1201        let poll = Pin::new(&mut output).poll_next(&mut cx_task);
1202        crate::assert_with_log!(
1203            poll == Poll::Ready(Some(1)),
1204            "forward 1",
1205            Poll::Ready(Some(1)),
1206            poll
1207        );
1208        let poll = Pin::new(&mut output).poll_next(&mut cx_task);
1209        crate::assert_with_log!(
1210            poll == Poll::Ready(Some(2)),
1211            "forward 2",
1212            Poll::Ready(Some(2)),
1213            poll
1214        );
1215        let poll = Pin::new(&mut output).poll_next(&mut cx_task);
1216        crate::assert_with_log!(
1217            poll == Poll::Ready(Some(3)),
1218            "forward 3",
1219            Poll::Ready(Some(3)),
1220            poll
1221        );
1222        let poll = Pin::new(&mut output).poll_next(&mut cx_task);
1223        crate::assert_with_log!(
1224            poll == Poll::Ready(None::<i32>),
1225            "forward done",
1226            Poll::Ready(None::<i32>),
1227            poll
1228        );
1229        crate::test_complete!("test_forward");
1230    }
1231
1232    #[test]
1233    fn test_stream_merge_method() {
1234        init_test("test_stream_merge_method");
1235
1236        let mut merged = iter(vec![1, 2, 3]).merge(iter(vec![10, 20, 30]));
1237        let waker = noop_waker();
1238        let mut cx = Context::from_waker(&waker);
1239
1240        let poll = Pin::new(&mut merged).poll_next(&mut cx);
1241        crate::assert_with_log!(
1242            poll == Poll::Ready(Some(1)),
1243            "merge first",
1244            Poll::Ready(Some(1)),
1245            poll
1246        );
1247        let poll = Pin::new(&mut merged).poll_next(&mut cx);
1248        crate::assert_with_log!(
1249            poll == Poll::Ready(Some(10)),
1250            "merge second",
1251            Poll::Ready(Some(10)),
1252            poll
1253        );
1254        let poll = Pin::new(&mut merged).poll_next(&mut cx);
1255        crate::assert_with_log!(
1256            poll == Poll::Ready(Some(2)),
1257            "merge third",
1258            Poll::Ready(Some(2)),
1259            poll
1260        );
1261        let poll = Pin::new(&mut merged).poll_next(&mut cx);
1262        crate::assert_with_log!(
1263            poll == Poll::Ready(Some(20)),
1264            "merge fourth",
1265            Poll::Ready(Some(20)),
1266            poll
1267        );
1268        let poll = Pin::new(&mut merged).poll_next(&mut cx);
1269        crate::assert_with_log!(
1270            poll == Poll::Ready(Some(3)),
1271            "merge fifth",
1272            Poll::Ready(Some(3)),
1273            poll
1274        );
1275        let poll = Pin::new(&mut merged).poll_next(&mut cx);
1276        crate::assert_with_log!(
1277            poll == Poll::Ready(Some(30)),
1278            "merge sixth",
1279            Poll::Ready(Some(30)),
1280            poll
1281        );
1282        let poll = Pin::new(&mut merged).poll_next(&mut cx);
1283        crate::assert_with_log!(
1284            poll == Poll::Ready(None::<i32>),
1285            "merge done",
1286            Poll::Ready(None::<i32>),
1287            poll
1288        );
1289        crate::test_complete!("test_stream_merge_method");
1290    }
1291}