cranpose_services/
async_io.rs1use std::{
15 collections::VecDeque,
16 future::Future,
17 pin::Pin,
18 sync::{Arc, Condvar, Mutex, PoisonError},
19 task::{Context, Poll, Waker},
20};
21
22pub const MAX_PENDING_CHUNKS: usize = 8;
26
27struct SignalState<T> {
28 value: Option<T>,
29 waker: Option<Waker>,
30 closed: bool,
31}
32
33pub struct Signal<T> {
39 state: Arc<Mutex<SignalState<T>>>,
40}
41
42impl<T> Clone for Signal<T> {
43 fn clone(&self) -> Self {
44 Self {
45 state: Arc::clone(&self.state),
46 }
47 }
48}
49
50impl<T> Default for Signal<T> {
51 fn default() -> Self {
52 Self::new()
53 }
54}
55
56impl<T> Signal<T> {
57 pub fn new() -> Self {
59 Self {
60 state: Arc::new(Mutex::new(SignalState {
61 value: None,
62 waker: None,
63 closed: false,
64 })),
65 }
66 }
67
68 pub fn set(&self, value: T) {
71 let waker = {
72 let mut state = lock(&self.state);
73 if state.closed {
74 return;
75 }
76 state.value = Some(value);
77 state.closed = true;
78 state.waker.take()
79 };
80 if let Some(waker) = waker {
81 waker.wake();
82 }
83 }
84
85 pub fn close(&self) {
87 let waker = {
88 let mut state = lock(&self.state);
89 if state.closed {
90 return;
91 }
92 state.closed = true;
93 state.waker.take()
94 };
95 if let Some(waker) = waker {
96 waker.wake();
97 }
98 }
99
100 pub fn wait(&self) -> SignalWait<T> {
102 SignalWait {
103 state: Arc::clone(&self.state),
104 }
105 }
106}
107
108pub struct SignalWait<T> {
110 state: Arc<Mutex<SignalState<T>>>,
111}
112
113impl<T> Future for SignalWait<T> {
114 type Output = Option<T>;
115
116 fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<T>> {
117 let mut state = lock(&self.state);
118 if let Some(value) = state.value.take() {
119 return Poll::Ready(Some(value));
120 }
121 if state.closed {
122 return Poll::Ready(None);
123 }
124 state.waker = Some(context.waker().clone());
125 Poll::Pending
126 }
127}
128
129struct ChunkState<E> {
130 ready: VecDeque<Vec<u8>>,
131 error: Option<E>,
132 finished: bool,
133 abandoned: bool,
134 waker: Option<Waker>,
135}
136
137struct ChunkShared<E> {
138 state: Mutex<ChunkState<E>>,
139 room: Condvar,
140}
141
142pub struct ChunkChannel<E> {
148 shared: Arc<ChunkShared<E>>,
149}
150
151impl<E> ChunkChannel<E> {
152 pub fn new() -> (Self, ChunkStream<E>) {
154 let shared = Arc::new(ChunkShared {
155 state: Mutex::new(ChunkState {
156 ready: VecDeque::new(),
157 error: None,
158 finished: false,
159 abandoned: false,
160 waker: None,
161 }),
162 room: Condvar::new(),
163 });
164 (
165 Self {
166 shared: Arc::clone(&shared),
167 },
168 ChunkStream { shared },
169 )
170 }
171
172 pub fn push(&self, chunk: Vec<u8>) -> bool {
178 let waker = {
179 let mut state = lock(&self.shared.state);
180 #[cfg(not(target_arch = "wasm32"))]
181 while state.ready.len() >= MAX_PENDING_CHUNKS && !state.abandoned && !state.finished {
182 state = self
183 .shared
184 .room
185 .wait(state)
186 .unwrap_or_else(PoisonError::into_inner);
187 }
188 if state.abandoned || state.finished {
189 return false;
190 }
191 state.ready.push_back(chunk);
192 state.waker.take()
193 };
194 if let Some(waker) = waker {
195 waker.wake();
196 }
197 true
198 }
199
200 pub fn fail(&self, error: E) {
202 self.shared.end(Some(error));
203 }
204
205 pub fn finish(&self) {
207 self.shared.end(None);
208 }
209
210 pub fn is_abandoned(&self) -> bool {
212 lock(&self.shared.state).abandoned
213 }
214}
215
216impl<E> Drop for ChunkChannel<E> {
217 fn drop(&mut self) {
218 self.finish();
219 }
220}
221
222impl<E> ChunkShared<E> {
223 fn end(&self, error: Option<E>) {
224 let waker = {
225 let mut state = lock(&self.state);
226 if state.finished {
227 return;
228 }
229 state.error = error;
230 state.finished = true;
231 state.waker.take()
232 };
233 self.room.notify_all();
234 if let Some(waker) = waker {
235 waker.wake();
236 }
237 }
238}
239
240pub struct ChunkStream<E> {
242 shared: Arc<ChunkShared<E>>,
243}
244
245impl<E> ChunkStream<E> {
246 pub fn next(&self) -> ChunkNext<'_, E> {
249 ChunkNext { stream: self }
250 }
251
252 pub fn fail(&self, error: E) {
256 self.shared.end(Some(error));
257 }
258}
259
260impl<E> Drop for ChunkStream<E> {
261 fn drop(&mut self) {
262 let mut state = lock(&self.shared.state);
263 state.abandoned = true;
264 drop(state);
265 self.shared.room.notify_all();
266 }
267}
268
269pub struct ChunkNext<'a, E> {
271 stream: &'a ChunkStream<E>,
272}
273
274impl<E> Future for ChunkNext<'_, E> {
275 type Output = Result<Option<Vec<u8>>, E>;
276
277 fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
278 let shared = &self.stream.shared;
279 let mut state = lock(&shared.state);
280 if let Some(chunk) = state.ready.pop_front() {
281 drop(state);
282 shared.room.notify_one();
283 return Poll::Ready(Ok(Some(chunk)));
284 }
285 if let Some(error) = state.error.take() {
286 return Poll::Ready(Err(error));
287 }
288 if state.finished {
289 return Poll::Ready(Ok(None));
290 }
291 state.waker = Some(context.waker().clone());
292 Poll::Pending
293 }
294}
295
296fn lock<T>(mutex: &Mutex<T>) -> std::sync::MutexGuard<'_, T> {
297 mutex.lock().unwrap_or_else(PoisonError::into_inner)
298}
299
300#[cfg(test)]
301#[path = "tests/async_io_tests.rs"]
302mod tests;