@@ -145,6 +145,99 @@ macro_rules! doc {
145
145
/// application is shutting down, then you probably don't care that partially
146
146
/// read data is lost.
147
147
///
148
+ /// # Alternatives from the Ecosystem
149
+ ///
150
+ /// The `select!` macro is a versatile tool for working with multiple asynchronous
151
+ /// branches, allowing tasks to run concurrently within the same thread. However,
152
+ /// depending on your use case, ecosystem alternatives can provide additional
153
+ /// benefits, such as more straightforward syntax, more transparent control flow or
154
+ /// reducing the burned of cancellation safety or fuse semantics.
155
+ ///
156
+ /// ## Merging Streams
157
+ ///
158
+ /// For cases where `loop { select! { ... } }` is used to poll multiple tasks,
159
+ /// stream merging offers a concise alternative, inherently handle cancellation-safe
160
+ /// processing, removing the risk of data loss. Libraries like
161
+ /// [`tokio-stream`](https://docs.rs/tokio-stream/latest/tokio_stream/) and
162
+ /// [`futures-concurrency`](https://docs.rs/futures-concurrency/latest/futures_concurrency/)
163
+ /// provide tools for merging streams and handling their outputs sequentially.
164
+ ///
165
+ /// ### Example with `select!`
166
+ ///
167
+ /// ```ignore
168
+ /// // open our IO types
169
+ /// let mut file = /* ... */;
170
+ /// let mut channel = /* ... */;
171
+ ///
172
+ /// async fn read_send(file: ..., channel: ...) { /* do work that is not cancel safe */ }
173
+ ///
174
+ /// // This loop re-creates the `read_send` future on each iteration. That means if
175
+ /// // `socket.read_packet()` completes, `read_send` may have read data from the file,
176
+ /// // but not finished writing it to a channel, which can lead to data loss
177
+ /// loop {
178
+ /// select! {
179
+ /// _ = read_send(&mut file, &mut channel) => {}, // data loss can happen here
180
+ /// data = socket.read_packet() => {
181
+ /// // ...
182
+ /// }
183
+ /// }
184
+ /// }
185
+ /// ```
186
+ ///
187
+ /// ### Moving to `merge`
188
+ ///
189
+ /// By using merge, you can unify multiple asynchronous tasks into a single stream,
190
+ /// eliminating the need to manage tasks manually and reducing the risk of
191
+ /// unintended behavior like data loss.
192
+ ///
193
+ /// ```ignore
194
+ /// let mut file = /* ... */;
195
+ /// let mut channel = /* ... */;
196
+ ///
197
+ /// enum Message {
198
+ /// None,
199
+ /// Data(Vec<u8>),
200
+ /// }
201
+ ///
202
+ /// async fn read_send(file: ..., channel: ...) { /* ... */ }
203
+ ///
204
+ /// let a = futures_lite::stream::repeat_with(|| read_send(&mut file, &mut channel)).map(Message::None);
205
+ /// let b = futures_lite::stream::repeat_with(|| socket.read_packet()).map(Message::Data);
206
+ ///
207
+ /// let mut s = pin!(a.merge(b));
208
+ /// while let Some(msg) = s.next().await {
209
+ /// match msg {
210
+ /// Message::None => continue,
211
+ /// Message::Data(data) => /* ... */ ,
212
+ /// }
213
+ /// }
214
+ /// ```
215
+ ///
216
+ /// ## Racing Futures
217
+ ///
218
+ /// If you need to wait for the first completion among several asynchronous tasks,
219
+ /// ecosystem utilities such as
220
+ /// [`futures-lite`](https://docs.rs/futures-lite/latest/futures_lite/) or
221
+ /// [`futures-concurrency`](https://docs.rs/futures-concurrency/latest/futures_concurrency/)
222
+ /// provide streamlined syntax for racing futures:
223
+ ///
224
+ /// - [`futures-lite::future::or`](https://docs.rs/futures-lite/latest/futures_lite/future/fn.or.html)
225
+ /// - [`futures-lite::future::race`](https://docs.rs/futures-lite/latest/futures_lite/future/fn.race.html)
226
+ /// - [`futures_concurrency::future::Race`](https://docs.rs/futures-concurrency/latest/futures_concurrency/future/trait.Race.html)
227
+ ///
228
+ /// ```ignore
229
+ /// let result = futures_lite::future::race(
230
+ /// async { /* Task A */ },
231
+ /// async { /* Task B */ },
232
+ /// )
233
+ /// .await;
234
+ ///
235
+ /// match result {
236
+ /// Ok(output) => println!("First task completed with: {output}"),
237
+ /// Err(err) => eprintln!("Error occurred: {err}"),
238
+ /// }
239
+ /// ```
240
+ ///
148
241
/// # Examples
149
242
///
150
243
/// Basic select with two branches.
0 commit comments