executor_core/
async_executor.rs1use std::{
2 any::Any,
3 borrow::Cow,
4 mem::ManuallyDrop,
5 ops::DerefMut,
6 panic::{AssertUnwindSafe, catch_unwind},
7 pin::Pin,
8 task::{Poll, ready},
9};
10
11use alloc::{boxed::Box, string::String};
12
13use pin_project_lite::pin_project;
14
15#[allow(dead_code)]
16pub type DefaultExecutor = ::async_executor::Executor<'static>;
17
18#[allow(dead_code)]
19pub type DefaultLocalExecutor = ::async_executor::LocalExecutor<'static>;
20
21use crate::{Error, Executor, LocalExecutor, LocalTask, Task};
22
23struct SmolTask<T>(ManuallyDrop<async_executor::Task<Result<T, Error>>>);
24
25impl<T> Future for SmolTask<T> {
26 type Output = T;
27 fn poll(
28 mut self: std::pin::Pin<&mut Self>,
29 cx: &mut std::task::Context<'_>,
30 ) -> std::task::Poll<Self::Output> {
31 let result = ready!(Pin::new(self.0.deref_mut()).poll(cx));
32 Poll::Ready(result.unwrap())
33 }
34}
35
36impl<T: 'static> LocalTask for SmolTask<T> {
37 async fn result(self) -> Result<Self::Output, crate::Error> {
38 async_executor::Task::fallible(ManuallyDrop::into_inner(self.0))
39 .await
40 .unwrap_or(Err(Error::Cancelled))
41 }
42
43 fn cancel(self) {
44 drop(ManuallyDrop::into_inner(self.0));
45 }
46}
47
48impl<T: 'static + Send> Task for SmolTask<T> {
49 async fn result(self) -> Result<Self::Output, crate::Error> {
50 async_executor::Task::fallible(ManuallyDrop::into_inner(self.0))
51 .await
52 .unwrap_or(Err(Error::Cancelled))
53 }
54
55 fn cancel(self) {
56 drop(ManuallyDrop::into_inner(self.0));
57 }
58}
59
60impl Executor for async_executor::Executor<'static> {
61 fn spawn<T: Send + 'static>(
62 &self,
63 fut: impl Future<Output = T> + Send + 'static,
64 ) -> impl Task<Output = T> {
65 SmolTask(ManuallyDrop::new(async_executor::Executor::spawn(
66 self,
67 UnwindFuture { fut },
68 )))
69 }
70}
71
72pin_project! {
73 struct UnwindFuture<Fut>{
74 #[pin]
75 fut:Fut
76 }
77}
78
79impl<Fut: Future> Future for UnwindFuture<Fut> {
80 type Output = Result<Fut::Output, Error>;
81 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
82 Poll::Ready(
83 match catch_unwind(AssertUnwindSafe(move || self.project().fut.poll(cx))) {
84 Ok(value) => Ok(ready!(value)),
85 Err(error) => Err(Error::Panicked(extract_error(error))),
86 },
87 )
88 }
89}
90
91fn extract_error(error: Box<dyn Any>) -> Cow<'static, str> {
92 error
93 .downcast::<String>()
94 .map(|s| Cow::Owned(*s))
95 .unwrap_or_else(|error| {
96 error
97 .downcast::<&'static str>()
98 .map(|s| Cow::Borrowed(*s))
99 .unwrap_or(Cow::Borrowed("Task panicked"))
100 })
101}
102
103impl LocalExecutor for async_executor::LocalExecutor<'static> {
104 fn spawn<T: 'static>(
105 &self,
106 fut: impl Future<Output = T> + 'static,
107 ) -> impl LocalTask<Output = T> {
108 SmolTask(ManuallyDrop::new(async_executor::LocalExecutor::spawn(
109 self,
110 UnwindFuture { fut },
111 )))
112 }
113}