• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::any::Any;
2 use std::fmt;
3 use std::io;
4 
5 use super::Id;
6 use crate::util::SyncWrapper;
7 cfg_rt! {
8     /// Task failed to execute to completion.
9     pub struct JoinError {
10         repr: Repr,
11         id: Id,
12     }
13 }
14 
15 enum Repr {
16     Cancelled,
17     Panic(SyncWrapper<Box<dyn Any + Send + 'static>>),
18 }
19 
20 impl JoinError {
cancelled(id: Id) -> JoinError21     pub(crate) fn cancelled(id: Id) -> JoinError {
22         JoinError {
23             repr: Repr::Cancelled,
24             id,
25         }
26     }
27 
panic(id: Id, err: Box<dyn Any + Send + 'static>) -> JoinError28     pub(crate) fn panic(id: Id, err: Box<dyn Any + Send + 'static>) -> JoinError {
29         JoinError {
30             repr: Repr::Panic(SyncWrapper::new(err)),
31             id,
32         }
33     }
34 
35     /// Returns true if the error was caused by the task being cancelled.
is_cancelled(&self) -> bool36     pub fn is_cancelled(&self) -> bool {
37         matches!(&self.repr, Repr::Cancelled)
38     }
39 
40     /// Returns true if the error was caused by the task panicking.
41     ///
42     /// # Examples
43     ///
44     /// ```
45     /// use std::panic;
46     ///
47     /// #[tokio::main]
48     /// async fn main() {
49     ///     let err = tokio::spawn(async {
50     ///         panic!("boom");
51     ///     }).await.unwrap_err();
52     ///
53     ///     assert!(err.is_panic());
54     /// }
55     /// ```
is_panic(&self) -> bool56     pub fn is_panic(&self) -> bool {
57         matches!(&self.repr, Repr::Panic(_))
58     }
59 
60     /// Consumes the join error, returning the object with which the task panicked.
61     ///
62     /// # Panics
63     ///
64     /// `into_panic()` panics if the `Error` does not represent the underlying
65     /// task terminating with a panic. Use `is_panic` to check the error reason
66     /// or `try_into_panic` for a variant that does not panic.
67     ///
68     /// # Examples
69     ///
70     /// ```should_panic
71     /// use std::panic;
72     ///
73     /// #[tokio::main]
74     /// async fn main() {
75     ///     let err = tokio::spawn(async {
76     ///         panic!("boom");
77     ///     }).await.unwrap_err();
78     ///
79     ///     if err.is_panic() {
80     ///         // Resume the panic on the main task
81     ///         panic::resume_unwind(err.into_panic());
82     ///     }
83     /// }
84     /// ```
85     #[track_caller]
into_panic(self) -> Box<dyn Any + Send + 'static>86     pub fn into_panic(self) -> Box<dyn Any + Send + 'static> {
87         self.try_into_panic()
88             .expect("`JoinError` reason is not a panic.")
89     }
90 
91     /// Consumes the join error, returning the object with which the task
92     /// panicked if the task terminated due to a panic. Otherwise, `self` is
93     /// returned.
94     ///
95     /// # Examples
96     ///
97     /// ```should_panic
98     /// use std::panic;
99     ///
100     /// #[tokio::main]
101     /// async fn main() {
102     ///     let err = tokio::spawn(async {
103     ///         panic!("boom");
104     ///     }).await.unwrap_err();
105     ///
106     ///     if let Ok(reason) = err.try_into_panic() {
107     ///         // Resume the panic on the main task
108     ///         panic::resume_unwind(reason);
109     ///     }
110     /// }
111     /// ```
try_into_panic(self) -> Result<Box<dyn Any + Send + 'static>, JoinError>112     pub fn try_into_panic(self) -> Result<Box<dyn Any + Send + 'static>, JoinError> {
113         match self.repr {
114             Repr::Panic(p) => Ok(p.into_inner()),
115             _ => Err(self),
116         }
117     }
118 
119     /// Returns a [task ID] that identifies the task which errored relative to
120     /// other currently spawned tasks.
121     ///
122     /// **Note**: This is an [unstable API][unstable]. The public API of this type
123     /// may break in 1.x releases. See [the documentation on unstable
124     /// features][unstable] for details.
125     ///
126     /// [task ID]: crate::task::Id
127     /// [unstable]: crate#unstable-features
128     #[cfg(tokio_unstable)]
129     #[cfg_attr(docsrs, doc(cfg(tokio_unstable)))]
id(&self) -> Id130     pub fn id(&self) -> Id {
131         self.id
132     }
133 }
134 
135 impl fmt::Display for JoinError {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result136     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
137         match &self.repr {
138             Repr::Cancelled => write!(fmt, "task {} was cancelled", self.id),
139             Repr::Panic(_) => write!(fmt, "task {} panicked", self.id),
140         }
141     }
142 }
143 
144 impl fmt::Debug for JoinError {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result145     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
146         match &self.repr {
147             Repr::Cancelled => write!(fmt, "JoinError::Cancelled({:?})", self.id),
148             Repr::Panic(_) => write!(fmt, "JoinError::Panic({:?}, ...)", self.id),
149         }
150     }
151 }
152 
153 impl std::error::Error for JoinError {}
154 
155 impl From<JoinError> for io::Error {
from(src: JoinError) -> io::Error156     fn from(src: JoinError) -> io::Error {
157         io::Error::new(
158             io::ErrorKind::Other,
159             match src.repr {
160                 Repr::Cancelled => "task was cancelled",
161                 Repr::Panic(_) => "task panicked",
162             },
163         )
164     }
165 }
166