-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathfutures_stream.rs
More file actions
82 lines (71 loc) · 2.8 KB
/
Copy pathfutures_stream.rs
File metadata and controls
82 lines (71 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright 2024 litep2p developers
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
use futures::{stream::FuturesUnordered, Stream, StreamExt};
use std::{
future::Future,
pin::Pin,
task::{Context, Poll, Waker},
};
/// Wrapper around [`FuturesUnordered`] that wakes a task up automatically.
/// The [`Stream`] implemented by [`FuturesStream`] never terminates and can be
/// polled when contains no futures.
#[derive(Default)]
pub struct FuturesStream<F> {
futures: FuturesUnordered<F>,
waker: Option<Waker>,
}
impl<F> FuturesStream<F> {
/// Create new [`FuturesStream`].
pub fn new() -> Self {
Self {
futures: FuturesUnordered::new(),
waker: None,
}
}
/// Number of futeres in the stream.
#[cfg(test)]
pub fn len(&self) -> usize {
self.futures.len()
}
/// Push a future for processing.
pub fn push(&mut self, future: F) {
self.futures.push(future);
if let Some(waker) = self.waker.take() {
waker.wake();
}
}
}
impl<F: Future> Stream for FuturesStream<F> {
type Item = <F as Future>::Output;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let Poll::Ready(Some(result)) = self.futures.poll_next_unpin(cx) else {
// We must save the current waker to wake up the task when new futures are inserted.
//
// Otherwise, simply returning `Poll::Pending` here would cause the task to never be
// woken up again.
//
// We were previously relying on some other task from the `loop tokio::select!` to
// finish.
self.waker = Some(cx.waker().clone());
return Poll::Pending;
};
Poll::Ready(Some(result))
}
}