Skip to main content

euv_ui/hook/error_boundary/
impl.rs

1use super::*;
2
3/// Inherent implementation of [`ErrorBoundary`].
4impl ErrorBoundary {
5    /// Creates a new `ErrorBoundary` in the `Healthy`
6    /// phase.
7    pub fn new() -> Self {
8        Self {
9            phase: Signal::create(ErrorBoundaryPhase::Healthy),
10        }
11    }
12
13    /// Runs a closure and, if it panics, transitions
14    /// the boundary to `Caught` and returns `Err`.
15    ///
16    /// On success, the closure's return value is
17    /// returned wrapped in `Ok`. The closure is
18    /// wrapped in `AssertUnwindSafe` so it does not
19    /// have to satisfy `UnwindSafe`.
20    ///
21    /// # Arguments
22    ///
23    /// - `F: FnOnce() -> R + UnwindSafe` - A generic type parameter.
24    ///
25    /// # Returns
26    ///
27    /// - `Result<R, String>` - Result of the operation; an `Err` variant on failure.
28    pub fn try_with<F, R>(&self, closure: F) -> Result<R, String>
29    where
30        F: FnOnce() -> R + UnwindSafe,
31    {
32        match catch_unwind(closure) {
33            Ok(value) => Ok(value),
34            Err(payload) => {
35                let message: String = extract_message(&payload);
36                let _ = catch_unwind(AssertUnwindSafe(|| {
37                    self.get_phase()
38                        .set(ErrorBoundaryPhase::Caught(message.clone()));
39                }));
40                Err(message)
41            }
42        }
43    }
44
45    /// Transitions the boundary back to `Healthy`.
46    /// Useful when invalidating the cache (e.g.,
47    /// after a retry).
48    pub fn reset(&self) {
49        let _ = catch_unwind(AssertUnwindSafe(|| {
50            self.get_phase().set(ErrorBoundaryPhase::Healthy);
51        }));
52    }
53}
54
55/// Default-construction for [`ErrorBoundary`].
56impl Default for ErrorBoundary {
57    /// Constructs a default [`ErrorBoundary`] value.
58    fn default() -> Self {
59        Self::new()
60    }
61}
62
63/// Formatting / debug-printing for [`ErrorBoundary`].
64impl Display for ErrorBoundary {
65    /// Formats the [`ErrorBoundary`] via the supplied formatter.
66    ///
67    /// # Arguments
68    ///
69    /// - `&mut Formatter<'_>` - The formatter receiving the formatted output.
70    ///
71    /// # Returns
72    ///
73    /// - `FmtResult` - Result of the formatting operation.
74    fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
75        write!(formatter, "ErrorBoundary({:?})", self.get_phase().get())
76    }
77}
78
79/// Equality comparison for [`ErrorBoundaryPhase`].
80impl PartialEq for ErrorBoundaryPhase {
81    /// Returns `true` when `self` and `other` are equivalent by the [`PartialEq`] contract.
82    ///
83    /// # Arguments
84    ///
85    /// - `&Self` - The other value to compare against `self`.
86    ///
87    /// # Returns
88    ///
89    /// - `bool` - `true` when `self` and `other` are equivalent by the trait contract.
90    fn eq(&self, other: &Self) -> bool {
91        match (self, other) {
92            (ErrorBoundaryPhase::Healthy, ErrorBoundaryPhase::Healthy) => true,
93            (ErrorBoundaryPhase::Caught(a), ErrorBoundaryPhase::Caught(b)) => a == b,
94            _ => false,
95        }
96    }
97}