1use std::{
4 fmt,
5 marker::PhantomData,
6 ops::{ControlFlow, Not},
7 pin::Pin,
8 sync::Arc,
9 task::{Context, Poll},
10};
11
12use futures::Stream;
13
14use crate::{
15 list::{
16 IntrusiveList,
17 cursor::{Cursor, CursorMut},
18 },
19 mpsc,
20 pollable::{PollStrategy, PollWith},
21 selector::iter::{ExtractIf, IntoIter, Iter, IterMut},
22 task::Task,
23};
24
25pub use borrowed::{Borrowed, BorrowedMut};
26pub use id::Id;
27pub use removed::Removed;
28
29mod borrowed;
30mod id;
31pub mod iter;
32mod removed;
33
34pub struct Selector<S: PollStrategy> {
78 ready_rx: mpsc::Receiver<Task<S::Pollable>>,
80 list: IntrusiveList<Task<S::Pollable>>,
82 _phantom: PhantomData<fn() -> S>,
84}
85
86impl<S: PollStrategy> Selector<S> {
87 pub fn push(&mut self, pollable: S::Pollable) {
91 let node = self
92 .list
93 .insert(Task::empty(self.ready_rx.weak_sender()), pollable);
94 self.ready_rx.send(node);
95 }
96
97 pub fn push_with_id(&mut self, pollable: S::Pollable) -> Id {
101 self.push_with_id_cyclic(|_| pollable)
102 }
103
104 pub fn push_with_id_cyclic<F>(&mut self, with: F) -> Id
110 where
111 F: FnOnce(Id) -> S::Pollable,
112 {
113 let node = self
114 .list
115 .insert_with(Task::empty(self.ready_rx.weak_sender()), |task| {
116 let id = Id::new(Arc::downgrade(task), self.ready_rx.weak_sender());
117 with(id)
118 });
119 let id = Id::new(Arc::downgrade(&node), node.ready_tx().clone());
120 self.ready_rx.send(node);
121 id
122 }
123
124 pub fn is_empty(&self) -> bool {
128 self.list.is_empty()
129 }
130
131 pub fn len(&self) -> usize {
135 self.list.len()
136 }
137
138 pub fn wake_all(&self) {
146 self.iter().for_each(|borrowed| borrowed.wake());
147 }
148
149 pub fn iter(&self) -> Iter<'_, S::Pollable> {
153 Iter {
154 cursor: Cursor::new(&self.list),
155 queue: &self.ready_rx,
156 }
157 }
158
159 pub fn iter_mut(&mut self) -> IterMut<'_, S::Pollable> {
165 IterMut {
166 cursor: CursorMut::new(&mut self.list),
167 queue: &self.ready_rx,
168 }
169 }
170
171 #[must_use = "ExtractIf does not remove any elements unless consumed"]
180 pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, S::Pollable, F>
181 where
182 F: FnMut(Pin<&mut S::Pollable>) -> bool,
183 {
184 ExtractIf {
185 cursor: CursorMut::new(&mut self.list),
186 pred,
187 }
188 }
189
190 pub fn get(&self, id: &Id) -> Option<Borrowed<'_, S::Pollable>> {
197 if std::ptr::addr_eq(self.ready_rx.as_ptr(), id.sender_ptr()).not() {
198 return None;
199 }
200 let node = unsafe {
201 let task = id.task::<S::Pollable>()?;
204 self.list.get(&task)
205 }?;
206 Some(Borrowed {
207 node,
208 queue: &self.ready_rx,
209 })
210 }
211
212 pub fn get_mut(&mut self, id: &Id) -> Option<BorrowedMut<'_, S::Pollable>> {
221 if std::ptr::addr_eq(self.ready_rx.as_ptr(), id.sender_ptr()).not() {
222 return None;
223 }
224 let node = unsafe {
225 let task = id.task::<S::Pollable>()?;
228 self.list.get_mut(&task)
229 }?;
230 Some(BorrowedMut {
231 node,
232 queue: &self.ready_rx,
233 })
234 }
235
236 pub fn remove(&mut self, id: &Id) -> Option<Removed<S::Pollable>> {
245 if std::ptr::addr_eq(self.ready_rx.as_ptr(), id.sender_ptr()).not() {
246 return None;
247 }
248 let removed = unsafe {
249 let task = id.task::<S::Pollable>()?;
252 self.list.remove(&task)?
253 };
254 Some(Removed(removed))
255 }
256
257 pub fn poll_next_with_ext<'a, E, EMut>(
265 &mut self,
266 ext: &'a E,
267 ext_mut: &mut EMut,
268 cx: &mut Context<'_>,
269 ) -> Poll<Option<<S as PollWith<'a, E, EMut>>::Progress>>
270 where
271 S: PollWith<'a, E, EMut>,
272 E: ?Sized,
273 EMut: ?Sized,
274 {
275 let marker = self.ready_rx.register(cx.waker());
276 if marker.is_null() {
277 return if self.list.is_empty() {
278 Poll::Ready(None)
279 } else {
280 Poll::Pending
281 };
282 }
283
284 let mut polled_all_queue = false;
285 while polled_all_queue.not() {
286 let task = match self.ready_rx.recv() {
287 Some(task) => {
288 polled_all_queue = std::ptr::eq(task.as_ref(), marker);
289 task
290 }
291 None if self.list.is_empty() => return Poll::Ready(None),
292 None => return Poll::Pending,
293 };
294
295 let mut guard = {
296 let guard = unsafe {
297 self.list.access(&task)
300 };
301 match guard {
302 Some(guard) => guard,
303 None => continue,
304 }
305 };
306 let waker = task.borrow_waker();
307 let mut cx = Context::from_waker(&waker);
308 let result = S::poll_progress(guard.get(), ext, ext_mut, &mut cx);
309 match result {
310 Poll::Ready(ControlFlow::Continue(item)) => {
311 guard.forget();
312 self.ready_rx.send(task);
313 return Poll::Ready(Some(item));
314 }
315 Poll::Ready(ControlFlow::Break(Some(item))) => return Poll::Ready(Some(item)),
316 Poll::Ready(ControlFlow::Break(None)) => {}
317 Poll::Pending => guard.forget(),
318 }
319 }
320
321 if self.list.is_empty() {
322 Poll::Ready(None)
323 } else {
324 Poll::Pending
325 }
326 }
327
328 pub async fn next_with_ext<'a, E, EMut>(
330 &mut self,
331 ext: &'a E,
332 ext_mut: &mut EMut,
333 ) -> Option<S::Progress>
334 where
335 S: PollWith<'a, E, EMut>,
336 E: ?Sized,
337 EMut: ?Sized,
338 {
339 futures::future::poll_fn(|cx| self.poll_next_with_ext(ext, ext_mut, cx)).await
340 }
341}
342
343impl<S: PollWith<'static, (), ()>> Stream for Selector<S> {
344 type Item = S::Progress;
345
346 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
347 let this = unsafe {
348 self.get_unchecked_mut()
350 };
351 this.poll_next_with_ext(&(), &mut (), cx)
352 }
353}
354
355impl<S: PollStrategy> Default for Selector<S> {
356 fn default() -> Self {
357 Self {
358 ready_rx: mpsc::Receiver::new(Task::empty),
359 list: Default::default(),
360 _phantom: Default::default(),
361 }
362 }
363}
364
365impl<S: PollStrategy> fmt::Debug for Selector<S> {
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 f.debug_struct("Selector")
368 .field("len", &self.len())
369 .finish()
370 }
371}
372
373impl<S: PollStrategy> Extend<S::Pollable> for Selector<S> {
374 fn extend<T: IntoIterator<Item = S::Pollable>>(&mut self, iter: T) {
375 for pollable in iter {
376 self.push(pollable);
377 }
378 }
379}
380
381impl<S: PollStrategy> FromIterator<S::Pollable> for Selector<S> {
382 fn from_iter<T: IntoIterator<Item = S::Pollable>>(iter: T) -> Self {
383 let mut this = Self::default();
384 this.extend(iter);
385 this
386 }
387}
388
389impl<S: PollStrategy> IntoIterator for Selector<S> {
390 type IntoIter = IntoIter<S::Pollable>;
391 type Item = Removed<S::Pollable>;
392
393 fn into_iter(self) -> Self::IntoIter {
394 IntoIter(self.list)
395 }
396}
397
398#[cfg(test)]
399mod test {
400 use std::{
401 ops::Not,
402 panic::{AssertUnwindSafe, catch_unwind},
403 pin::Pin,
404 sync::Arc,
405 task::{Context, Poll, Waker},
406 };
407
408 use futures::{FutureExt, StreamExt, channel::oneshot, task::AtomicWaker};
409 use rstest::rstest;
410
411 use crate::{pollable::PollAsFuture, selector::Selector};
412
413 #[tokio::test]
414 async fn basic() {
415 let (tx, rx) = oneshot::channel::<()>();
416 let mut selector = Selector::<PollAsFuture<_>>::default();
417 selector.push(rx);
418 assert!(selector.next().now_or_never().is_none());
419 assert_eq!(selector.len(), 1);
420 tx.send(()).unwrap();
421 assert!(selector.next().await.is_some());
422 assert_eq!(selector.len(), 0);
423 }
424
425 #[rstest]
428 #[tokio::test]
429 async fn task_yield_is_respected(#[values(1, 4, 8)] futures: usize) {
430 struct Fut {
431 polled: bool,
432 }
433
434 impl Future for Fut {
435 type Output = ();
436
437 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
438 let this = self.get_mut();
439 if this.polled.not() {
440 this.polled = true;
441 cx.waker().wake_by_ref();
442 Poll::Pending
443 } else {
444 Poll::Ready(())
445 }
446 }
447 }
448
449 let mut selector = Selector::<PollAsFuture<_>>::default();
450 for _ in 0..futures {
451 selector.push(Fut { polled: false });
452 }
453
454 assert!(
455 selector
456 .poll_next_with_ext(&(), &mut (), &mut Context::from_waker(Waker::noop()))
457 .is_pending()
458 );
459 for fut in selector.iter() {
460 assert!(fut.polled);
461 }
462
463 for _ in 0..futures {
464 assert_eq!(
465 selector.poll_next_with_ext(&(), &mut (), &mut Context::from_waker(Waker::noop())),
466 Poll::Ready(Some(())),
467 );
468 }
469 }
470
471 #[test]
472 fn stale_wakeups_on_removed_tasks_still_report_empty_selector() {
473 struct StoreWaker(Arc<AtomicWaker>);
474
475 impl Future for StoreWaker {
476 type Output = usize;
477
478 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
479 self.0.register(cx.waker());
480 Poll::Pending
481 }
482 }
483
484 let slot = Arc::new(AtomicWaker::new());
485 let mut selector = Selector::<PollAsFuture<_>>::default();
486 let id = selector.push_with_id(StoreWaker(slot.clone()).boxed());
487 let mut cx = Context::from_waker(Waker::noop());
488
489 assert!(
490 selector
491 .poll_next_with_ext(&(), &mut (), &mut cx)
492 .is_pending()
493 );
494 let waker = slot.take().unwrap();
495 let _ = selector.remove(&id).unwrap();
496 assert!(selector.is_empty());
497
498 for _ in 0..3 {
499 waker.wake_by_ref();
500 assert_eq!(
501 selector.poll_next_with_ext(&(), &mut (), &mut cx),
502 Poll::Ready(None)
503 );
504 }
505
506 selector.push(std::future::ready(7).boxed());
507 assert_eq!(
508 selector.poll_next_with_ext(&(), &mut (), &mut cx),
509 Poll::Ready(Some(7))
510 );
511 assert_eq!(
512 selector.poll_next_with_ext(&(), &mut (), &mut cx),
513 Poll::Ready(None)
514 );
515 }
516
517 #[test]
518 fn panicking_task_is_removed_and_selector_remains_valid() {
519 struct PanicOnPoll {
520 _shared: Arc<()>,
521 }
522
523 impl Future for PanicOnPoll {
524 type Output = usize;
525
526 fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
527 panic!("boom");
528 }
529 }
530
531 let drops = Arc::new(());
532 let drops_weak = Arc::downgrade(&drops);
533 let mut selector = Selector::<PollAsFuture<_>>::default();
534 selector.push(PanicOnPoll { _shared: drops }.boxed());
535
536 let mut cx = Context::from_waker(Waker::noop());
537 let result = catch_unwind(AssertUnwindSafe(|| {
538 selector.poll_next_with_ext(&(), &mut (), &mut cx)
539 }));
540
541 assert!(result.is_err());
542 assert!(selector.is_empty());
543 assert_eq!(selector.len(), 0);
544 assert!(drops_weak.upgrade().is_none());
545
546 selector.push(std::future::ready(11).boxed());
547 assert_eq!(
548 selector.poll_next_with_ext(&(), &mut (), &mut cx),
549 Poll::Ready(Some(11))
550 );
551 assert_eq!(
552 selector.poll_next_with_ext(&(), &mut (), &mut cx),
553 Poll::Ready(None)
554 );
555 }
556}