dioxus_core/
render_error.rs

1use std::{
2    fmt::{Debug, Display},
3    sync::Arc,
4};
5
6use crate::innerlude::*;
7
8/// An error that can occur while rendering a component
9#[derive(Debug, Clone, PartialEq)]
10pub enum RenderError {
11    /// The render function returned early due to an error.
12    ///
13    /// We captured the error, wrapped it in an Arc, and stored it here. You can no longer modify the error,
14    /// but you can cheaply pass it around.
15    Error(CapturedError),
16
17    /// The component was suspended
18    Suspended(SuspendedFuture),
19}
20
21impl Default for RenderError {
22    fn default() -> Self {
23        struct RenderAbortedEarly;
24        impl Debug for RenderAbortedEarly {
25            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26                f.write_str("Render aborted early")
27            }
28        }
29        impl Display for RenderAbortedEarly {
30            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31                f.write_str("Render aborted early")
32            }
33        }
34        impl std::error::Error for RenderAbortedEarly {}
35        Self::Error(CapturedError(Arc::new(RenderAbortedEarly.into())))
36    }
37}
38
39impl Display for RenderError {
40    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41        match self {
42            Self::Error(e) => write!(f, "Render aborted: {e}"),
43            Self::Suspended(e) => write!(f, "Component suspended: {e:?}"),
44        }
45    }
46}
47
48impl From<CapturedError> for RenderError {
49    fn from(e: CapturedError) -> Self {
50        Self::Error(e)
51    }
52}
53
54impl<E: Into<anyhow::Error>> From<E> for RenderError {
55    fn from(e: E) -> Self {
56        let anyhow_err = e.into();
57
58        if let Some(suspended) = anyhow_err.downcast_ref::<SuspendedFuture>() {
59            return Self::Suspended(suspended.clone());
60        }
61
62        if let Some(render_error) = anyhow_err.downcast_ref::<RenderError>() {
63            return render_error.clone();
64        }
65
66        Self::Error(CapturedError(Arc::new(anyhow_err)))
67    }
68}
69
70/// An `anyhow::Error` wrapped in an `Arc` so it can be cheaply cloned and passed around.
71#[derive(Debug, Clone)]
72pub struct CapturedError(pub Arc<anyhow::Error>);
73
74impl CapturedError {
75    /// Create a `CapturedError` from anything that implements `Display`.
76    pub fn from_display(t: impl Display) -> Self {
77        Self(Arc::new(anyhow::anyhow!(t.to_string())))
78    }
79
80    /// Create a `CapturedError` from anything that implements `std::error::Error`.
81    pub fn new<E>(error: E) -> Self
82    where
83        E: std::error::Error + Send + Sync + 'static,
84    {
85        anyhow::Error::new(error).into()
86    }
87
88    /// Create a `CapturedError` from anything that implements `Display` and `Debug`.
89    pub fn msg<M>(t: M) -> Self
90    where
91        M: Display + Debug + Send + Sync + 'static,
92    {
93        anyhow::Error::msg(t).into()
94    }
95
96    /// Create a `CapturedError` from a boxed `std::error::Error`.
97    pub fn from_boxed(boxed_error: Box<dyn std::error::Error + Send + Sync + 'static>) -> Self {
98        anyhow::Error::from_boxed(boxed_error).into()
99    }
100
101    /// Returns the strong count of the underlying error.
102    pub fn _strong_count(&self) -> usize {
103        std::sync::Arc::strong_count(&self.0)
104    }
105
106    /// Try to unwrap the underlying error if this is the only reference to it.
107    pub fn into_inner(self) -> Option<anyhow::Error> {
108        Arc::try_unwrap(self.0).ok()
109    }
110}
111
112#[cfg(feature = "serialize")]
113impl serde::Serialize for CapturedError {
114    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
115    where
116        S: serde::Serializer,
117    {
118        serializer.serialize_str(&self.0.to_string())
119    }
120}
121
122#[cfg(feature = "serialize")]
123impl<'de> serde::Deserialize<'de> for CapturedError {
124    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
125    where
126        D: serde::Deserializer<'de>,
127    {
128        let s = String::deserialize(deserializer)?;
129        Ok(Self::from_display(s))
130    }
131}
132
133impl std::ops::Deref for CapturedError {
134    type Target = anyhow::Error;
135
136    fn deref(&self) -> &Self::Target {
137        &self.0
138    }
139}
140
141impl<E: Into<anyhow::Error>> From<E> for CapturedError {
142    fn from(e: E) -> Self {
143        Self(Arc::new(e.into()))
144    }
145}
146
147impl std::fmt::Display for CapturedError {
148    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149        std::fmt::Display::fmt(&*self.0, f)
150    }
151}
152
153impl PartialEq for CapturedError {
154    fn eq(&self, other: &Self) -> bool {
155        Arc::ptr_eq(&self.0, &other.0)
156    }
157}
158
159#[test]
160fn assert_errs_can_downcast() {
161    fn assert_is_stderr_like<T: Send + Sync + Display + Debug>() {}
162
163    assert_is_stderr_like::<RenderError>();
164    assert_is_stderr_like::<CapturedError>();
165}