From c52af221f755601a9e826ffc2c355def138999d0 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 14 Jul 2021 18:19:51 -0400 Subject: [PATCH] wip: basic support for scheduled rendering --- packages/core-macro/Cargo.toml | 1 - packages/core/src/util.rs | 8 ++- packages/core/src/virtual_dom.rs | 23 +++++---- packages/web/examples/async_web.rs | 13 +---- packages/web/src/lib.rs | 82 ++++++++++++++++-------------- packages/web/src/new.rs | 33 +++++++----- packages/webview/src/dom.rs | 3 +- packages/webview/src/lib.rs | 10 ++-- 8 files changed, 93 insertions(+), 80 deletions(-) diff --git a/packages/core-macro/Cargo.toml b/packages/core-macro/Cargo.toml index f599da01a..6c2fc5a4c 100644 --- a/packages/core-macro/Cargo.toml +++ b/packages/core-macro/Cargo.toml @@ -13,7 +13,6 @@ proc-macro = true [dependencies] once_cell = "1.7.2" -proc-macro-hack = "0.5.19" proc-macro2 = { version = "1.0.6" } quote = "1.0" syn = { version = "1.0.11", features = ["full", "extra-traits"] } diff --git a/packages/core/src/util.rs b/packages/core/src/util.rs index d229e5bbe..76c1b6005 100644 --- a/packages/core/src/util.rs +++ b/packages/core/src/util.rs @@ -66,6 +66,11 @@ impl RealDomNode { let key: DefaultKey = data.into(); Self(key) } + pub fn from_u64(id: u64) -> Self { + let data = KeyData::from_ffi(id); + let key: DefaultKey = data.into(); + Self(key) + } pub fn empty_cell() -> Cell { Cell::new(Self::empty()) } @@ -102,7 +107,8 @@ impl<'a> RealDom<'a> for DebugDom { async fn launch_demo(app: FC<()>) { let mut dom = VirtualDom::new(app); let mut real_dom = DebugDom::new(); - dom.rebuild(&mut real_dom).unwrap(); + let mut edits = Vec::new(); + dom.rebuild(&mut real_dom, &mut edits).unwrap(); while let Some(evt) = dom.tasks.next().await { // diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 4cc700773..c7f3734e0 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -191,7 +191,8 @@ impl VirtualDom { /// SSR takes advantage of this by using Dioxus itself as the source of truth, and rendering from the tree directly. pub fn rebuild_in_place(&mut self) -> Result<()> { let mut realdom = DebugDom::new(); - self.rebuild(&mut realdom) + let mut edits = Vec::new(); + self.rebuild(&mut realdom, &mut edits) } /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch @@ -199,10 +200,13 @@ impl VirtualDom { /// Currently this doesn't do what we want it to do /// /// The diff machine expects the RealDom's stack to be the root of the application - pub fn rebuild<'s, Dom: RealDom<'s>>(&'s mut self, realdom: &mut Dom) -> Result<()> { - let mut edits = Vec::new(); + pub fn rebuild<'s, Dom: RealDom<'s>>( + &'s mut self, + realdom: &mut Dom, + edits: &mut Vec>, + ) -> Result<()> { let mut diff_machine = DiffMachine::new( - &mut edits, + edits, realdom, &self.components, self.base_scope, @@ -211,7 +215,6 @@ impl VirtualDom { ); let cur_component = self.components.try_get_mut(self.base_scope).unwrap(); - cur_component.run_scope()?; let meta = diff_machine.create(cur_component.next_frame()); @@ -278,12 +281,12 @@ impl VirtualDom { pub async fn progress_with_event<'s, Dom: RealDom<'s>>( &'s mut self, realdom: &'_ mut Dom, + edits: &mut Vec>, ) -> Result<()> { let trigger = self.triggers.borrow_mut().pop().expect("failed"); - let mut edits = Vec::new(); let mut diff_machine = DiffMachine::new( - &mut edits, + edits, realdom, &self.components, trigger.originator, @@ -295,9 +298,9 @@ impl VirtualDom { VirtualEvent::OtherEvent => todo!(), // Fiber events - VirtualEvent::FiberEvent => { - // - } + // VirtualEvent::FiberEvent => { + // // + // } // This is the "meat" of our cooperative scheduler // As updates flow in, we re-evalute the event queue and decide if we should be switching the type of work diff --git a/packages/web/examples/async_web.rs b/packages/web/examples/async_web.rs index 345e897ee..dbefbbf56 100644 --- a/packages/web/examples/async_web.rs +++ b/packages/web/examples/async_web.rs @@ -17,7 +17,7 @@ use dioxus_web::*; fn main() { // Setup logging - // wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); + wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); console_error_panic_hook::set_once(); // Run the app @@ -37,17 +37,6 @@ static App: FC<()> = |cx| { let set_val = state.setter(); let (tas, g) = cx.use_task(|| async move { - let mut tick: i32 = 0; - log::debug!("yeet!"); - // loop { - // gloo_timers::future::TimeoutFuture::new(250).await; - // log::debug!("ticking forward... {}", tick); - // tick += 1; - // if tick > 10 { - // break; - // } - // } - // String::from("Huzza!") set_val(10); surf::get(ENDPOINT).recv_json::().await }); diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index 55c98a604..aca261cb7 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -72,53 +72,57 @@ impl WebsysRenderer { websys_dom.stack.push(root_node.clone()); websys_dom.stack.push(root_node); - self.internal_dom.rebuild(&mut websys_dom)?; + let mut edits = Vec::new(); + self.internal_dom.rebuild(&mut websys_dom, &mut edits)?; + websys_dom.process_edits(&mut edits); log::info!("Going into event loop"); - // loop { - let trigger = { - let real_queue = websys_dom.wait_for_event(); - if self.internal_dom.tasks.is_empty() { - log::info!("tasks is empty, waiting for dom event to trigger soemthing"); - real_queue.await - } else { - log::info!("tasks is not empty, waiting for either tasks or event system"); - let task_queue = (&mut self.internal_dom.tasks).next(); + loop { + let trigger = { + let real_queue = websys_dom.wait_for_event(); + if self.internal_dom.tasks.is_empty() { + log::info!("tasks is empty, waiting for dom event to trigger soemthing"); + real_queue.await + } else { + log::info!("tasks is not empty, waiting for either tasks or event system"); + let task_queue = (&mut self.internal_dom.tasks).next(); - pin_mut!(real_queue); - pin_mut!(task_queue); + pin_mut!(real_queue); + pin_mut!(task_queue); - match futures_util::future::select(real_queue, task_queue).await { - futures_util::future::Either::Left((trigger, _)) => trigger, - futures_util::future::Either::Right((trigger, _)) => trigger, + match futures_util::future::select(real_queue, task_queue).await { + futures_util::future::Either::Left((trigger, _)) => trigger, + futures_util::future::Either::Right((trigger, _)) => trigger, + } } + }; + + if let Some(real_trigger) = trigger { + log::info!("event received"); + // let root_node = body_element.first_child().unwrap(); + // websys_dom.stack.push(root_node.clone()); + + self.internal_dom.queue_event(real_trigger)?; + + let mut edits = Vec::new(); + self.internal_dom + .progress_with_event(&mut websys_dom, &mut edits) + .await?; + websys_dom.process_edits(&mut edits); } - }; - if let Some(real_trigger) = trigger { - log::info!("event received"); - // let root_node = body_element.first_child().unwrap(); - // websys_dom.stack.push(root_node.clone()); - - self.internal_dom.queue_event(real_trigger)?; - - self.internal_dom - .progress_with_event(&mut websys_dom) - .await?; + // let t2 = self.internal_dom.tasks.next(); + // futures::select! { + // trigger = t1 => { + // log::info!("event received"); + // let root_node = body_element.first_child().unwrap(); + // websys_dom.stack.push(root_node.clone()); + // self.internal_dom + // .progress_with_event(&mut websys_dom, trigger)?; + // }, + // () = t2 => {} + // }; } - - // let t2 = self.internal_dom.tasks.next(); - // futures::select! { - // trigger = t1 => { - // log::info!("event received"); - // let root_node = body_element.first_child().unwrap(); - // websys_dom.stack.push(root_node.clone()); - // self.internal_dom - // .progress_with_event(&mut websys_dom, trigger)?; - // }, - // () = t2 => {} - // }; - // } // while let Some(trigger) = websys_dom.wait_for_event().await { // } diff --git a/packages/web/src/new.rs b/packages/web/src/new.rs index 642c39a1d..5aee667ff 100644 --- a/packages/web/src/new.rs +++ b/packages/web/src/new.rs @@ -13,7 +13,7 @@ use web_sys::{ pub struct WebsysDom { pub stack: Stack, - nodes: slotmap::SlotMap, + nodes: slotmap::SlotMap>, document: Document, root: Element, @@ -51,7 +51,7 @@ impl WebsysDom { let mut nodes = slotmap::SlotMap::with_capacity(1000); - let root_id = nodes.insert(root.clone().dyn_into::().unwrap()); + let root_id = nodes.insert(Some(root.clone().dyn_into::().unwrap())); Self { stack: Stack::with_capacity(10), @@ -72,6 +72,7 @@ impl WebsysDom { pub fn process_edits(&mut self, edits: &mut Vec) { for edit in edits.drain(..) { + log::info!("Handling edit: {:#?}", edit); match edit { DomEdit::PushRoot { root } => self.push(root), DomEdit::PopRoot => self.pop(), @@ -90,18 +91,19 @@ impl WebsysDom { idx, } => self.new_event_listener(event, scope, idx, node), DomEdit::RemoveEventListener { event } => todo!(), - DomEdit::SetText { text } => todo!(), - DomEdit::SetAttribute { field, value, ns } => todo!(), - DomEdit::RemoveAttribute { name } => todo!(), + DomEdit::SetText { text } => self.set_text(text), + DomEdit::SetAttribute { field, value, ns } => self.set_attribute(field, value, ns), + DomEdit::RemoveAttribute { name } => self.remove_attribute(name), } } } fn push(&mut self, root: RealDomNode) { let key = root.0; - let domnode = self - .nodes - .get(key) - .expect(&format!("Failed to pop know root: {:#?}", key)); + let domnode = self.nodes.get_mut(key); + + let domnode = domnode.unwrap().as_mut().unwrap(); + // .expect(&format!("Failed to pop know root: {:#?}", key)) + // .unwrap(); self.stack.push(domnode.clone()); } @@ -189,14 +191,17 @@ impl WebsysDom { } fn create_text_node(&mut self, text: &str, id: RealDomNode) { // let nid = self.node_counter.next(); + let textnode = self .document .create_text_node(text) .dyn_into::() .unwrap(); - self.stack.push(textnode.clone()); - todo!(); + self.stack.push(textnode.clone()); + let mut slot = self.nodes.get_mut(id.0).unwrap(); + *slot = Some(textnode); + // let nid = self.nodes.insert(textnode); // let nid = nid.data().as_ffi(); @@ -223,6 +228,8 @@ impl WebsysDom { }; self.stack.push(el.clone()); + let mut slot = self.nodes.get_mut(id.0).unwrap(); + *slot = Some(el); // let nid = self.node_counter.?next(); // let nid = self.nodes.insert(el).data().as_ffi(); // log::debug!("Called [`create_element`]: {}, {:?}", tag, nid); @@ -331,7 +338,9 @@ impl WebsysDom { impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom { fn request_available_node(&mut self) -> RealDomNode { - todo!() + let key = self.nodes.insert(None); + log::debug!("making new key: {:#?}", key); + RealDomNode(key) } fn raw_node_as_any(&self) -> &mut dyn std::any::Any { diff --git a/packages/webview/src/dom.rs b/packages/webview/src/dom.rs index a3c3d8c04..230d98fc2 100644 --- a/packages/webview/src/dom.rs +++ b/packages/webview/src/dom.rs @@ -37,6 +37,7 @@ impl<'bump> RealDom<'bump> for WebviewDom<'bump> { } fn request_available_node(&mut self) -> RealDomNode { - todo!() + self.node_counter += 1; + RealDomNode::from_u64(self.node_counter) } } diff --git a/packages/webview/src/lib.rs b/packages/webview/src/lib.rs index 0a2548ca0..60f495562 100644 --- a/packages/webview/src/lib.rs +++ b/packages/webview/src/lib.rs @@ -87,8 +87,9 @@ impl WebviewRenderer { // Serialize the edit stream let edits = { - lock.rebuild(&mut real).unwrap(); - serde_json::to_value(&real.edits).unwrap() + let mut edits = Vec::new(); + lock.rebuild(&mut real, &mut edits).unwrap(); + serde_json::to_value(edits).unwrap() }; // Give back the registry into its slot @@ -108,8 +109,9 @@ impl WebviewRenderer { // Serialize the edit stream let edits = { - lock.rebuild(&mut real).unwrap(); - serde_json::to_value(&real.edits).unwrap() + let mut edits = Vec::new(); + lock.rebuild(&mut real, &mut edits).unwrap(); + serde_json::to_value(edits).unwrap() }; // Give back the registry into its slot