feat: amazingly awesome error handling
This commit is contained in:
1 parent
05c909f320
commit
4a72b3140b
58 files changed
+248
-1219
No files matched your search
@@ -5,7 +5,7 @@
|
||||
//! if the type suppports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder
|
||||
//! that ensures compile-time required and optional fields on cx.
|
||||
|
||||
use crate::innerlude::{Context, LazyNodes, VNode, FC};
|
||||
use crate::innerlude::{Context, DomTree, LazyNodes, VNode, FC};
|
||||
|
||||
pub trait Properties: Sized {
|
||||
type Builder;
|
||||
@@ -51,6 +51,6 @@ pub fn fc_to_builder<T: Properties>(_: FC<T>) -> T::Builder {
|
||||
/// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase.
|
||||
/// Try to avoid nesting fragments if you can. Infinitely nested Fragments *will* cause diffing to crash.
|
||||
#[allow(non_upper_case_globals, non_snake_case)]
|
||||
pub fn Fragment<'a>(cx: Context<'a, ()>) -> VNode<'a> {
|
||||
pub fn Fragment<'a>(cx: Context<'a, ()>) -> DomTree<'a> {
|
||||
cx.render(LazyNodes::new(move |f| f.fragment_from_iter(cx.children())))
|
||||
}
|
||||
@@ -133,13 +133,13 @@ impl<'src, P> Context<'src, P> {
|
||||
pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||
self,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> VNode<'src> {
|
||||
) -> DomTree<'src> {
|
||||
let scope_ref = self.scope;
|
||||
let listener_id = &scope_ref.listener_idx;
|
||||
lazy_nodes.into_vnode(NodeFactory {
|
||||
Some(lazy_nodes.into_vnode(NodeFactory {
|
||||
scope_ref,
|
||||
listener_id,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
/// Store a value between renders
|
||||
@@ -378,7 +378,7 @@ pub(crate) struct SuspenseHook {
|
||||
pub callback: SuspendedCallback,
|
||||
pub dom_node_id: Rc<Cell<RealDomNode>>,
|
||||
}
|
||||
type SuspendedCallback = Box<dyn for<'a> Fn(Context<'a, ()>) -> VNode<'a>>;
|
||||
type SuspendedCallback = Box<dyn for<'a> Fn(SuspendedContext<'a>) -> DomTree<'a>>;
|
||||
|
||||
impl<'src, P> Context<'src, P> {
|
||||
/// Asynchronously render new nodes once the given future has completed.
|
||||
@@ -395,11 +395,11 @@ impl<'src, P> Context<'src, P> {
|
||||
self,
|
||||
task_initializer: impl FnOnce() -> Fut,
|
||||
user_callback: Cb,
|
||||
) -> VNode<'src>
|
||||
) -> DomTree<'src>
|
||||
where
|
||||
Fut: Future<Output = Out> + 'static,
|
||||
Out: 'static,
|
||||
Cb: for<'a> Fn(Context<'a, ()>, &Out) -> VNode<'a> + 'static,
|
||||
Cb: for<'a> Fn(SuspendedContext<'a>, &Out) -> DomTree<'a> + 'static,
|
||||
{
|
||||
self.use_hook(
|
||||
move |hook_idx| {
|
||||
@@ -410,7 +410,7 @@ impl<'src, P> Context<'src, P> {
|
||||
|
||||
let slot = value.clone();
|
||||
|
||||
let callback: SuspendedCallback = Box::new(move |ctx: Context<()>| {
|
||||
let callback: SuspendedCallback = Box::new(move |ctx: SuspendedContext| {
|
||||
let v: std::cell::Ref<Option<Box<dyn Any>>> = slot.as_ref().borrow();
|
||||
match v.as_ref() {
|
||||
Some(a) => {
|
||||
@@ -420,13 +420,13 @@ impl<'src, P> Context<'src, P> {
|
||||
}
|
||||
None => {
|
||||
//
|
||||
VNode {
|
||||
Some(VNode {
|
||||
dom_id: RealDomNode::empty_cell(),
|
||||
key: None,
|
||||
kind: VNodeKind::Suspended {
|
||||
node: domnode.clone(),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -459,13 +459,31 @@ impl<'src, P> Context<'src, P> {
|
||||
scope: &self.scope,
|
||||
props: &(),
|
||||
};
|
||||
(&hook.callback)(cx)
|
||||
let csx = SuspendedContext { inner: cx };
|
||||
(&hook.callback)(csx)
|
||||
},
|
||||
|_| {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SuspendedContext<'a> {
|
||||
pub(crate) inner: Context<'a, ()>,
|
||||
}
|
||||
impl<'src> SuspendedContext<'src> {
|
||||
pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||
self,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> DomTree<'src> {
|
||||
let scope_ref = self.inner.scope;
|
||||
let listener_id = &scope_ref.listener_idx;
|
||||
Some(lazy_nodes.into_vnode(NodeFactory {
|
||||
scope_ref,
|
||||
listener_id,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TaskHandle<'src> {
|
||||
_p: PhantomData<&'src ()>,
|
||||
|
||||
@@ -18,8 +18,7 @@ pub use crate::innerlude::{
|
||||
pub mod prelude {
|
||||
pub use crate::component::{fc_to_builder, Fragment, Properties};
|
||||
pub use crate::context::Context;
|
||||
pub use crate::innerlude::DioxusElement;
|
||||
pub use crate::innerlude::{LazyNodes, NodeFactory, FC};
|
||||
pub use crate::innerlude::{DioxusElement, DomTree, LazyNodes, NodeFactory, FC};
|
||||
pub use crate::nodes::VNode;
|
||||
pub use crate::VirtualDom;
|
||||
pub use dioxus_core_macro::{format_args_f, html, rsx, Props};
|
||||
@@ -43,7 +42,8 @@ pub(crate) mod innerlude {
|
||||
pub use crate::util::*;
|
||||
pub use crate::virtual_dom::*;
|
||||
|
||||
pub type FC<P> = fn(Context<P>) -> VNode;
|
||||
pub type DomTree<'a> = Option<VNode<'a>>;
|
||||
pub type FC<P> = fn(Context<P>) -> DomTree;
|
||||
|
||||
pub use dioxus_core_macro::{format_args_f, html, rsx};
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//! These VNodes should be *very* cheap and *very* fast to construct - building a full tree should be insanely quick.
|
||||
use crate::{
|
||||
events::VirtualEvent,
|
||||
innerlude::{Context, Properties, RealDomNode, Scope, ScopeId, FC},
|
||||
innerlude::{Context, DomTree, Properties, RealDomNode, Scope, ScopeId, FC},
|
||||
};
|
||||
use std::{
|
||||
cell::Cell,
|
||||
@@ -50,6 +50,7 @@ pub struct VText<'src> {
|
||||
pub struct VFragment<'src> {
|
||||
pub children: &'src [VNode<'src>],
|
||||
pub is_static: bool,
|
||||
pub is_error: bool,
|
||||
}
|
||||
|
||||
pub trait DioxusElement {
|
||||
@@ -114,7 +115,7 @@ pub struct Listener<'bump> {
|
||||
pub struct VComponent<'src> {
|
||||
pub ass_scope: Cell<Option<ScopeId>>,
|
||||
|
||||
pub(crate) caller: Rc<dyn Fn(&Scope) -> VNode>,
|
||||
pub(crate) caller: Rc<dyn Fn(&Scope) -> DomTree>,
|
||||
|
||||
pub(crate) children: &'src [VNode<'src>],
|
||||
|
||||
@@ -321,9 +322,9 @@ impl<'a> NodeFactory<'a> {
|
||||
pub fn create_component_caller<'g, P: 'g>(
|
||||
component: FC<P>,
|
||||
raw_props: *const (),
|
||||
) -> Rc<dyn for<'r> Fn(&'r Scope) -> VNode<'r>> {
|
||||
type Captured<'a> = Rc<dyn for<'r> Fn(&'r Scope) -> VNode<'r> + 'a>;
|
||||
let caller: Captured = Rc::new(move |scp: &Scope| -> VNode {
|
||||
) -> Rc<dyn for<'r> Fn(&'r Scope) -> DomTree<'r>> {
|
||||
type Captured<'a> = Rc<dyn for<'r> Fn(&'r Scope) -> DomTree<'r> + 'a>;
|
||||
let caller: Captured = Rc::new(move |scp: &Scope| -> DomTree {
|
||||
// cast back into the right lifetime
|
||||
let safe_props: &'_ P = unsafe { &*(raw_props as *const P) };
|
||||
let cx: Context<P> = Context {
|
||||
@@ -371,6 +372,7 @@ To help you identify where this error is coming from, we've generated a backtrac
|
||||
kind: VNodeKind::Fragment(VFragment {
|
||||
children: nodes.into_bump_slice(),
|
||||
is_static: false,
|
||||
is_error: false,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -426,6 +428,7 @@ impl<'a> IntoVNode<'a> for &VNode<'a> {
|
||||
VNodeKind::Fragment(fragment) => VNodeKind::Fragment(VFragment {
|
||||
children: fragment.children,
|
||||
is_static: fragment.is_static,
|
||||
is_error: false,
|
||||
}),
|
||||
VNodeKind::Component(component) => VNodeKind::Component(component),
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ pub struct Scope {
|
||||
type EventChannel = Rc<dyn Fn()>;
|
||||
|
||||
// The type of closure that wraps calling components
|
||||
pub type WrappedCaller = dyn for<'b> Fn(&'b Scope) -> VNode<'b>;
|
||||
pub type WrappedCaller = dyn for<'b> Fn(&'b Scope) -> DomTree<'b>;
|
||||
|
||||
// The type of task that gets sent to the task scheduler
|
||||
pub type FiberTask = Pin<Box<dyn Future<Output = EventTrigger>>>;
|
||||
@@ -130,7 +130,8 @@ impl Scope {
|
||||
|
||||
// this is its own function so we can preciesly control how lifetimes flow
|
||||
unsafe fn call_user_component<'a>(&'a self, caller: &WrappedCaller) -> VNode<'static> {
|
||||
let new_head: VNode<'a> = caller(self);
|
||||
let new_head: Option<VNode<'a>> = caller(self);
|
||||
let new_head = new_head.unwrap_or(errored_fragment());
|
||||
std::mem::transmute(new_head)
|
||||
}
|
||||
|
||||
@@ -205,3 +206,15 @@ impl Scope {
|
||||
&self.frames.cur_frame().head_node
|
||||
}
|
||||
}
|
||||
|
||||
pub fn errored_fragment() -> VNode<'static> {
|
||||
VNode {
|
||||
dom_id: RealDomNode::empty_cell(),
|
||||
key: None,
|
||||
kind: VNodeKind::Fragment(VFragment {
|
||||
children: &[],
|
||||
is_static: false,
|
||||
is_error: true,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ impl VirtualDom {
|
||||
///
|
||||
/// // or directly from a fn
|
||||
///
|
||||
/// fn Example(cx: Context<()>) -> VNode {
|
||||
/// fn Example(cx: Context<()>) -> DomTree {
|
||||
/// cx.render(rsx!{ div{"hello world"} })
|
||||
/// }
|
||||
///
|
||||
@@ -318,9 +318,11 @@ impl VirtualDom {
|
||||
let hook = unsafe { scope.hooks.get_mut::<SuspenseHook>(*hook_idx) }.unwrap();
|
||||
|
||||
let cx = Context { scope, props: &() };
|
||||
let scx = SuspendedContext { inner: cx };
|
||||
|
||||
// generate the new node!
|
||||
let nodes: VNode<'s> = (&hook.callback)(cx);
|
||||
let nodes: Option<VNode<'s>> = (&hook.callback)(scx);
|
||||
let nodes = nodes.unwrap_or_else(|| errored_fragment());
|
||||
let nodes = scope.cur_frame().bump.alloc(nodes);
|
||||
|
||||
// push the old node's root onto the stack
|
||||
|
||||
Reference in new issue
Block a user