feat: amazingly awesome error handling

This commit is contained in:
Jonathan Kelley committed 2021-07-18 12:39:32 -04:00
1 parent 05c909f320
commit 4a72b3140b
58 files changed
+248 -1219

No files matched your search

+2 -2
View File
@@ -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())))
}
+28 -10
View File
@@ -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 ()>,
+3 -3
View File
@@ -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};
}
+8 -5
View File
@@ -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),
+15 -2
View File
@@ -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,
}),
}
}
+4 -2
View File
@@ -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