1use std::future::Future;
17use std::pin::Pin;
18use std::sync::atomic::{AtomicBool, Ordering};
19use std::sync::Arc;
20use std::task::{Context, Poll, Wake, Waker};
21
22struct SlotWaker {
25 ready: AtomicBool,
26 parent: std::sync::Mutex<Option<Waker>>,
27}
28
29impl Wake for SlotWaker {
30 fn wake(self: Arc<Self>) {
31 self.wake_by_ref();
32 }
33 fn wake_by_ref(self: &Arc<Self>) {
34 self.ready.store(true, Ordering::Release);
35 if let Some(w) =
36 self.parent.lock().unwrap_or_else(std::sync::PoisonError::into_inner).as_ref()
37 {
38 w.wake_by_ref();
39 }
40 }
41}
42
43struct Slot<F: Future> {
44 fut: Option<Pin<Box<F>>>,
45 out: Option<F::Output>,
46 flag: Arc<SlotWaker>,
47 waker: Waker,
48}
49
50pub struct JoinAll<F: Future> {
52 slots: Vec<Slot<F>>,
53 pending: usize,
54}
55
56impl<F: Future> std::fmt::Debug for JoinAll<F> {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 f.debug_struct("JoinAll")
59 .field("len", &self.slots.len())
60 .field("pending", &self.pending)
61 .finish()
62 }
63}
64
65pub fn join_all<F: Future>(futures: impl IntoIterator<Item = F>) -> JoinAll<F> {
68 let slots: Vec<Slot<F>> = futures
69 .into_iter()
70 .map(|f| {
71 let flag = Arc::new(SlotWaker {
72 ready: AtomicBool::new(true),
73 parent: std::sync::Mutex::new(None),
74 });
75 let waker = Waker::from(Arc::clone(&flag));
76 Slot { fut: Some(Box::pin(f)), out: None, flag, waker }
77 })
78 .collect();
79 let pending = slots.len();
80 JoinAll { slots, pending }
81}
82
83impl<F: Future> Unpin for JoinAll<F> {}
84
85impl<F: Future> Future for JoinAll<F> {
86 type Output = Vec<F::Output>;
87
88 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
89 let this = &mut *self;
90 for slot in &mut this.slots {
91 let Some(fut) = slot.fut.as_mut() else { continue };
92 {
93 let mut parent =
94 slot.flag.parent.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
95 if parent.as_ref().is_none_or(|w| !w.will_wake(cx.waker())) {
96 *parent = Some(cx.waker().clone());
97 }
98 }
99 if !slot.flag.ready.swap(false, Ordering::AcqRel) {
100 continue;
101 }
102 if let Poll::Ready(v) = fut.as_mut().poll(&mut Context::from_waker(&slot.waker)) {
103 slot.out = Some(v);
104 slot.fut = None;
105 this.pending -= 1;
106 }
107 }
108 if this.pending == 0 {
109 Poll::Ready(this.slots.iter_mut().filter_map(|s| s.out.take()).collect())
110 } else {
111 Poll::Pending
112 }
113 }
114}
115
116pub fn spin_on<F: Future>(f: F) -> F::Output {
121 let mut cx = Context::from_waker(Waker::noop());
122 let mut f = std::pin::pin!(f);
123 loop {
124 if let Poll::Ready(v) = f.as_mut().poll(&mut cx) {
125 return v;
126 }
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use std::cell::Cell;
134
135 struct YieldN(u32, u32);
138 impl Future for YieldN {
139 type Output = u32;
140 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<u32> {
141 if self.0 == 0 {
142 Poll::Ready(self.1)
143 } else {
144 self.0 -= 1;
145 cx.waker().wake_by_ref();
146 Poll::Pending
147 }
148 }
149 }
150
151 #[test]
152 fn outputs_keep_input_order() {
153 let out = spin_on(join_all([YieldN(5, 1), YieldN(0, 2), YieldN(2, 3)]));
154 assert_eq!(out, vec![1, 2, 3]);
155 }
156
157 #[test]
158 fn empty_input_is_ready() {
159 let out: Vec<u32> = spin_on(join_all(Vec::<YieldN>::new()));
160 assert!(out.is_empty());
161 }
162
163 #[test]
164 fn futures_may_borrow_caller_state() {
165 let counter = Cell::new(0);
166 let futs = (0..4).map(|i| {
167 let c = &counter;
168 async move {
169 c.set(c.get() + i);
170 i * 2
171 }
172 });
173 let out = spin_on(join_all(futs));
174 assert_eq!(out, vec![0, 2, 4, 6]);
175 assert_eq!(counter.get(), 6);
176 }
177
178 #[test]
179 fn only_woken_futures_are_polled() {
180 struct Counted<'a>(&'a Cell<u32>, bool);
181 impl Future for Counted<'_> {
182 type Output = ();
183 fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
184 self.0.set(self.0.get() + 1);
185 if self.1 {
186 Poll::Ready(())
187 } else {
188 self.1 = true; Poll::Pending
190 }
191 }
192 }
193 let polls = Cell::new(0);
194 let mut j = join_all([Counted(&polls, false)]);
195 let waker = Waker::from(Arc::new(SlotWaker {
196 ready: AtomicBool::new(false),
197 parent: std::sync::Mutex::new(None),
198 }));
199 let mut cx = Context::from_waker(&waker);
200 assert!(Pin::new(&mut j).poll(&mut cx).is_pending());
201 assert!(Pin::new(&mut j).poll(&mut cx).is_pending());
202 assert_eq!(polls.get(), 1, "a future that did not wake is not polled again");
203 }
204}