1use std::any::Any;
2use std::future::Future;
3use std::hash::Hash;
4use std::pin::Pin;
5use std::task::{Context, Poll, Waker};
6use std::time::Duration;
7use std::{future, mem};
8
9use futures_util::stream::FuturesUnordered;
10use futures_util::{FutureExt, StreamExt};
11
12use crate::{AnyFuture, BoxFuture, Delay, PushError, Timeout};
13
14pub struct FuturesMap<ID, O> {
18 make_delay: Box<dyn Fn() -> Delay + Send + Sync>,
19 capacity: usize,
20 inner: FuturesUnordered<TaggedFuture<ID, TimeoutFuture<BoxFuture<O>>>>,
21 empty_waker: Option<Waker>,
22 full_waker: Option<Waker>,
23}
24
25impl<ID, O> FuturesMap<ID, O> {
26 pub fn new(make_delay: impl Fn() -> Delay + Send + Sync + 'static, capacity: usize) -> Self {
27 Self {
28 make_delay: Box::new(make_delay),
29 capacity,
30 inner: Default::default(),
31 empty_waker: None,
32 full_waker: None,
33 }
34 }
35}
36
37impl<ID, O> FuturesMap<ID, O>
38where
39 ID: Clone + Hash + Eq + Send + Unpin + 'static,
40 O: 'static,
41{
42 pub fn try_push<F>(&mut self, future_id: ID, future: F) -> Result<(), PushError<BoxFuture<O>>>
50 where
51 F: AnyFuture<Output = O>,
52 {
53 if self.inner.len() >= self.capacity {
54 return Err(PushError::BeyondCapacity(Box::pin(future)));
55 }
56
57 if let Some(waker) = self.empty_waker.take() {
58 waker.wake();
59 }
60
61 let old = self.remove(future_id.clone());
62 self.inner.push(TaggedFuture {
63 tag: future_id,
64 inner: TimeoutFuture {
65 inner: Box::pin(future),
66 timeout: (self.make_delay)(),
67 cancelled: false,
68 },
69 });
70 match old {
71 None => Ok(()),
72 Some(old) => Err(PushError::Replaced(old)),
73 }
74 }
75
76 pub fn remove(&mut self, id: ID) -> Option<BoxFuture<O>> {
77 let tagged = self.inner.iter_mut().find(|s| s.tag == id)?;
78
79 let inner = mem::replace(&mut tagged.inner.inner, Box::pin(future::pending()));
80 tagged.inner.cancelled = true;
81
82 Some(inner)
83 }
84
85 pub fn contains(&self, id: ID) -> bool {
86 self.inner.iter().any(|f| f.tag == id && !f.inner.cancelled)
87 }
88
89 pub fn len(&self) -> usize {
90 self.inner.len()
91 }
92
93 pub fn is_empty(&self) -> bool {
94 self.inner.is_empty()
95 }
96
97 #[allow(unknown_lints, clippy::needless_pass_by_ref_mut)] pub fn poll_ready_unpin(&mut self, cx: &mut Context<'_>) -> Poll<()> {
99 if self.inner.len() < self.capacity {
100 return Poll::Ready(());
101 }
102
103 self.full_waker = Some(cx.waker().clone());
104
105 Poll::Pending
106 }
107
108 pub fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<(ID, Result<O, Timeout>)> {
109 loop {
110 let maybe_result = futures_util::ready!(self.inner.poll_next_unpin(cx));
111
112 match maybe_result {
113 None => {
114 self.empty_waker = Some(cx.waker().clone());
115 return Poll::Pending;
116 }
117 Some((id, Ok(output))) => return Poll::Ready((id, Ok(output))),
118 Some((id, Err(TimeoutError::Timeout(dur)))) => {
119 return Poll::Ready((id, Err(Timeout::new(dur))))
120 }
121 Some((_, Err(TimeoutError::Cancelled))) => continue,
122 }
123 }
124 }
125
126 pub fn iter_of_type<T>(&self) -> impl Iterator<Item = (&ID, Pin<&T>)>
131 where
132 T: 'static,
133 {
134 self.inner.iter().filter_map(|a| {
135 let pointer = a.inner.inner.as_ref().get_ref();
136
137 let any = pointer as &(dyn Any + Send);
138 let inner = any.downcast_ref::<T>()?;
140
141 let pinned = unsafe { Pin::new_unchecked(inner) };
144
145 Some((&a.tag, pinned))
146 })
147 }
148
149 pub fn iter_mut_of_type<T>(&mut self) -> impl Iterator<Item = (&ID, Pin<&mut T>)>
155 where
156 T: 'static,
157 {
158 self.inner.iter_mut().filter_map(|a| {
159 let pin = a.inner.inner.as_mut();
160
161 let pointer = unsafe { Pin::into_inner_unchecked(pin) };
163 let any = pointer as &mut (dyn Any + Send);
164 let inner = any.downcast_mut::<T>()?;
165
166 let pinned = unsafe { Pin::new_unchecked(inner) };
168
169 Some((&a.tag, pinned))
170 })
171 }
172}
173
174struct TimeoutFuture<F> {
175 inner: F,
176 timeout: Delay,
177
178 cancelled: bool,
179}
180
181impl<F> Future for TimeoutFuture<F>
182where
183 F: Future + Unpin,
184{
185 type Output = Result<F::Output, TimeoutError>;
186
187 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
188 if self.cancelled {
189 return Poll::Ready(Err(TimeoutError::Cancelled));
190 }
191
192 if let Poll::Ready(duration) = self.timeout.poll_unpin(cx) {
193 return Poll::Ready(Err(TimeoutError::Timeout(duration)));
194 }
195
196 self.inner.poll_unpin(cx).map(Ok)
197 }
198}
199
200enum TimeoutError {
201 Timeout(Duration),
202 Cancelled,
203}
204
205struct TaggedFuture<T, F> {
206 tag: T,
207 inner: F,
208}
209
210impl<T, F> Future for TaggedFuture<T, F>
211where
212 T: Clone + Unpin,
213 F: Future + Unpin,
214{
215 type Output = (T, F::Output);
216
217 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
218 let output = futures_util::ready!(self.inner.poll_unpin(cx));
219
220 Poll::Ready((self.tag.clone(), output))
221 }
222}
223
224#[cfg(all(test, feature = "futures-timer"))]
225mod tests {
226 use futures::channel::oneshot;
227 use futures_util::task::noop_waker_ref;
228 use std::future::{pending, poll_fn, ready};
229 use std::pin::Pin;
230 use std::time::Instant;
231
232 use super::*;
233
234 #[test]
235 fn cannot_push_more_than_capacity_tasks() {
236 let mut futures = FuturesMap::new(|| Delay::futures_timer(Duration::from_secs(10)), 1);
237
238 assert!(futures.try_push("ID_1", ready(())).is_ok());
239 matches!(
240 futures.try_push("ID_2", ready(())),
241 Err(PushError::BeyondCapacity(_))
242 );
243 }
244
245 #[test]
246 fn cannot_push_the_same_id_few_times() {
247 let mut futures = FuturesMap::new(|| Delay::futures_timer(Duration::from_secs(10)), 5);
248
249 assert!(futures.try_push("ID", ready(())).is_ok());
250 matches!(
251 futures.try_push("ID", ready(())),
252 Err(PushError::Replaced(_))
253 );
254 }
255
256 #[tokio::test]
257 async fn futures_timeout() {
258 let mut futures = FuturesMap::new(|| Delay::futures_timer(Duration::from_millis(100)), 1);
259
260 let _ = futures.try_push("ID", pending::<()>());
261 futures_timer::Delay::new(Duration::from_millis(150)).await;
262 let (_, result) = poll_fn(|cx| futures.poll_unpin(cx)).await;
263
264 assert!(result.is_err())
265 }
266
267 #[test]
268 fn resources_of_removed_future_are_cleaned_up() {
269 let mut futures = FuturesMap::new(|| Delay::futures_timer(Duration::from_millis(100)), 1);
270
271 let _ = futures.try_push("ID", pending::<()>());
272 futures.remove("ID");
273
274 let poll = futures.poll_unpin(&mut Context::from_waker(noop_waker_ref()));
275 assert!(poll.is_pending());
276
277 assert_eq!(futures.len(), 0);
278 }
279
280 #[tokio::test]
281 async fn replaced_pending_future_is_polled() {
282 let mut streams = FuturesMap::new(|| Delay::futures_timer(Duration::from_millis(100)), 3);
283
284 let (_tx1, rx1) = oneshot::channel();
285 let (tx2, rx2) = oneshot::channel();
286
287 let _ = streams.try_push("ID1", rx1);
288 let _ = streams.try_push("ID2", rx2);
289
290 let _ = tx2.send(2);
291 let (id, res) = poll_fn(|cx| streams.poll_unpin(cx)).await;
292 assert_eq!(id, "ID2");
293 assert_eq!(res.unwrap().unwrap(), 2);
294
295 let (new_tx1, new_rx1) = oneshot::channel();
296 let replaced = streams.try_push("ID1", new_rx1);
297 assert!(matches!(replaced.unwrap_err(), PushError::Replaced(_)));
298
299 let _ = new_tx1.send(4);
300 let (id, res) = poll_fn(|cx| streams.poll_unpin(cx)).await;
301
302 assert_eq!(id, "ID1");
303 assert_eq!(res.unwrap().unwrap(), 4);
304 }
305
306 #[tokio::test]
309 async fn backpressure() {
310 const DELAY: Duration = Duration::from_millis(100);
311 const NUM_FUTURES: u32 = 10;
312
313 let start = Instant::now();
314 Task::new(DELAY, NUM_FUTURES, 1).await;
315 let duration = start.elapsed();
316
317 assert!(duration >= DELAY * NUM_FUTURES);
318 }
319
320 #[test]
321 fn contains() {
322 let mut futures = FuturesMap::new(|| Delay::futures_timer(Duration::from_secs(10)), 1);
323 _ = futures.try_push("ID", pending::<()>());
324 assert!(futures.contains("ID"));
325 _ = futures.remove("ID");
326 assert!(!futures.contains("ID"));
327 }
328
329 #[test]
330 fn can_iter_typed_futures() {
331 const N: usize = 10;
332 let mut futures = FuturesMap::new(|| Delay::futures_timer(Duration::from_millis(100)), N);
333 let mut sender = Vec::with_capacity(N);
334 for i in 0..N {
335 let (tx, rx) = oneshot::channel::<()>();
336 futures.try_push(format!("ID{i}"), rx).unwrap();
337 sender.push(tx);
338 }
339 assert_eq!(futures.iter_of_type::<oneshot::Receiver<()>>().count(), N);
340 for (i, (id, _)) in futures.iter_of_type::<oneshot::Receiver<()>>().enumerate() {
341 let expect_id = format!("ID{}", N - i - 1); assert_eq!(id, &expect_id);
343 }
344 assert!(!sender.iter().any(|tx| tx.is_canceled()));
345
346 for (_, mut rx) in futures.iter_mut_of_type::<oneshot::Receiver<()>>() {
347 rx.close();
348 }
349 assert!(sender.iter().all(|tx| tx.is_canceled()));
350
351 assert_eq!(futures.iter_mut_of_type::<()>().count(), 0);
353 }
354
355 struct Task {
356 future: Duration,
357 num_futures: usize,
358 num_processed: usize,
359 inner: FuturesMap<u8, ()>,
360 }
361
362 impl Task {
363 fn new(future: Duration, num_futures: u32, capacity: usize) -> Self {
364 Self {
365 future,
366 num_futures: num_futures as usize,
367 num_processed: 0,
368 inner: FuturesMap::new(|| Delay::futures_timer(Duration::from_secs(60)), capacity),
369 }
370 }
371 }
372
373 impl Future for Task {
374 type Output = ();
375
376 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
377 let this = self.get_mut();
378
379 while this.num_processed < this.num_futures {
380 if let Poll::Ready((_, result)) = this.inner.poll_unpin(cx) {
381 if result.is_err() {
382 panic!("Timeout is great than future delay")
383 }
384
385 this.num_processed += 1;
386 continue;
387 }
388
389 if let Poll::Ready(()) = this.inner.poll_ready_unpin(cx) {
390 let maybe_future = this
393 .inner
394 .try_push(1u8, futures_timer::Delay::new(this.future));
395 assert!(maybe_future.is_ok(), "we polled for readiness");
396
397 continue;
398 }
399
400 return Poll::Pending;
401 }
402
403 Poll::Ready(())
404 }
405 }
406}