1use core::future::Future;
16use core::pin::Pin;
17use core::ptr::NonNull;
18use core::task::{Context, Poll, Waker};
19use std::fmt;
20use std::sync::atomic::{AtomicBool, Ordering};
21use std::sync::{Arc, Weak};
22use std::task::Wake;
23
24use crate::rt::inbox::{Inbox, Link, Linked, Pop};
25use crate::sync::atomic_waker::AtomicWaker;
26use crate::task::{AbortHandle, Id, Join, JoinError, Task};
27
28struct Shared {
30 ready: Inbox<Queued>,
32 awaiter: AtomicWaker,
34}
35
36struct SlotWake {
38 link: Link,
39 shared: Weak<Shared>,
40 slot: usize,
41 queued: AtomicBool,
42}
43
44impl Wake for SlotWake {
45 fn wake(self: Arc<Self>) {
46 self.wake_by_ref();
47 }
48
49 fn wake_by_ref(self: &Arc<Self>) {
50 if !self.queued.swap(true, Ordering::AcqRel)
51 && let Some(shared) = self.shared.upgrade()
52 {
53 shared.ready.push(Queued(Arc::clone(self)));
54 shared.awaiter.wake();
55 }
56 }
57}
58
59struct Queued(Arc<SlotWake>);
61
62unsafe impl Linked for Queued {
65 fn into_link(self) -> NonNull<Link> {
66 let wake = Arc::into_raw(self.0);
67 unsafe { NonNull::new_unchecked(core::ptr::addr_of!((*wake).link).cast_mut()) }
69 }
70
71 unsafe fn from_link(link: NonNull<Link>) -> Self {
72 let offset = core::mem::offset_of!(SlotWake, link);
73 Self(unsafe { Arc::from_raw(link.as_ptr().cast::<u8>().sub(offset).cast::<SlotWake>()) })
76 }
77}
78
79struct Slot<T> {
81 wake: Arc<SlotWake>,
82 waker: Waker,
83 member: Option<Member<T>>,
84}
85
86struct Member<T> {
87 join: Join<T>,
88 abort: AbortHandle,
89}
90
91pub struct JoinSet<T> {
110 slots: Vec<Slot<T>>,
111 free: Vec<usize>,
112 len: usize,
113 shared: Arc<Shared>,
114}
115
116impl<T> Default for JoinSet<T> {
117 fn default() -> Self {
118 Self::new()
119 }
120}
121
122impl<T> JoinSet<T> {
123 pub fn new() -> Self {
125 Self {
126 slots: Vec::new(),
127 free: Vec::new(),
128 len: 0,
129 shared: Arc::new(Shared {
130 ready: Inbox::new(),
131 awaiter: AtomicWaker::new(),
132 }),
133 }
134 }
135
136 pub fn len(&self) -> usize {
138 self.len
139 }
140
141 pub fn is_empty(&self) -> bool {
143 self.len == 0
144 }
145
146 pub fn insert(&mut self, task: Task<T>) -> AbortHandle {
148 let abort = task.abort_handle();
149 let member = Member {
150 join: task.join(),
151 abort: abort.clone(),
152 };
153 let slot = match self.free.pop() {
154 Some(slot) => slot,
155 None => {
156 let slot = self.slots.len();
157 let wake = Arc::new(SlotWake {
158 link: Link::new(),
159 shared: Arc::downgrade(&self.shared),
160 slot,
161 queued: AtomicBool::new(false),
162 });
163 self.slots.push(Slot {
164 waker: Waker::from(Arc::clone(&wake)),
165 wake,
166 member: None,
167 });
168 slot
169 }
170 };
171 let place = &mut self.slots[slot];
172 place.member = Some(member);
173 self.len += 1;
174 if !place.wake.queued.swap(true, Ordering::AcqRel) {
177 self.shared.ready.push(Queued(Arc::clone(&place.wake)));
178 }
179 abort
180 }
181
182 pub fn spawn<F>(&mut self, future: F) -> AbortHandle
184 where
185 F: Future<Output = T> + Send + 'static,
186 T: Send + 'static,
187 {
188 self.insert(crate::task::spawn(future))
189 }
190
191 pub fn spawn_local<F>(&mut self, future: F) -> AbortHandle
194 where
195 F: Future<Output = T> + 'static,
196 T: 'static,
197 {
198 self.insert(crate::task::spawn_local(future))
199 }
200
201 pub fn spawn_blocking<F>(&mut self, f: F) -> AbortHandle
203 where
204 F: FnOnce() -> T + Send + 'static,
205 T: Send + 'static,
206 {
207 self.insert(crate::task::spawn_blocking(f))
208 }
209
210 pub fn spawn_on<F>(&mut self, future: F, handle: &crate::runtime::RuntimeHandle) -> AbortHandle
212 where
213 F: Future<Output = T> + Send + 'static,
214 T: Send + 'static,
215 {
216 self.insert(handle.spawn(future))
217 }
218
219 pub async fn join_next(&mut self) -> Option<Result<T, JoinError>> {
222 core::future::poll_fn(|cx| self.poll_join_next(cx))
223 .await
224 .map(|out| out.map(|(_, value)| value))
225 }
226
227 pub async fn join_next_with_id(&mut self) -> Option<Result<(Id, T), JoinError>> {
229 core::future::poll_fn(|cx| self.poll_join_next(cx)).await
230 }
231
232 pub fn try_join_next(&mut self) -> Option<Result<T, JoinError>> {
235 let mut cx = Context::from_waker(Waker::noop());
236 match self.poll_join_next(&mut cx) {
237 Poll::Ready(Some(out)) => Some(out.map(|(_, value)| value)),
238 _ => None,
239 }
240 }
241
242 pub fn poll_join_next(
244 &mut self,
245 cx: &mut Context<'_>,
246 ) -> Poll<Option<Result<(Id, T), JoinError>>> {
247 if self.len == 0 {
248 return Poll::Ready(None);
249 }
250 self.shared.awaiter.register(cx.waker());
251 for _ in 0..self.len {
254 let wake = match unsafe { self.shared.ready.pop() } {
256 Pop::Item(Queued(wake)) => wake,
257 Pop::Empty | Pop::Busy => return Poll::Pending,
259 };
260 wake.queued.store(false, Ordering::Release);
261 let slot = wake.slot;
262 let Some(place) = self
264 .slots
265 .get_mut(slot)
266 .filter(|p| Arc::ptr_eq(&p.wake, &wake))
267 else {
268 continue;
269 };
270 let Some(member) = place.member.as_mut() else {
271 continue;
272 };
273 let mut member_cx = Context::from_waker(&place.waker);
274 if let Poll::Ready(out) = Pin::new(&mut member.join).poll(&mut member_cx) {
275 let id = member.abort.id();
276 place.member = None;
277 self.free.push(slot);
278 self.len -= 1;
279 return Poll::Ready(Some(out.map(|value| (id, value))));
280 }
281 }
282 cx.waker().wake_by_ref();
285 Poll::Pending
286 }
287
288 #[expect(clippy::panic, reason = "documented under `# Panics`")]
294 pub async fn join_all(mut self) -> Vec<T> {
295 let mut outputs = Vec::with_capacity(self.len);
296 while let Some(out) = self.join_next().await {
297 match out {
298 Ok(value) => outputs.push(value),
299 Err(error) => match error.try_into_panic() {
300 Ok(panic) => std::panic::resume_unwind(panic),
301 Err(error) => panic!("`JoinSet::join_all`: {error}"),
302 },
303 }
304 }
305 outputs
306 }
307
308 pub fn abort_all(&mut self) {
311 for member in self.slots.iter().filter_map(|p| p.member.as_ref()) {
312 member.abort.abort();
313 }
314 }
315
316 pub fn detach_all(&mut self) {
319 for place in self.slots.drain(..) {
320 if let Some(member) = place.member {
321 member.join.detach();
322 }
323 }
324 self.free.clear();
325 self.len = 0;
326 unsafe { self.shared.ready.drain(drop) };
328 }
329
330 pub async fn shutdown(&mut self) {
332 self.abort_all();
333 while self.join_next().await.is_some() {}
334 }
335}
336
337impl<T, F> FromIterator<F> for JoinSet<T>
338where
339 F: Future<Output = T> + Send + 'static,
340 T: Send + 'static,
341{
342 fn from_iter<I: IntoIterator<Item = F>>(iter: I) -> Self {
343 let mut set = Self::new();
344 for future in iter {
345 set.spawn(future);
346 }
347 set
348 }
349}
350
351impl<T, F> Extend<F> for JoinSet<T>
352where
353 F: Future<Output = T> + Send + 'static,
354 T: Send + 'static,
355{
356 fn extend<I: IntoIterator<Item = F>>(&mut self, iter: I) {
357 for future in iter {
358 self.spawn(future);
359 }
360 }
361}
362
363impl<T> fmt::Debug for JoinSet<T> {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 f.debug_struct("JoinSet").field("len", &self.len).finish()
366 }
367}