• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Need non-snake case so the macro can re-use type names for variables.
6 #![allow(non_snake_case)]
7 
8 use std::future::Future;
9 use std::pin::Pin;
10 use std::task::{Context, Poll};
11 
12 use futures::future::{maybe_done, FutureExt, MaybeDone};
13 
14 pub enum SelectResult<F: Future> {
15     Pending(F),
16     Finished(F::Output),
17 }
18 
19 // Macro-generate future combinators to allow for running different numbers of top-level futures in
20 // this FutureList. Generates the implementation of `FutureList` for the select types. For an
21 // explicit example this is modeled after, see `UnitFutures`.
22 macro_rules! generate {
23     ($(
24         $(#[$doc:meta])*
25         ($Select:ident, <$($Fut:ident),*>),
26     )*) => ($(
27         #[must_use = "Combinations of futures don't do anything unless run in an executor."]
28         paste::item! {
29             pub(crate) struct $Select<$($Fut: Future + Unpin),*> {
30                 $($Fut: MaybeDone<$Fut>,)*
31             }
32         }
33 
34         impl<$($Fut: Future + Unpin),*> $Select<$($Fut),*> {
35             paste::item! {
36                 pub(crate) fn new($($Fut: $Fut),*) -> $Select<$($Fut),*> {
37                     $Select {
38                         $($Fut: maybe_done($Fut),)*
39                     }
40                 }
41             }
42         }
43 
44         impl<$($Fut: Future + Unpin),*> Future for $Select<$($Fut),*> {
45             type Output = ($(SelectResult<$Fut>),*);
46 
47             fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
48                 let mut complete = false;
49                 $(
50                     let $Fut = Pin::new(&mut self.$Fut);
51                     // The future impls `Unpin`, use `poll_unpin` to avoid wrapping it in
52                     // `Pin` to call `poll`.
53                     complete |= self.$Fut.poll_unpin(cx).is_ready();
54                 )*
55 
56                 if complete {
57                     Poll::Ready(($(
58                         match std::mem::replace(&mut self.$Fut, MaybeDone::Gone) {
59                             MaybeDone::Future(f) => SelectResult::Pending(f),
60                             MaybeDone::Done(o) => SelectResult::Finished(o),
61                             MaybeDone::Gone => unreachable!(),
62                         }
63                     ), *))
64                 } else {
65                     Poll::Pending
66                 }
67             }
68         }
69     )*)
70 }
71 
72 generate! {
73     /// _Future for the [`select2`] function.
74     (Select2, <_Fut1, _Fut2>),
75 
76     /// _Future for the [`select3`] function.
77     (Select3, <_Fut1, _Fut2, _Fut3>),
78 
79     /// _Future for the [`select4`] function.
80     (Select4, <_Fut1, _Fut2, _Fut3, _Fut4>),
81 
82     /// _Future for the [`select5`] function.
83     (Select5, <_Fut1, _Fut2, _Fut3, _Fut4, _Fut5>),
84 
85     /// _Future for the [`select6`] function.
86     (Select6, <_Fut1, _Fut2, _Fut3, _Fut4, _Fut5, _Fut6>),
87 }
88