From d1b294fff0c8618e50969ca59f198baf0565777d Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 1 Nov 2021 03:35:26 -0400 Subject: [PATCH] polish: move debugging virtualdom into its own feature --- packages/core/Cargo.toml | 1 + packages/core/src/debug_dom.rs | 128 +++++++++++++++++++++++++++++++ packages/core/src/lib.rs | 3 + packages/core/src/nodes.rs | 60 +++++++-------- packages/core/src/scope.rs | 107 -------------------------- packages/core/src/virtual_dom.rs | 56 +++++--------- 6 files changed, 182 insertions(+), 173 deletions(-) create mode 100644 packages/core/src/debug_dom.rs diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml index ea0ae505d..334ebcee1 100644 --- a/packages/core/Cargo.toml +++ b/packages/core/Cargo.toml @@ -55,6 +55,7 @@ dioxus-core-macro = { path = "../core-macro", version = "0.1.2" } [features] default = [] serialize = ["serde", "serde_repr"] +debug_vdom = [] [[bench]] name = "create" diff --git a/packages/core/src/debug_dom.rs b/packages/core/src/debug_dom.rs new file mode 100644 index 000000000..13d874be3 --- /dev/null +++ b/packages/core/src/debug_dom.rs @@ -0,0 +1,128 @@ +use crate::{innerlude::ScopeInner, virtual_dom::VirtualDom, VNode}; + +impl std::fmt::Display for VirtualDom { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let base = self.base_scope(); + let root = base.root_node(); + + let renderer = ScopeRenderer { + show_fragments: false, + skip_components: false, + + _scope: base, + _pre_render: false, + _newline: true, + _indent: true, + _max_depth: usize::MAX, + }; + + renderer.render(self, root, f, 0) + } +} + +/// render the scope to a string using the rsx! syntax +pub(crate) struct ScopeRenderer<'a> { + pub skip_components: bool, + pub show_fragments: bool, + pub _scope: &'a ScopeInner, + pub _pre_render: bool, + pub _newline: bool, + pub _indent: bool, + pub _max_depth: usize, +} + +// this is more or less a debug tool, but it'll render the entire tree to the terminal +impl<'a> ScopeRenderer<'a> { + pub fn render( + &self, + vdom: &VirtualDom, + node: &VNode, + f: &mut std::fmt::Formatter, + il: u16, + ) -> std::fmt::Result { + const INDENT: &str = " "; + let write_indent = |_f: &mut std::fmt::Formatter, le| { + for _ in 0..le { + write!(_f, "{}", INDENT).unwrap(); + } + }; + + match &node { + VNode::Text(text) => { + write_indent(f, il); + writeln!(f, "\"{}\"", text.text)? + } + VNode::Anchor(_anchor) => { + write_indent(f, il); + writeln!(f, "Anchor {{}}")?; + } + VNode::Element(el) => { + write_indent(f, il); + writeln!(f, "{} {{", el.tag_name)?; + // write!(f, "element: {}", el.tag_name)?; + let mut attr_iter = el.attributes.iter().peekable(); + + while let Some(attr) = attr_iter.next() { + match attr.namespace { + None => { + // + write_indent(f, il + 1); + writeln!(f, "{}: \"{}\"", attr.name, attr.value)? + } + + Some(ns) => { + // write the opening tag + write_indent(f, il + 1); + write!(f, " {}:\"", ns)?; + let mut cur_ns_el = attr; + 'ns_parse: loop { + write!(f, "{}:{};", cur_ns_el.name, cur_ns_el.value)?; + match attr_iter.peek() { + Some(next_attr) if next_attr.namespace == Some(ns) => { + cur_ns_el = attr_iter.next().unwrap(); + } + _ => break 'ns_parse, + } + } + // write the closing tag + write!(f, "\"")?; + } + } + } + + for child in el.children { + self.render(vdom, child, f, il + 1)?; + } + write_indent(f, il); + + writeln!(f, "}}")?; + } + VNode::Fragment(frag) => { + if self.show_fragments { + write_indent(f, il); + writeln!(f, "Fragment {{")?; + for child in frag.children { + self.render(vdom, child, f, il + 1)?; + } + write_indent(f, il); + writeln!(f, "}}")?; + } else { + for child in frag.children { + self.render(vdom, child, f, il)?; + } + } + } + VNode::Component(vcomp) => { + let idx = vcomp.associated_scope.get().unwrap(); + if !self.skip_components { + let new_node = vdom.get_scope(idx).unwrap().root_node(); + self.render(vdom, new_node, f, il)?; + } + } + VNode::Suspended { .. } => { + // we can't do anything with suspended nodes + } + } + Ok(()) + } +} diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 043e321e2..cdc532ac1 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -34,6 +34,9 @@ pub mod threadsafe; pub mod util; pub mod virtual_dom; +#[cfg(feature = "debug_vdom")] +pub mod debug_dom; + pub(crate) mod innerlude { pub(crate) use crate::bumpframe::*; pub(crate) use crate::childiter::*; diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index bc06eb29d..217374666 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -173,6 +173,29 @@ impl<'src> VNode<'src> { } } +impl Debug for VNode<'_> { + fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { + match &self { + VNode::Element(el) => s + .debug_struct("VElement") + .field("name", &el.tag_name) + .field("key", &el.key) + .finish(), + + VNode::Text(t) => write!(s, "VText {{ text: {} }}", t.text), + VNode::Anchor(_) => write!(s, "VAnchor"), + + VNode::Fragment(frag) => write!(s, "VFragment {{ children: {:?} }}", frag.children), + VNode::Suspended { .. } => write!(s, "VSuspended"), + VNode::Component(comp) => write!( + s, + "VComponent {{ fc: {:?}, children: {:?} }}", + comp.user_fc, comp.children + ), + } + } +} + /// A placeholder node only generated when Fragments don't have any children. pub struct VAnchor { pub dom_id: Cell>, @@ -611,6 +634,12 @@ impl<'a> NodeFactory<'a> { } } +impl Debug for NodeFactory<'_> { + fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Ok(()) + } +} + /// Trait implementations for use in the rsx! and html! macros. /// /// ## Details @@ -668,7 +697,6 @@ impl<'a> IntoVNode<'a> for Option> { } impl<'a> IntoVNode<'a> for Option> { - // impl<'a> IntoVNode<'a> for Option) -> VNode<'a> + '_>> { fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> { match self { Some(lazy) => lazy.call(cx), @@ -682,7 +710,6 @@ impl<'a> IntoVNode<'a> for Option> { } impl<'a> IntoVNode<'a> for LazyNodes<'a, '_> { - // impl<'a> IntoVNode<'a> for Box) -> VNode<'a> + '_> { fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> { self.call(cx) } @@ -699,32 +726,3 @@ impl IntoVNode<'_> for Arguments<'_> { cx.text(self) } } - -impl Debug for NodeFactory<'_> { - fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Ok(()) - } -} - -impl Debug for VNode<'_> { - fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { - match &self { - VNode::Element(el) => s - .debug_struct("VElement") - .field("name", &el.tag_name) - .field("key", &el.key) - .finish(), - - VNode::Text(t) => write!(s, "VText {{ text: {} }}", t.text), - VNode::Anchor(_) => write!(s, "VAnchor"), - - VNode::Fragment(frag) => write!(s, "VFragment {{ children: {:?} }}", frag.children), - VNode::Suspended { .. } => write!(s, "VSuspended"), - VNode::Component(comp) => write!( - s, - "VComponent {{ fc: {:?}, children: {:?} }}", - comp.user_fc, comp.children - ), - } - } -} diff --git a/packages/core/src/scope.rs b/packages/core/src/scope.rs index 94db9d67f..ccfe64855 100644 --- a/packages/core/src/scope.rs +++ b/packages/core/src/scope.rs @@ -358,110 +358,3 @@ impl ScopeInner { } } } - -/// render the scope to a string using the rsx! syntax -pub(crate) struct ScopeRenderer<'a> { - pub skip_components: bool, - pub show_fragments: bool, - pub _scope: &'a ScopeInner, - pub _pre_render: bool, - pub _newline: bool, - pub _indent: bool, - pub _max_depth: usize, -} - -// this is more or less a debug tool, but it'll render the entire tree to the terminal -impl<'a> ScopeRenderer<'a> { - pub fn render( - &self, - vdom: &VirtualDom, - node: &VNode, - f: &mut std::fmt::Formatter, - il: u16, - ) -> std::fmt::Result { - const INDENT: &str = " "; - let write_indent = |_f: &mut std::fmt::Formatter, le| { - for _ in 0..le { - write!(_f, "{}", INDENT).unwrap(); - } - }; - - match &node { - VNode::Text(text) => { - write_indent(f, il); - writeln!(f, "\"{}\"", text.text)? - } - VNode::Anchor(_anchor) => { - write_indent(f, il); - writeln!(f, "Anchor {{}}")?; - } - VNode::Element(el) => { - write_indent(f, il); - writeln!(f, "{} {{", el.tag_name)?; - // write!(f, "element: {}", el.tag_name)?; - let mut attr_iter = el.attributes.iter().peekable(); - - while let Some(attr) = attr_iter.next() { - match attr.namespace { - None => { - // - write_indent(f, il + 1); - writeln!(f, "{}: \"{}\"", attr.name, attr.value)? - } - - Some(ns) => { - // write the opening tag - write_indent(f, il + 1); - write!(f, " {}:\"", ns)?; - let mut cur_ns_el = attr; - 'ns_parse: loop { - write!(f, "{}:{};", cur_ns_el.name, cur_ns_el.value)?; - match attr_iter.peek() { - Some(next_attr) if next_attr.namespace == Some(ns) => { - cur_ns_el = attr_iter.next().unwrap(); - } - _ => break 'ns_parse, - } - } - // write the closing tag - write!(f, "\"")?; - } - } - } - - for child in el.children { - self.render(vdom, child, f, il + 1)?; - } - write_indent(f, il); - - writeln!(f, "}}")?; - } - VNode::Fragment(frag) => { - if self.show_fragments { - write_indent(f, il); - writeln!(f, "Fragment {{")?; - for child in frag.children { - self.render(vdom, child, f, il + 1)?; - } - write_indent(f, il); - writeln!(f, "}}")?; - } else { - for child in frag.children { - self.render(vdom, child, f, il)?; - } - } - } - VNode::Component(vcomp) => { - let idx = vcomp.associated_scope.get().unwrap(); - if !self.skip_components { - let new_node = vdom.get_scope(idx).unwrap().root_node(); - self.render(vdom, new_node, f, il)?; - } - } - VNode::Suspended { .. } => { - // we can't do anything with suspended nodes - } - } - Ok(()) - } -} diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 205854a4b..412d9c2a0 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -368,44 +368,30 @@ impl VirtualDom { use futures_util::StreamExt; // Wait for any new events if we have nothing to do - todo!("wait for work without select macro") - // futures_util::select! { - // _ = self.scheduler.async_tasks.next() => {} - // msg = self.scheduler.receiver.next() => { - // match msg.unwrap() { - // SchedulerMsg::Task(t) => { - // self.scheduler.handle_task(t); - // }, - // SchedulerMsg::Immediate(im) => { - // self.scheduler.dirty_scopes.insert(im); - // } - // SchedulerMsg::UiEvent(evt) => { - // self.scheduler.ui_events.push_back(evt); - // } - // } - // }, - // } - } -} + let tasks_fut = self.scheduler.async_tasks.next(); + let scheduler_fut = self.scheduler.receiver.next(); -impl std::fmt::Display for VirtualDom { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let base = self.base_scope(); - let root = base.root_node(); + use futures_util::future::{select, Either}; + match select(tasks_fut, scheduler_fut).await { + // poll the internal futures + Either::Left((_id, _)) => { + // + } - let renderer = ScopeRenderer { - show_fragments: false, - skip_components: false, - - _scope: base, - _pre_render: false, - _newline: true, - _indent: true, - _max_depth: usize::MAX, - }; - - renderer.render(self, root, f, 0) + // wait for an external event + Either::Right((msg, _)) => match msg.unwrap() { + SchedulerMsg::Task(t) => { + self.scheduler.handle_task(t); + } + SchedulerMsg::Immediate(im) => { + self.scheduler.dirty_scopes.insert(im); + } + SchedulerMsg::UiEvent(evt) => { + self.scheduler.ui_events.push_back(evt); + } + }, + } } }