executor_core/
async_executor.rs

1use 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}