|
1 | 1 | use super::assert_stream;
|
2 |
| -use crate::stream::{select_with_strategy, ExitStrategy, PollNext, SelectWithStrategy}; |
| 2 | +use crate::stream::{ |
| 3 | + select_with_strategy, ClosedStreams, ExitStrategy, PollNext, SelectWithStrategy, |
| 4 | +}; |
3 | 5 | use core::pin::Pin;
|
4 | 6 | use futures_core::stream::{FusedStream, Stream};
|
5 | 7 | use futures_core::task::{Context, Poll};
|
6 | 8 | use pin_project_lite::pin_project;
|
7 | 9 |
|
| 10 | +type PollNextFn = fn(&mut PollNext) -> PollNext; |
| 11 | + |
8 | 12 | pin_project! {
|
9 | 13 | /// Stream for the [`select()`] function.
|
10 | 14 | #[derive(Debug)]
|
11 | 15 | #[must_use = "streams do nothing unless polled"]
|
12 |
| - pub struct Select<St1, St2> { |
| 16 | + pub struct Select<St1, St2, Exit> { |
13 | 17 | #[pin]
|
14 |
| - inner: SelectWithStrategy<St1, St2, fn(&mut PollNext)-> PollNext, PollNext>, |
| 18 | + inner: SelectWithStrategy<St1, St2, PollNextFn, PollNext, Exit>, |
| 19 | + } |
| 20 | +} |
| 21 | + |
| 22 | +#[derive(Debug)] |
| 23 | +pub struct ExitWhenBothFinished {} |
| 24 | + |
| 25 | +impl ExitStrategy for ExitWhenBothFinished { |
| 26 | + #[inline] |
| 27 | + fn is_terminated(closed_streams: ClosedStreams) -> bool { |
| 28 | + match closed_streams { |
| 29 | + ClosedStreams::Both => true, |
| 30 | + _ => false, |
| 31 | + } |
15 | 32 | }
|
16 | 33 | }
|
17 | 34 |
|
| 35 | +#[derive(Debug)] |
| 36 | +pub struct ExitWhenEitherFinished {} |
| 37 | + |
| 38 | +impl ExitStrategy for ExitWhenEitherFinished { |
| 39 | + #[inline] |
| 40 | + fn is_terminated(closed_streams: ClosedStreams) -> bool { |
| 41 | + match closed_streams { |
| 42 | + ClosedStreams::None => false, |
| 43 | + _ => true, |
| 44 | + } |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +fn round_robin(last: &mut PollNext) -> PollNext { |
| 49 | + last.toggle() |
| 50 | +} |
| 51 | + |
18 | 52 | /// This function will attempt to pull items from both streams. Each
|
19 | 53 | /// stream will be polled in a round-robin fashion, and whenever a stream is
|
20 | 54 | /// ready to yield an item that item is yielded.
|
@@ -44,42 +78,31 @@ pin_project! {
|
44 | 78 | /// }
|
45 | 79 | /// # });
|
46 | 80 | /// ```
|
47 |
| -pub fn select<St1, St2>(stream1: St1, stream2: St2) -> Select<St1, St2> |
| 81 | +pub fn select<St1, St2>(stream1: St1, stream2: St2) -> Select<St1, St2, ExitWhenBothFinished> |
48 | 82 | where
|
49 | 83 | St1: Stream,
|
50 | 84 | St2: Stream<Item = St1::Item>,
|
51 | 85 | {
|
52 |
| - select_with_exit(stream1, stream2, ExitStrategy::WhenBothFinish) |
| 86 | + assert_stream::<St1::Item, _>(Select { |
| 87 | + inner: select_with_strategy(stream1, stream2, round_robin), |
| 88 | + }) |
53 | 89 | }
|
54 | 90 |
|
55 | 91 | /// Same as `select`, but finishes when either stream finishes
|
56 |
| -pub fn select_early_exit<St1, St2>(stream1: St1, stream2: St2) -> Select<St1, St2> |
57 |
| -where |
58 |
| - St1: Stream, |
59 |
| - St2: Stream<Item = St1::Item>, |
60 |
| -{ |
61 |
| - select_with_exit(stream1, stream2, ExitStrategy::WhenEitherFinish) |
62 |
| -} |
63 |
| - |
64 |
| -fn select_with_exit<St1, St2>( |
| 92 | +pub fn select_early_exit<St1, St2>( |
65 | 93 | stream1: St1,
|
66 | 94 | stream2: St2,
|
67 |
| - exit_strategy: ExitStrategy, |
68 |
| -) -> Select<St1, St2> |
| 95 | +) -> Select<St1, St2, ExitWhenEitherFinished> |
69 | 96 | where
|
70 | 97 | St1: Stream,
|
71 | 98 | St2: Stream<Item = St1::Item>,
|
72 | 99 | {
|
73 |
| - fn round_robin(last: &mut PollNext) -> PollNext { |
74 |
| - last.toggle() |
75 |
| - } |
76 |
| - |
77 | 100 | assert_stream::<St1::Item, _>(Select {
|
78 |
| - inner: select_with_strategy(stream1, stream2, round_robin, exit_strategy), |
| 101 | + inner: select_with_strategy(stream1, stream2, round_robin), |
79 | 102 | })
|
80 | 103 | }
|
81 | 104 |
|
82 |
| -impl<St1, St2> Select<St1, St2> { |
| 105 | +impl<St1, St2, Exit> Select<St1, St2, Exit> { |
83 | 106 | /// Acquires a reference to the underlying streams that this combinator is
|
84 | 107 | /// pulling from.
|
85 | 108 | pub fn get_ref(&self) -> (&St1, &St2) {
|
@@ -114,20 +137,22 @@ impl<St1, St2> Select<St1, St2> {
|
114 | 137 | }
|
115 | 138 | }
|
116 | 139 |
|
117 |
| -impl<St1, St2> FusedStream for Select<St1, St2> |
| 140 | +impl<St1, St2, Exit> FusedStream for Select<St1, St2, Exit> |
118 | 141 | where
|
119 | 142 | St1: Stream,
|
120 | 143 | St2: Stream<Item = St1::Item>,
|
| 144 | + Exit: ExitStrategy, |
121 | 145 | {
|
122 | 146 | fn is_terminated(&self) -> bool {
|
123 | 147 | self.inner.is_terminated()
|
124 | 148 | }
|
125 | 149 | }
|
126 | 150 |
|
127 |
| -impl<St1, St2> Stream for Select<St1, St2> |
| 151 | +impl<St1, St2, Exit> Stream for Select<St1, St2, Exit> |
128 | 152 | where
|
129 | 153 | St1: Stream,
|
130 | 154 | St2: Stream<Item = St1::Item>,
|
| 155 | + Exit: ExitStrategy, |
131 | 156 | {
|
132 | 157 | type Item = St1::Item;
|
133 | 158 |
|
|
0 commit comments