1use std::{
2 collections::HashMap,
3 sync::{Arc, Mutex, Weak},
4 task::{Context, Poll, Wake, Waker},
5};
6
7use wasi::io::poll::Pollable;
8
9pub trait PollableRegistry: Clone + Unpin {
13 type RegisteredPollable: Unpin;
14
15 fn register_pollable(&self, cx: &mut Context, pollable: Pollable) -> Self::RegisteredPollable;
19
20 fn poll(&self) -> bool;
22
23 fn block_on<T>(&self, fut: impl std::future::Future<Output = T>) -> Result<T, Stalled> {
27 let mut fut = std::pin::pin!(fut);
28 let waker = noop_waker();
29 let mut cx = Context::from_waker(&waker);
30 loop {
31 if let Poll::Ready(val) = fut.as_mut().poll(&mut cx) {
32 return Ok(val);
33 }
34 if !self.poll() {
35 return Err(Stalled);
36 }
37 }
38 }
39}
40
41#[derive(Default)]
42pub struct Poller {
43 entries: Arc<Mutex<HashMap<u32, Entry>>>,
44}
45
46struct Entry {
47 pollable: Weak<Pollable>,
48 waker: Waker,
49}
50
51impl PollableRegistry for Poller {
52 type RegisteredPollable = Arc<Pollable>;
53
54 fn register_pollable(&self, cx: &mut Context, pollable: Pollable) -> Self::RegisteredPollable {
55 let handle = pollable.handle();
56 let pollable = Arc::new(pollable);
57 let entry = Entry {
58 pollable: Arc::downgrade(&pollable),
59 waker: cx.waker().clone(),
60 };
61 self.entries.lock().unwrap().insert(handle, entry);
62 pollable
63 }
64
65 fn poll(&self) -> bool {
66 let mut entries = self.entries.lock().unwrap();
67
68 entries.retain(|_, entry| entry.pollable.strong_count() > 0);
70
71 if entries.is_empty() {
72 return false;
73 }
74
75 let pollables = entries
77 .values()
78 .filter_map(|entry| entry.pollable.upgrade())
79 .collect::<Vec<_>>();
80 let pollable_refs = pollables.iter().map(|p| p.as_ref()).collect::<Vec<_>>();
81 let ready_idxs = wasi::io::poll::poll(&pollable_refs);
82
83 for idx in ready_idxs {
85 let idx: usize = idx.try_into().unwrap();
86 let handle = pollables[idx].handle();
87 let entry = entries.remove(&handle).unwrap();
88 entry.waker.wake();
89 }
90 true
91 }
92}
93
94impl Clone for Poller {
95 fn clone(&self) -> Self {
96 Self {
97 entries: self.entries.clone(),
98 }
99 }
100}
101
102pub fn noop_waker() -> Waker {
103 struct NoopWaker;
104 impl Wake for NoopWaker {
105 fn wake(self: Arc<Self>) {}
106 }
107 Arc::new(NoopWaker).into()
108}
109
110#[derive(Debug)]
111pub struct Stalled;
112
113impl std::fmt::Display for Stalled {
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 write!(f, "future stalled with no remaining pollables")
116 }
117}
118
119impl std::error::Error for Stalled {}
120
121pub trait WasiSubscribe: Unpin {
122 fn subscribe(&self) -> wasi::io::poll::Pollable;
123}
124
125macro_rules! impl_subscribe {
126 ($($ty:ty),+) => {
127 $(
128 impl WasiSubscribe for $ty {
129 fn subscribe(&self) -> wasi::io::poll::Pollable {
130 self.subscribe()
131 }
132 }
133 )+
134 }
135}
136mod subscribe_impls {
137 use super::WasiSubscribe;
138 use wasi::http::types::*;
139 impl_subscribe!(
140 FutureTrailers,
141 InputStream,
142 OutputStream,
143 FutureIncomingResponse
144 );
145}