From 6185fa27d89fd664691ba1fc835c305e1a46450c Mon Sep 17 00:00:00 2001 From: Ryan McGrath Date: Sun, 26 May 2019 02:01:34 -0700 Subject: [PATCH] Finalizing new RenderEngine --- alchemy/src/window/window.rs | 65 +++---------------- lifecycle/src/reconciler/error.rs | 30 +++++++++ .../src/{reconciler.rs => reconciler/mod.rs} | 40 ++++++++++-- 3 files changed, 73 insertions(+), 62 deletions(-) create mode 100644 lifecycle/src/reconciler/error.rs rename lifecycle/src/{reconciler.rs => reconciler/mod.rs} (93%) diff --git a/alchemy/src/window/window.rs b/alchemy/src/window/window.rs index 80bad3d..b22c781 100644 --- a/alchemy/src/window/window.rs +++ b/alchemy/src/window/window.rs @@ -37,65 +37,18 @@ impl AppWindow { /// This method is called on the `show` event, and in rare cases can be useful to call /// directly. pub fn render(&mut self) { - /* - let mut new_root_node = create_root_node(None, &mut self.layout); - - // For API reasons, we'll call the render for this Window, and then patch it into a new - // root node for the tree diff/patch comparison. For this we only need to go one level - // deep, the recursion in the next step will handle the rest. - match self.delegate.render() { - Ok(opt) => match opt { - RSX::VirtualNode(mut child) => { - if let RSX::VirtualNode(root) = &mut new_root_node { - if child.tag == "Fragment" { - root.children.append(&mut child.children); - } else { - root.children.push(RSX::VirtualNode(child)); - } - } - }, - - // If it's an RSX::None, or a RSX::VirtualText, we do nothing, as... one - // requires nothing, and one isn't supported unless it's inside a tag. - _ => {} - }, + let children = match self.delegate.render() { + Ok(opt) => opt, + Err(e) => { + eprintln!("Error rendering window! {}", e); + RSX::None + } + }; + match RENDER_ENGINE.diff_and_render_root(&self.render_key, children) { + Ok(_) => {} Err(e) => { eprintln!("Error rendering window! {}", e); } } - - // Taking ownership of the tree makes parts of this so much easier, so let's swap - // them out for the moment. We're going to discard the old one anyway. - let mut old_root_node = RSX::None; - std::mem::swap(&mut old_root_node, &mut self.root_node); - - self.root_node = match diff_and_patch_tree(old_root_node, new_root_node, &mut self.layout, 0) { - Ok(node) => node, - Err(e) => { eprintln!("Error: {}", e); RSX::None } - }; - - self.configure_and_apply_styles(); - */ - } - - /// Walks the tree again, purely concerning itself with calculating layout and applying styles. - /// This in effect creates a two-pass layout system. In the future much of this may be made - /// async, so relying on underlying behavior in here is considered... suspect. - /// - /// This method is called on window resize and show events. - fn configure_and_apply_styles(&mut self) -> Result<(), Box> { - let window_size = Size { - width: Number::Defined(600.), - height: Number::Defined(600.) - }; - - /*if let RSX::VirtualNode(root_node) = &mut self.root_node { - if let Some(layout_node) = &root_node.layout_node { - self.layout.compute_layout(*layout_node, window_size)?; - walk_and_apply_styles(&root_node, &mut self.layout)?; - } - }*/ - - Ok(()) } /// Renders and calls through to the native platform window show method. diff --git a/lifecycle/src/reconciler/error.rs b/lifecycle/src/reconciler/error.rs new file mode 100644 index 0000000..8c2bbc4 --- /dev/null +++ b/lifecycle/src/reconciler/error.rs @@ -0,0 +1,30 @@ +//! Implements a set of Error types that could happen during a diff/patch/reflow +//! run. These are mostly internal to the rendering engine itself, but could potentially +//! show up elsewhere. + +use std::fmt; +use std::error::Error; + +pub enum RenderEngineError { + InvalidKeyError +} + +impl fmt::Display for RenderEngineError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + RenderEngineError::InvalidKeyError => write!(f, "An invalid key was passed to the render engine.") + } + } +} + +impl fmt::Debug for RenderEngineError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + RenderEngineError::InvalidKeyError => write!(f, "An invalid key was passed to the render engine: {{ file: {}, line: {} }}", file!(), line!()) + } + } +} + +impl Error for RenderEngineError { + +} diff --git a/lifecycle/src/reconciler.rs b/lifecycle/src/reconciler/mod.rs similarity index 93% rename from lifecycle/src/reconciler.rs rename to lifecycle/src/reconciler/mod.rs index 5ea3fdf..9a8bf78 100644 --- a/lifecycle/src/reconciler.rs +++ b/lifecycle/src/reconciler/mod.rs @@ -16,6 +16,9 @@ use alchemy_styles::geometry::Size; use crate::traits::Component; use crate::rsx::{Props, RSX, VirtualNode}; +mod error; +use error::RenderEngineError; + // This is never actually created, it's just to satisfy the fact that View // is defined in the core crate, which we can't import here without creating a // circular dependency. @@ -77,12 +80,37 @@ impl RenderEngine { /// the new tree before discarding the old tree. /// /// This calls the necessary component lifecycles per-component. - pub fn diff_and_apply_root(&self, key: &Uuid, new_root: RSX) -> Result<(), Box> { - /*let trees = self.trees.lock().unwrap(); - let (old_root, stretch) = trees.remove(key)?; - diff_and_patch_trees(old_root, new_root, &mut stretch, 0)?; - trees.insert(*key, (new_root, stretch)); - */ + pub fn diff_and_render_root(&self, key: &Uuid, child: RSX) -> Result<(), Box> { + let mut new_root = RSX::node("root", || { + Arc::new(RwLock::new(StubView {})) + }, { + let mut props = Props::default(); + props.styles = "root".into(); + props + }); + + // If it's an RSX::None, or a RSX::VirtualText, we do nothing, as... one + // requires nothing, and one isn't supported unless it's inside a tag. + if let RSX::VirtualNode(mut child) = child { + if let RSX::VirtualNode(new_root_node) = &mut new_root { + if child.tag == "Fragment" { + new_root_node.children.append(&mut child.children); + } else { + new_root_node.children.push(RSX::VirtualNode(child)); + } + } + } + + let mut trees = self.trees.lock().unwrap(); + let (old_root, mut stretch) = trees.remove(key).ok_or_else(|| RenderEngineError::InvalidKeyError {})?; + let patched_new_root = diff_and_patch_trees(old_root, new_root, &mut stretch, 0)?; + + if let RSX::VirtualNode(node) = &patched_new_root { + walk_and_apply_styles(node, &mut stretch)?; + } + + trees.insert(*key, (patched_new_root, stretch)); + println!("RENDERED"); Ok(()) } }