Skip to main content

http_type/panic/
impl.rs

1use crate::*;
2
3/// Implementation of methods for the `PanicData` struct.
4impl PanicData {
5    /// Creates a new `PanicData` instance from its constituent parts.
6    ///
7    /// # Arguments
8    ///
9    /// - `Option<String>` - The panic message.
10    /// - `Option<String>` - The source code location of the panic.
11    /// - `Option<String>` - The panic payload.
12    ///
13    /// # Returns
14    ///
15    /// - `PanicData` - A new panic instance.
16    #[inline(always)]
17    pub(crate) fn new(
18        message: Option<String>,
19        location: Option<String>,
20        payload: Option<String>,
21    ) -> Self {
22        Self {
23            message,
24            location,
25            payload,
26        }
27    }
28
29    /// Attempts to extract a string from a dynamic `&dyn Any` panic payload.
30    ///
31    /// This function handles payloads that are either `&str` or `String`.
32    ///
33    /// # Arguments
34    ///
35    /// - `&dyn Any` - The payload from a object.
36    ///
37    /// # Returns
38    ///
39    /// - `Option<String>` - The extracted message, or None if the payload is not a string type.
40    #[inline(always)]
41    fn try_extract_panic_message(panic_payload: &dyn Any) -> Option<String> {
42        if let Some(s) = panic_payload.downcast_ref::<&str>() {
43            Some(s.to_string())
44        } else {
45            panic_payload.downcast_ref::<String>().cloned()
46        }
47    }
48
49    /// Creates a `PanicData` instance from a `tokio::task::JoinError`.
50    ///
51    /// This is used to handle panics that occur within spawned asynchronous tasks,
52    /// extracting the panic message from the `JoinError`.
53    ///
54    /// # Arguments
55    ///
56    /// - `JoinError` - The error from a panicked task.
57    ///
58    /// # Returns
59    ///
60    /// - `PanicData` - A new panic instance with message from error.
61    pub fn from_join_error(join_error: JoinError) -> Self {
62        let default_message: String = join_error.to_string();
63        let mut message: Option<String> = if let Ok(panic_join_error) = join_error.try_into_panic()
64        {
65            Self::try_extract_panic_message(&panic_join_error)
66        } else {
67            None
68        };
69        if (message.is_none() || message.clone().unwrap_or_default().is_empty())
70            && !default_message.is_empty()
71        {
72            message = Some(default_message);
73        }
74        let panic: PanicData = PanicData::new(message, None, None);
75        panic
76    }
77}