1use std::any::Any;
2use std::fmt;
3use std::future::Future;
4use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
5use std::sync::Arc;
6use std::time::Duration;
7
8use super::dispatcher_operation::{box_local_callback, OperationCore, SendCallback, WaitOutcome};
9use super::dispatcher_task::{wrap_local_future, wrap_send_future};
10use super::{
11 CancellationToken, Dispatcher, DispatcherOperation, DispatcherOperationStatus, DispatcherPriority,
12 DispatcherPriorityAwaitable, DispatcherPriorityTaskAwaitable, DispatcherTask, FerroSynchronizationContext,
13 OperationCanceledError,
14};
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum DispatcherInvokeError {
19 Canceled,
22 Timeout,
24}
25
26impl fmt::Display for DispatcherInvokeError {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 match self {
29 Self::Canceled => f.write_str("The dispatcher operation was canceled"),
30 Self::Timeout => f.write_str("The dispatcher operation timed out"),
31 }
32 }
33}
34
35impl std::error::Error for DispatcherInvokeError {}
36
37impl Dispatcher {
42 pub fn invoke<R: Send + 'static>(
51 &self,
52 callback: impl FnOnce() -> R + Send + 'static,
53 ) -> Result<R, OperationCanceledError> {
54 self.invoke_with_cancellation(callback, DispatcherPriority::SEND, &CancellationToken::none())
55 }
56
57 pub fn invoke_with_priority<R: Send + 'static>(
60 &self,
61 callback: impl FnOnce() -> R + Send + 'static,
62 priority: DispatcherPriority,
63 ) -> Result<R, OperationCanceledError> {
64 self.invoke_with_cancellation(callback, priority, &CancellationToken::none())
65 }
66
67 pub fn invoke_with_cancellation<R: Send + 'static>(
73 &self,
74 callback: impl FnOnce() -> R + Send + 'static,
75 priority: DispatcherPriority,
76 cancellation_token: &CancellationToken,
77 ) -> Result<R, OperationCanceledError> {
78 DispatcherPriority::validate(priority, "priority");
79
80 if !cancellation_token.is_cancellation_requested() && priority == DispatcherPriority::SEND && self.check_access()
84 {
85 let _restore = FerroSynchronizationContext::ensure_with_dispatcher(self, priority);
86 return Ok(callback());
87 }
88
89 let operation = DispatcherOperation::new_send(&self.to_arc(), priority, callback);
91 self.invoke_impl(&operation, cancellation_token, None).map_err(|_| OperationCanceledError)
92 }
93
94 pub fn invoke_with_timeout<R: Send + 'static>(
106 &self,
107 callback: impl FnOnce() -> R + Send + 'static,
108 priority: DispatcherPriority,
109 cancellation_token: &CancellationToken,
110 timeout: Duration,
111 ) -> Result<R, DispatcherInvokeError> {
112 DispatcherPriority::validate(priority, "priority");
113
114 if !cancellation_token.is_cancellation_requested() && priority == DispatcherPriority::SEND && self.check_access()
116 {
117 let _restore = FerroSynchronizationContext::ensure_with_dispatcher(self, priority);
118 return Ok(callback());
119 }
120
121 let operation = DispatcherOperation::new_send(&self.to_arc(), priority, callback);
123 self.invoke_impl(&operation, cancellation_token, Some(timeout))
124 }
125
126 pub fn invoke_local<R: 'static>(&self, callback: impl FnOnce() -> R + 'static) -> Result<R, OperationCanceledError> {
131 self.invoke_local_with_cancellation(callback, DispatcherPriority::SEND, &CancellationToken::none())
132 }
133
134 pub fn invoke_local_with_priority<R: 'static>(
140 &self,
141 callback: impl FnOnce() -> R + 'static,
142 priority: DispatcherPriority,
143 ) -> Result<R, OperationCanceledError> {
144 self.invoke_local_with_cancellation(callback, priority, &CancellationToken::none())
145 }
146
147 pub fn invoke_local_with_cancellation<R: 'static>(
153 &self,
154 callback: impl FnOnce() -> R + 'static,
155 priority: DispatcherPriority,
156 cancellation_token: &CancellationToken,
157 ) -> Result<R, OperationCanceledError> {
158 self.verify_access();
159 DispatcherPriority::validate(priority, "priority");
160
161 if !cancellation_token.is_cancellation_requested() && priority == DispatcherPriority::SEND {
163 let _restore = FerroSynchronizationContext::ensure_with_dispatcher(self, priority);
164 return Ok(callback());
165 }
166
167 let operation = DispatcherOperation::new_local(&self.to_arc(), priority, callback);
169 self.invoke_impl(&operation, cancellation_token, None).map_err(|_| OperationCanceledError)
170 }
171
172 pub fn invoke_local_with_timeout<R: 'static>(
178 &self,
179 callback: impl FnOnce() -> R + 'static,
180 priority: DispatcherPriority,
181 cancellation_token: &CancellationToken,
182 timeout: Duration,
183 ) -> Result<R, DispatcherInvokeError> {
184 self.verify_access();
185 DispatcherPriority::validate(priority, "priority");
186
187 if !cancellation_token.is_cancellation_requested() && priority == DispatcherPriority::SEND {
189 let _restore = FerroSynchronizationContext::ensure_with_dispatcher(self, priority);
190 return Ok(callback());
191 }
192
193 let operation = DispatcherOperation::new_local(&self.to_arc(), priority, callback);
195 self.invoke_impl(&operation, cancellation_token, Some(timeout))
196 }
197
198 fn invoke_impl<R: 'static>(
199 &self,
200 operation: &DispatcherOperation<R>,
201 cancellation_token: &CancellationToken,
202 timeout: Option<Duration>,
203 ) -> Result<R, DispatcherInvokeError> {
204 if cancellation_token.is_cancellation_requested() {
205 operation.core().set_status(DispatcherOperationStatus::Aborted);
206 operation.core().call_abort_callbacks();
207 return Err(DispatcherInvokeError::Canceled);
208 }
209
210 debug_assert!(operation.priority() != DispatcherPriority::SEND || !self.check_access()); self.invoke_async_impl(operation.core(), cancellation_token);
215
216 match operation.core().wait_with_limit(timeout, true) {
226 WaitOutcome::TimedOut => Err(DispatcherInvokeError::Timeout),
228 WaitOutcome::Finished => operation.take_result().map_err(|_| DispatcherInvokeError::Canceled),
230 }
231 }
232
233 pub(crate) fn send(&self, action: impl FnOnce() + Send + 'static, priority: Option<DispatcherPriority>) {
240 let priority = priority.unwrap_or(DispatcherPriority::SEND);
241
242 if priority == DispatcherPriority::SEND && self.check_access() {
243 self.send_inline(action, priority);
244 } else {
245 let callback: SendCallback = Box::new(move || {
246 action();
247 Box::new(()) as Box<dyn Any + Send>
248 });
249 let operation = OperationCore::new_send(&self.to_arc(), priority, true, callback);
250 self.invoke_async_impl(&operation, &CancellationToken::none());
251 operation.wait();
252 }
253 }
254
255 pub(crate) fn send_local(&self, action: impl FnOnce() + 'static, priority: Option<DispatcherPriority>) {
260 self.verify_access();
261 let priority = priority.unwrap_or(DispatcherPriority::SEND);
262
263 if priority == DispatcherPriority::SEND {
264 self.send_inline(action, priority);
265 } else {
266 let operation = OperationCore::new_local(&self.to_arc(), priority, true, box_local_callback(action));
267 self.invoke_async_impl(&operation, &CancellationToken::none());
268 operation.wait();
269 }
270 }
271
272 fn send_inline(&self, action: impl FnOnce(), priority: DispatcherPriority) {
273 let result = catch_unwind(AssertUnwindSafe(|| {
274 let _restore = FerroSynchronizationContext::ensure_with_dispatcher(self, priority);
275 action();
276 }));
277 if let Err(payload) = result {
278 if !self.try_catch_when(&payload) {
279 self.forget_exception_if_outermost(&payload);
280 resume_unwind(payload);
281 }
282 }
283 }
284}
285
286impl Dispatcher {
288 pub fn invoke_async<R: Send + 'static>(
294 &self,
295 callback: impl FnOnce() -> R + Send + 'static,
296 ) -> DispatcherOperation<R> {
297 self.invoke_async_with_cancellation(callback, DispatcherPriority::DEFAULT, &CancellationToken::none())
298 }
299
300 pub fn invoke_async_with_priority<R: Send + 'static>(
303 &self,
304 callback: impl FnOnce() -> R + Send + 'static,
305 priority: DispatcherPriority,
306 ) -> DispatcherOperation<R> {
307 self.invoke_async_with_cancellation(callback, priority, &CancellationToken::none())
308 }
309
310 pub fn invoke_async_with_cancellation<R: Send + 'static>(
316 &self,
317 callback: impl FnOnce() -> R + Send + 'static,
318 priority: DispatcherPriority,
319 cancellation_token: &CancellationToken,
320 ) -> DispatcherOperation<R> {
321 DispatcherPriority::validate(priority, "priority");
322
323 let operation = DispatcherOperation::new_send(&self.to_arc(), priority, callback);
324 self.invoke_async_impl(operation.core(), cancellation_token);
325
326 operation
327 }
328
329 pub fn invoke_async_local<R: 'static>(&self, callback: impl FnOnce() -> R + 'static) -> DispatcherOperation<R> {
335 self.invoke_async_local_with_cancellation(callback, DispatcherPriority::DEFAULT, &CancellationToken::none())
336 }
337
338 pub fn invoke_async_local_with_priority<R: 'static>(
344 &self,
345 callback: impl FnOnce() -> R + 'static,
346 priority: DispatcherPriority,
347 ) -> DispatcherOperation<R> {
348 self.invoke_async_local_with_cancellation(callback, priority, &CancellationToken::none())
349 }
350
351 pub fn invoke_async_local_with_cancellation<R: 'static>(
358 &self,
359 callback: impl FnOnce() -> R + 'static,
360 priority: DispatcherPriority,
361 cancellation_token: &CancellationToken,
362 ) -> DispatcherOperation<R> {
363 self.verify_access();
364 DispatcherPriority::validate(priority, "priority");
365
366 let operation = DispatcherOperation::new_local(&self.to_arc(), priority, callback);
367 self.invoke_async_impl(operation.core(), cancellation_token);
368
369 operation
370 }
371
372 pub(crate) fn invoke_async_impl(&self, operation: &Arc<OperationCore>, cancellation_token: &CancellationToken) {
373 let mut succeeded = false;
374
375 {
377 let mut st = self.lock();
378 if !cancellation_token.is_cancellation_requested() && !st.has_shutdown_finished {
379 st.queue.enqueue(operation.priority(), operation.clone());
381
382 succeeded = self.request_processing_locked(&mut st);
384
385 if !succeeded {
386 st.queue.remove_item(operation);
390 }
391 }
392 }
393
394 if succeeded {
395 if cancellation_token.can_be_canceled() {
399 let to_abort = operation.clone();
400 let registration = Arc::new(cancellation_token.register(move || {
401 to_abort.abort();
402 }));
403
404 let revoke = registration.clone();
406 operation.add_aborted(Arc::new(move || revoke.dispose()));
407 operation.add_completed(Arc::new(move || registration.dispose()));
408 }
409 } else {
410 operation.set_status(DispatcherOperationStatus::Aborted);
416 operation.call_abort_callbacks();
417 }
418 }
419
420 pub fn invoke_async_task<F, Fut>(&self, callback: F) -> DispatcherTask<Fut::Output>
427 where
428 F: FnOnce() -> Fut + Send + 'static,
429 Fut: Future + 'static,
430 Fut::Output: Send + 'static,
431 {
432 self.invoke_async_task_with_priority(callback, DispatcherPriority::DEFAULT)
433 }
434
435 pub fn invoke_async_task_with_priority<F, Fut>(
448 &self,
449 callback: F,
450 priority: DispatcherPriority,
451 ) -> DispatcherTask<Fut::Output>
452 where
453 F: FnOnce() -> Fut + Send + 'static,
454 Fut: Future + 'static,
455 Fut::Output: Send + 'static,
456 {
457 DispatcherPriority::validate(priority, "priority");
458 let dispatcher = self.to_arc();
459 let (task, completion, wrap) = wrap_send_future::<Fut>(&dispatcher);
460 let target = dispatcher.clone();
461 drop(self.invoke_async_with_priority(
464 move || match catch_unwind(AssertUnwindSafe(callback)) {
465 Ok(future) => target.start_task(priority, wrap(future), completion, true),
466 Err(payload) => completion.fail(payload),
467 },
468 priority,
469 ));
470 task
471 }
472
473 pub fn invoke_async_task_local<F, Fut>(&self, callback: F) -> DispatcherTask<Fut::Output>
479 where
480 F: FnOnce() -> Fut + 'static,
481 Fut: Future + 'static,
482 Fut::Output: 'static,
483 {
484 self.invoke_async_task_local_with_priority(callback, DispatcherPriority::DEFAULT)
485 }
486
487 pub fn invoke_async_task_local_with_priority<F, Fut>(
494 &self,
495 callback: F,
496 priority: DispatcherPriority,
497 ) -> DispatcherTask<Fut::Output>
498 where
499 F: FnOnce() -> Fut + 'static,
500 Fut: Future + 'static,
501 Fut::Output: 'static,
502 {
503 self.verify_access();
504 DispatcherPriority::validate(priority, "priority");
505 let dispatcher = self.to_arc();
506 let (task, completion, wrap) = wrap_local_future::<Fut>(&dispatcher);
507 let target = dispatcher.clone();
508 drop(self.invoke_async_local_with_priority(
509 move || match catch_unwind(AssertUnwindSafe(callback)) {
510 Ok(future) => target.start_task(priority, wrap(future), completion, true),
511 Err(payload) => completion.fail(payload),
512 },
513 priority,
514 ));
515 task
516 }
517
518 pub fn post(&self, action: impl FnOnce() + Send + 'static, priority: DispatcherPriority) {
523 let callback: SendCallback = Box::new(move || {
524 action();
525 Box::new(()) as Box<dyn Any + Send>
526 });
527 let operation = OperationCore::new_send(&self.to_arc(), priority, true, callback);
528 self.invoke_async_impl(&operation, &CancellationToken::none());
529 }
530
531 pub fn post_local(&self, action: impl FnOnce() + 'static, priority: DispatcherPriority) {
537 let operation = OperationCore::new_local(&self.to_arc(), priority, true, box_local_callback(action));
538 self.invoke_async_impl(&operation, &CancellationToken::none());
539 }
540
541 pub fn await_with_priority<F: Future>(
545 &self,
546 task: F,
547 priority: DispatcherPriority,
548 ) -> DispatcherPriorityTaskAwaitable<F> {
549 DispatcherPriority::validate(priority, "priority");
550 DispatcherPriorityTaskAwaitable::new(self.to_arc(), task, priority)
551 }
552
553 pub fn resume(&self) -> DispatcherPriorityAwaitable {
556 self.resume_with_priority(DispatcherPriority::BACKGROUND)
557 }
558
559 pub fn resume_with_priority(&self, priority: DispatcherPriority) -> DispatcherPriorityAwaitable {
562 DispatcherPriority::validate(priority, "priority");
563 DispatcherPriorityAwaitable::new(self.to_arc(), priority)
564 }
565
566 pub fn yield_now() -> DispatcherPriorityAwaitable {
569 Self::yield_with_priority(DispatcherPriority::BACKGROUND)
570 }
571
572 pub fn yield_with_priority(priority: DispatcherPriority) -> DispatcherPriorityAwaitable {
575 Self::current_dispatcher().resume_with_priority(priority)
576 }
577}