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<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<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
81#[cfg(feature = "serialize")]
82impl serde::Serialize for CapturedError {
83    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
84    where
85        S: serde::Serializer,
86    {
87        serializer.serialize_str(&self.0.to_string())
88    }
89}
90
91#[cfg(feature = "serialize")]
92impl<'de> serde::Deserialize<'de> for CapturedError {
93    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
94    where
95        D: serde::Deserializer<'de>,
96    {
97        let s = String::deserialize(deserializer)?;
98        Ok(Self::from_display(s))
99    }
100}
101
102impl std::ops::Deref for CapturedError {
103    type Target = Error;
104
105    fn deref(&self) -> &Self::Target {
106        &self.0
107    }
108}
109
110impl<E: Into<Error>> From<E> for CapturedError {
111    fn from(e: E) -> Self {
112        Self(Arc::new(e.into()))
113    }
114}
115
116impl std::fmt::Display for CapturedError {
117    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118        std::fmt::Display::fmt(&*self.0, f)
119    }
120}
121
122impl PartialEq for CapturedError {
123    fn eq(&self, other: &Self) -> bool {
124        Arc::ptr_eq(&self.0, &other.0)
125    }
126}
127
128#[test]
129fn assert_errs_can_downcast() {
130    fn assert_is_stderr_like<T: Send + Sync + Display + Debug>() {}
131
132    assert_is_stderr_like::<RenderError>();
133    assert_is_stderr_like::<CapturedError>();
134}