feat: expand error boundary concept
This commit is contained in:
1 parent
6b41c9d193
commit
85f6ea0545
3 files changed
+92
-9
No files matched your search
@@ -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`.
|
/// The value that will be returned in if the given value is `Ok`.
|
||||||
type Out;
|
type Out;
|
||||||
|
|
||||||
@@ -94,6 +94,34 @@ pub trait Throw {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
fn throw(self, cx: &ScopeState) -> Option<Self::Out>;
|
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
|
/// 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
|
/// 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
|
/// Or just throw errors we know about
|
||||||
@@ -131,12 +184,20 @@ impl<T> Throw for Option<T> {
|
|||||||
type Out = T;
|
type Out = T;
|
||||||
|
|
||||||
fn throw(self, cx: &ScopeState) -> Option<T> {
|
fn throw(self, cx: &ScopeState) -> Option<T> {
|
||||||
match self {
|
self.or_else(|| {
|
||||||
Some(t) => Some(t),
|
cx.throw("None error.");
|
||||||
None => {
|
None
|
||||||
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
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{ParsedRoute, RouteContext, RouterContext};
|
use crate::{Error as RouterError, ParsedRoute, RouteContext, RouterContext};
|
||||||
use dioxus::core::{ScopeId, ScopeState};
|
use dioxus::core::{ScopeId, ScopeState};
|
||||||
use std::{borrow::Cow, str::FromStr, sync::Arc};
|
use std::{borrow::Cow, str::FromStr, sync::Arc};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
@@ -107,6 +107,23 @@ impl UseRoute {
|
|||||||
{
|
{
|
||||||
self.segment(name).map(|value| value.parse::<T>())
|
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.
|
// The entire purpose of this struct is to unubscribe this component when it is unmounted.
|
||||||
|
|||||||
@@ -30,3 +30,8 @@ mod service;
|
|||||||
|
|
||||||
pub use routecontext::*;
|
pub use routecontext::*;
|
||||||
pub use service::*;
|
pub use service::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
NotFound,
|
||||||
|
}
|
||||||
Reference in new issue
Block a user