turbo_tasks/
capture_future.rs1use std::{
2 borrow::Cow,
3 fmt::Display,
4 future::Future,
5 panic,
6 pin::Pin,
7 task::{Context, Poll},
8};
9
10use anyhow::Result;
11use pin_project_lite::pin_project;
12use serde::{Deserialize, Serialize};
13
14use crate::{backend::TurboTasksExecutionErrorMessage, panic_hooks::LAST_ERROR_LOCATION};
15
16pin_project! {
17 pub struct CaptureFuture<T, F: Future<Output = T>> {
18 #[pin]
19 future: F,
20 }
21}
22
23impl<T, F: Future<Output = T>> CaptureFuture<T, F> {
24 pub fn new(future: F) -> Self {
25 Self { future }
26 }
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
30pub struct TurboTasksPanic {
31 pub message: TurboTasksExecutionErrorMessage,
32 pub location: Option<String>,
33}
34
35impl TurboTasksPanic {
36 pub fn into_panic(self) -> Box<dyn std::any::Any + Send> {
37 Box::new(format!(
38 "{} at {}",
39 self.message,
40 self.location
41 .unwrap_or_else(|| "unknown location".to_string())
42 ))
43 }
44}
45
46impl Display for TurboTasksPanic {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 write!(f, "{}", self.message)
49 }
50}
51
52impl<T, F: Future<Output = T>> Future for CaptureFuture<T, F> {
53 type Output = Result<T, TurboTasksPanic>;
54
55 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
56 let this = self.project();
57
58 let result =
59 panic::catch_unwind(panic::AssertUnwindSafe(|| this.future.poll(cx))).map_err(|err| {
60 let message = match err.downcast_ref::<&'static str>() {
61 Some(s) => TurboTasksExecutionErrorMessage::PIISafe(Cow::Borrowed(s)),
62 None => match err.downcast_ref::<String>() {
63 Some(s) => TurboTasksExecutionErrorMessage::NonPIISafe(s.clone()),
64 None => {
65 let error_message = err
66 .downcast_ref::<Box<dyn Display>>()
67 .map(|e| e.to_string())
68 .unwrap_or_else(|| String::from("<unknown panic>"));
69
70 TurboTasksExecutionErrorMessage::NonPIISafe(error_message)
71 }
72 },
73 };
74
75 LAST_ERROR_LOCATION.with_borrow(|loc| TurboTasksPanic {
76 message,
77 location: loc.clone(),
78 })
79 });
80
81 match result {
82 Err(err) => Poll::Ready(Err(err)),
83 Ok(Poll::Ready(r)) => Poll::Ready(Ok(r)),
84 Ok(Poll::Pending) => Poll::Pending,
85 }
86 }
87}