From c096057dd334f51c9e0d2f30a855802e2a68e3b5 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Tue, 8 Nov 2022 20:06:39 -0800 Subject: [PATCH] chore: tweak attributes to only set ID once --- packages/core/src/create.rs | 51 +++++++++++------------ packages/core/src/mutations.rs | 3 +- packages/core/src/virtual_dom.rs | 2 +- packages/dioxus/tests/rsx_syntax.rs | 63 ++-------------------------- packages/dioxus/tests/suspense.rs | 64 +++++++++++++++++++++++++++++ packages/html/src/events.rs | 16 +++++++- 6 files changed, 109 insertions(+), 90 deletions(-) create mode 100644 packages/dioxus/tests/suspense.rs diff --git a/packages/core/src/create.rs b/packages/core/src/create.rs index dc754ae94..ff6f3229e 100644 --- a/packages/core/src/create.rs +++ b/packages/core/src/create.rs @@ -55,43 +55,42 @@ impl VirtualDom { TemplateNode::DynamicText { .. } => 1, }; - let mut cur_route = None; - // we're on top of a node that has a dynamic attribute for a descendant // Set that attribute now before the stack gets in a weird state - while let Some((idx, path)) = dynamic_attrs.next_if(|(_, p)| p[0] == root_idx as u8) { - let attr = &template.dynamic_attrs[idx]; - if cur_route.is_none() { - cur_route = Some((self.next_element(template), &path[1..])); - } + while let Some((mut attr_id, path)) = + dynamic_attrs.next_if(|(_, p)| p[0] == root_idx as u8) + { + let id = self.next_element(template); + mutations.push(AssignId { + path: &path[1..], + id, + }); - // Attach all the elementIDs to the nodes with dynamic content - let (id, path) = cur_route.unwrap(); + // set any future attrs with the same path (ie same element) + loop { + let attr = &template.dynamic_attrs[attr_id]; + attr.mounted_element.set(id); - mutations.push(AssignId { path, id }); - attr.mounted_element.set(id); - - match attr.value { - AttributeValue::Text(value) => { - mutations.push(SetAttribute { + match attr.value { + AttributeValue::Text(value) => mutations.push(SetAttribute { name: attr.name, value, id, - }); + }), + AttributeValue::Listener(_) => {} + AttributeValue::Float(_) => todo!(), + AttributeValue::Int(_) => todo!(), + AttributeValue::Bool(_) => todo!(), + AttributeValue::Any(_) => todo!(), + AttributeValue::None => todo!(), } - AttributeValue::Listener(_) => { - // + if let Some((next_attr_id, _)) = dynamic_attrs.next_if(|(_, p)| *p == path) { + attr_id = next_attr_id + } else { + break; } - - AttributeValue::Float(_) => todo!(), - AttributeValue::Int(_) => todo!(), - AttributeValue::Bool(_) => todo!(), - AttributeValue::Any(_) => todo!(), - - // Optional attributes - AttributeValue::None => todo!(), } } diff --git a/packages/core/src/mutations.rs b/packages/core/src/mutations.rs index e6a26c0cb..f9405bef4 100644 --- a/packages/core/src/mutations.rs +++ b/packages/core/src/mutations.rs @@ -3,9 +3,8 @@ use crate::arena::ElementId; #[derive(Debug)] pub struct Renderer<'a> { pub subtree: usize, - pub mutations: Vec>, pub template_mutations: Vec>, - // mutations: Vec>, + pub mutations: Vec>, } impl<'a> Renderer<'a> { diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index d68e5edb6..9ed2b483e 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -76,7 +76,7 @@ impl VirtualDom { RenderReturn::Sync(None) => { // } - RenderReturn::Async(_) => unreachable!(), + RenderReturn::Async(_) => unreachable!("Root scope cannot be an async component"), } mutations.push(Mutation::AppendChildren { m: created }); diff --git a/packages/dioxus/tests/rsx_syntax.rs b/packages/dioxus/tests/rsx_syntax.rs index b83d6b7dd..fe5e9c171 100644 --- a/packages/dioxus/tests/rsx_syntax.rs +++ b/packages/dioxus/tests/rsx_syntax.rs @@ -1,5 +1,3 @@ -use std::future::IntoFuture; - use dioxus::prelude::*; fn basic_syntax_is_a_template(cx: Scope) -> Element { @@ -25,63 +23,8 @@ fn basic_syntax_is_a_template(cx: Scope) -> Element { }) } -#[inline_props] -fn suspense_boundary<'a>(cx: Scope<'a>, children: Element<'a>) -> Element { - cx.use_hook(|| cx.provide_context(SuspenseBoundary::new(cx.scope_id()))); - cx.render(rsx! { children }) -} - -fn basic_child(cx: Scope) -> Element { - cx.render(rsx! { - div { "basic child 1" } - }) -} - -async fn async_child(cx: Scope<'_>) -> Element { - let username = use_future!(cx, || async { - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - "async child 1" - }); - - let age = use_future!(cx, || async { - tokio::time::sleep(std::time::Duration::from_secs(2)).await; - println!("long future completed"); - 1234 - }); - - let (_user, _age) = use_future!(cx, || async { - tokio::join!( - tokio::time::sleep(std::time::Duration::from_secs(1)), - tokio::time::sleep(std::time::Duration::from_secs(2)) - ); - ("async child 1", 1234) - }) - .await; - - let (username, age) = tokio::join!(username.into_future(), age.into_future()); - - cx.render(rsx!( - div { "Hello! {username}, you are {age}, {_user} {_age}" } - )) -} - -#[tokio::test] -async fn basic_prints() { - let mut dom = VirtualDom::new(|cx| { - cx.render(rsx! { - div { - h1 { "var" } - suspense_boundary { - basic_child { } - async_child { } - } - } - }) - }); - - dbg!(dom.rebuild()); - - dom.wait_for_work().await; - +#[test] +fn dual_stream() { + let mut dom = VirtualDom::new(basic_syntax_is_a_template); dbg!(dom.rebuild()); } diff --git a/packages/dioxus/tests/suspense.rs b/packages/dioxus/tests/suspense.rs new file mode 100644 index 000000000..3a385fd37 --- /dev/null +++ b/packages/dioxus/tests/suspense.rs @@ -0,0 +1,64 @@ +use std::future::IntoFuture; + +use dioxus::prelude::*; + +#[inline_props] +fn suspense_boundary<'a>(cx: Scope<'a>, children: Element<'a>) -> Element { + cx.use_hook(|| cx.provide_context(SuspenseBoundary::new(cx.scope_id()))); + cx.render(rsx! { children }) +} + +fn basic_child(cx: Scope) -> Element { + cx.render(rsx! { + div { "basic child 1" } + }) +} + +async fn async_child(cx: Scope<'_>) -> Element { + let username = use_future!(cx, || async { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + "async child 1" + }); + + let age = use_future!(cx, || async { + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + println!("long future completed"); + 1234 + }); + + let (_user, _age) = use_future!(cx, || async { + tokio::join!( + tokio::time::sleep(std::time::Duration::from_secs(1)), + tokio::time::sleep(std::time::Duration::from_secs(2)) + ); + ("async child 1", 1234) + }) + .await; + + let (username, age) = tokio::join!(username.into_future(), age.into_future()); + + cx.render(rsx!( + div { "Hello! {username}, you are {age}, {_user} {_age}" } + )) +} + +#[tokio::test] +async fn basic_prints() { + let mut dom = VirtualDom::new(|cx| { + cx.render(rsx! { + div { + h1 { "var" } + suspense_boundary { + basic_child { } + async_child { } + } + } + }) + }); + + dbg!(dom.rebuild()); + + dom.wait_for_work().await; + + dbg!(dom.rebuild()); +} diff --git a/packages/html/src/events.rs b/packages/html/src/events.rs index 51decfa91..d059ccb89 100644 --- a/packages/html/src/events.rs +++ b/packages/html/src/events.rs @@ -15,6 +15,7 @@ pub mod on { }; use euclid::UnknownUnit; use keyboard_types::{Code, Key, Location, Modifiers}; + use std::cell::Cell; use std::collections::HashMap; use std::convert::TryInto; use std::fmt::{Debug, Formatter}; @@ -62,7 +63,20 @@ pub mod on { // let handler = bump.alloc(std::cell::RefCell::new(Some(callback))); // factory.listener(shortname, handler) - todo!() + // pub struct Attribute<'a> { + // pub name: &'a str, + // pub value: AttributeValue<'a>, + // pub namespace: Option<&'static str>, + // pub mounted_element: Cell, + // pub volatile: bool, + // } + Attribute { + name: stringify!($name), + value: AttributeValue::Text("asd"), + namespace: None, + mounted_element: Cell::new(ElementId(0)), + volatile: false, + } } )* )*