Ver código fonte

feat: expand error boundary concept

Jonathan Kelley 2 anos atrás
pai
commit
85f6ea0545

+ 69 - 8
packages/core/src/error_boundary.rs

@@ -67,7 +67,7 @@ impl ErrorBoundary {
 ///     })
 /// }
 /// ```
-pub trait Throw {
+pub trait Throw<S = ()>: Sized {
     /// The value that will be returned in if the given value is `Ok`.
     type Out;
 
@@ -94,6 +94,34 @@ pub trait Throw {
     /// }
     /// ```
     fn throw(self, cx: &ScopeState) -> Option<Self::Out>;
+
+    /// Returns an option that evalutes to None if there is an error, injecting the error to the nearest error boundary.
+    ///
+    /// If the value is `Ok`, then throw returns the value, not aborting the rendering preocess.
+    ///
+    /// The call stack is saved for this component and provided to the error boundary
+    ///
+    ///
+    /// Note that you can also manually throw errors using the throw method on `ScopeState` directly,
+    /// which is what this trait shells out to.
+    ///
+    ///
+    /// ```rust, ignore
+    ///
+    /// #[inline_props]
+    /// fn app(cx: Scope, count: String) -> Element {
+    ///     let id: i32 = count.parse().throw(cx)?;
+    ///
+    ///     cx.render(rsx! {
+    ///         div { "Count {}" }
+    ///     })
+    /// }
+    /// ```
+    fn throw_with<D: Debug + 'static>(
+        self,
+        cx: &ScopeState,
+        e: impl FnOnce() -> D,
+    ) -> Option<Self::Out>;
 }
 
 /// We call clone on any errors that can be owned out of a reference
@@ -109,6 +137,20 @@ impl<'a, T, O: Debug + 'static, E: ToOwned<Owned = O>> Throw for &'a Result<T, E
             }
         }
     }
+
+    fn throw_with<D: Debug + 'static>(
+        self,
+        cx: &ScopeState,
+        err: impl FnOnce() -> D,
+    ) -> Option<Self::Out> {
+        match self {
+            Ok(t) => Some(t),
+            Err(_e) => {
+                cx.throw(err());
+                None
+            }
+        }
+    }
 }
 
 /// Or just throw errors we know about
@@ -124,6 +166,17 @@ impl<T, E: Debug + 'static> Throw for Result<T, E> {
             }
         }
     }
+
+    fn throw_with<D: Debug + 'static>(
+        self,
+        cx: &ScopeState,
+        error: impl FnOnce() -> D,
+    ) -> Option<Self::Out> {
+        self.ok().or_else(|| {
+            cx.throw(error());
+            None
+        })
+    }
 }
 
 /// Or just throw errors we know about
@@ -131,12 +184,20 @@ impl<T> Throw for Option<T> {
     type Out = T;
 
     fn throw(self, cx: &ScopeState) -> Option<T> {
-        match self {
-            Some(t) => Some(t),
-            None => {
-                cx.throw("None error.");
-                None
-            }
-        }
+        self.or_else(|| {
+            cx.throw("None error.");
+            None
+        })
+    }
+
+    fn throw_with<D: Debug + 'static>(
+        self,
+        cx: &ScopeState,
+        error: impl FnOnce() -> D,
+    ) -> Option<Self::Out> {
+        self.or_else(|| {
+            cx.throw(error());
+            None
+        })
     }
 }

+ 18 - 1
packages/router/src/hooks/use_route.rs

@@ -1,4 +1,4 @@
-use crate::{ParsedRoute, RouteContext, RouterContext};
+use crate::{Error as RouterError, ParsedRoute, RouteContext, RouterContext};
 use dioxus::core::{ScopeId, ScopeState};
 use std::{borrow::Cow, str::FromStr, sync::Arc};
 use url::Url;
@@ -107,6 +107,23 @@ impl UseRoute {
     {
         self.segment(name).map(|value| value.parse::<T>())
     }
+
+    /// Get the named parameter from the path, as defined in your router. The
+    /// value will be parsed into the type specified by `T` by calling
+    /// `value.parse::<T>()`. This method returns `None` if the named
+    /// parameter does not exist in the current path.
+    pub fn parse_segment_or_404<T>(&self, name: &str) -> Option<T>
+    where
+        T: FromStr,
+    {
+        match self.parse_segment(name) {
+            Some(Ok(val)) => Some(val),
+            _ => {
+                // todo: throw a 404
+                None
+            }
+        }
+    }
 }
 
 // The entire purpose of this struct is to unubscribe this component when it is unmounted.

+ 5 - 0
packages/router/src/lib.rs

@@ -30,3 +30,8 @@ mod service;
 
 pub use routecontext::*;
 pub use service::*;
+
+#[derive(Debug)]
+pub enum Error {
+    NotFound,
+}