work on fixing some core tests

This commit is contained in:
Evan Almloff committed 2024-01-10 19:21:15 -06:00
1 parent 4a1a00b0f0
commit 55f76fede6
35 files changed
+422 -460

No files matched your search

+2
View File
@@ -33,6 +33,7 @@ serde = { version = "1", features = ["derive"], optional = true }
[dev-dependencies] [dev-dependencies]
tokio = { workspace = true, features = ["full"] } tokio = { workspace = true, features = ["full"] }
dioxus = { workspace = true } dioxus = { workspace = true }
dioxus-core = { workspace = true, features = ["internal-testing"] }
dioxus-html = { workspace = true, features = ["serialize"] } dioxus-html = { workspace = true, features = ["serialize"] }
pretty_assertions = "1.3.0" pretty_assertions = "1.3.0"
rand = "0.8.5" rand = "0.8.5"
@@ -42,3 +43,4 @@ trybuild = "1.0"
[features] [features]
default = [] default = []
serialize = ["serde"] serialize = ["serde"]
internal-testing = []
+1
View File
@@ -326,6 +326,7 @@ pub enum Mutation {
} }
/// A static list of mutations that can be applied to the DOM. Note: this list does not contain any `Any` attribute values /// A static list of mutations that can be applied to the DOM. Note: this list does not contain any `Any` attribute values
#[derive(Debug, PartialEq, Default)]
pub struct MutationsVec { pub struct MutationsVec {
/// The list of Scopes that were diffed, created, and removed during the Diff process. /// The list of Scopes that were diffed, created, and removed during the Diff process.
pub dirty_scopes: FxHashSet<ScopeId>, pub dirty_scopes: FxHashSet<ScopeId>,
+1 -1
View File
@@ -10,7 +10,7 @@ use std::{cell::Ref, fmt::Debug, rc::Rc};
/// time for any logic that relies on these IDs to properly update. /// time for any logic that relies on these IDs to properly update.
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub struct ScopeId(pub(crate) usize); pub struct ScopeId(pub usize);
impl ScopeId { impl ScopeId {
/// The root ScopeId. /// The root ScopeId.
+29 -2
View File
@@ -13,7 +13,7 @@ use crate::{
nodes::{Template, TemplateId}, nodes::{Template, TemplateId},
runtime::{Runtime, RuntimeGuard}, runtime::{Runtime, RuntimeGuard},
scopes::{ScopeId, ScopeState}, scopes::{ScopeId, ScopeState},
AttributeValue, Element, Event, AttributeValue, Element, Event, MutationsVec,
}; };
use futures_util::{pin_mut, StreamExt}; use futures_util::{pin_mut, StreamExt};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@@ -300,7 +300,7 @@ impl VirtualDom {
/// Get the single scope at the top of the VirtualDom tree that will always be around /// Get the single scope at the top of the VirtualDom tree that will always be around
/// ///
/// This scope has a ScopeId of 0 and is the root of the tree /// This scope has a ScopeId of 0 and is the root of the tree
pub(crate) fn base_scope(&self) -> &ScopeState { pub fn base_scope(&self) -> &ScopeState {
self.get_scope(ScopeId::ROOT).unwrap() self.get_scope(ScopeId::ROOT).unwrap()
} }
@@ -563,6 +563,14 @@ impl VirtualDom {
to.append_children(ElementId(0), m); to.append_children(ElementId(0), m);
} }
#[cfg(features = "internal-testing")]
/// [`VirtualDom::rebuild`] to a vector of mutations for testing purposes
pub fn rebuild_to_vec(&mut self) -> MutationsVec {
let mut mutations = MutationsVec::default();
self.rebuild(&mut mutations);
mutations
}
/// Render whatever the VirtualDom has ready as fast as possible without requiring an executor to progress /// Render whatever the VirtualDom has ready as fast as possible without requiring an executor to progress
/// suspended subtrees. /// suspended subtrees.
pub fn render_immediate(&mut self, to: &mut impl WriteMutations) { pub fn render_immediate(&mut self, to: &mut impl WriteMutations) {
@@ -582,6 +590,14 @@ impl VirtualDom {
} }
} }
#[cfg(features = "internal-testing")]
/// [`Self::render_immediate`] to a vector of mutations for testing purposes
pub fn render_immediate_to_vec(&mut self) -> MutationsVec {
let mut mutations = MutationsVec::default();
self.render_immediate(&mut mutations);
mutations
}
/// Render the virtual dom, waiting for all suspense to be finished /// Render the virtual dom, waiting for all suspense to be finished
/// ///
/// The mutations will be thrown out, so it's best to use this method for things like SSR that have async content /// The mutations will be thrown out, so it's best to use this method for things like SSR that have async content
@@ -646,6 +662,17 @@ impl VirtualDom {
} }
} }
#[cfg(features = "internal-testing")]
/// [`Self::render_with_deadline`] to a vector of mutations for testing purposes
pub async fn render_with_deadline_to_vec(
&mut self,
deadline: impl Future<Output = ()>,
) -> MutationsVec {
let mut mutations = MutationsVec::default();
self.render_with_deadline(deadline, &mut mutations).await;
mutations
}
/// Get the current runtime /// Get the current runtime
pub fn runtime(&self) -> Rc<Runtime> { pub fn runtime(&self) -> Rc<Runtime> {
self.runtime.clone() self.runtime.clone()
+1 -1
View File
@@ -44,5 +44,5 @@ Hooks
VirtualDOM API VirtualDOM API
- [] work - [] work
- [] rebuild - [] rebuild_to_vec
- [] change props - [] change props
+11 -15
View File
@@ -10,16 +10,12 @@ use dioxus_core::BorrowedAttributeValue;
#[test] #[test]
fn attrs_cycle() { fn attrs_cycle() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let id = cx.generation(); let id = generation();
match cx.generation() % 2 { match generation() % 2 {
0 => cx.render(rsx! { 0 => render! { div {} },
div {} 1 => render! {
}), div { h1 { class: "{id}", id: "{id}" } }
1 => cx.render(rsx! { },
div {
h1 { class: "{id}", id: "{id}" }
}
}),
_ => unreachable!(), _ => unreachable!(),
} }
}); });
@@ -27,7 +23,7 @@ fn attrs_cycle() {
let bump = Bump::new(); let bump = Bump::new();
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild_to_vec_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1,) }, LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
AppendChildren { m: 1, id: ElementId(0) }, AppendChildren { m: 1, id: ElementId(0) },
@@ -36,7 +32,7 @@ fn attrs_cycle() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2,) }, LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
AssignId { path: &[0,], id: ElementId(3,) }, AssignId { path: &[0,], id: ElementId(3,) },
@@ -58,7 +54,7 @@ fn attrs_cycle() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1) }, LoadTemplate { name: "template", index: 0, id: ElementId(1) },
ReplaceWith { id: ElementId(2), m: 1 } ReplaceWith { id: ElementId(2), m: 1 }
@@ -67,7 +63,7 @@ fn attrs_cycle() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2) }, LoadTemplate { name: "template", index: 0, id: ElementId(2) },
AssignId { path: &[0], id: ElementId(3) }, AssignId { path: &[0], id: ElementId(3) },
@@ -90,7 +86,7 @@ fn attrs_cycle() {
// we take the node taken by attributes since we reused it // we take the node taken by attributes since we reused it
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1) }, LoadTemplate { name: "template", index: 0, id: ElementId(1) },
ReplaceWith { id: ElementId(2), m: 1 } ReplaceWith { id: ElementId(2), m: 1 }
+3 -3
View File
@@ -4,16 +4,16 @@ use dioxus::prelude::*;
#[test] #[test]
fn bool_test() { fn bool_test() {
let mut app = VirtualDom::new(|cx| cx.render(rsx!(div { hidden: false }))); let mut app = VirtualDom::new(|cx| render!(div { hidden: false })));
let bump = Bump::new(); let bump = Bump::new();
assert_eq!( assert_eq!(
app.rebuild().santize().edits, app.rebuild_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1) }, LoadTemplate { name: "template", index: 0, id: ElementId(1) },
SetAttribute { SetAttribute {
name: "hidden", name: "hidden",
value: (&*bump.alloc(false.into_value(&bump))).into(), value: dioxus_core::AttributeValue::Bool(false),
id: ElementId(1,), id: ElementId(1,),
ns: None ns: None
}, },
+8 -10
View File
@@ -8,12 +8,12 @@ fn test_borrowed_state() {
let mut dom = VirtualDom::new(Parent); let mut dom = VirtualDom::new(Parent);
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1,) }, LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
LoadTemplate { name: "template", index: 0, id: ElementId(2,) }, LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
LoadTemplate { name: "template", index: 0, id: ElementId(3,) }, LoadTemplate { name: "template", index: 0, id: ElementId(3,) },
HydrateText { path: &[0,], value: "Hello w1!", id: ElementId(4,) }, HydrateText { path: &[0,], value: "Hello w1!".to_string(), id: ElementId(4,) },
ReplacePlaceholder { path: &[1,], m: 1 }, ReplacePlaceholder { path: &[1,], m: 1 },
ReplacePlaceholder { path: &[0,], m: 1 }, ReplacePlaceholder { path: &[0,], m: 1 },
AppendChildren { m: 1, id: ElementId(0) }, AppendChildren { m: 1, id: ElementId(0) },
@@ -24,11 +24,9 @@ fn test_borrowed_state() {
fn Parent(cx: Scope) -> Element { fn Parent(cx: Scope) -> Element {
let w1 = cx.use_hook(|| String::from("w1")); let w1 = cx.use_hook(|| String::from("w1"));
cx.render(rsx! { render! {
div { div { Child { name: w1 } }
Child { name: w1 } }
}
})
} }
#[derive(Props)] #[derive(Props)]
@@ -37,12 +35,12 @@ struct ChildProps<'a> {
} }
fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element { fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element {
cx.render(rsx! { render! {
div { div {
h1 { "it's nested" } h1 { "it's nested" }
Child2 { name: cx.props.name } Child2 { name: cx.props.name }
} }
}) }
} }
#[derive(Props)] #[derive(Props)]
@@ -51,5 +49,5 @@ struct Grandchild<'a> {
} }
fn Child2<'a>(cx: Scope<'a, Grandchild<'a>>) -> Element { fn Child2<'a>(cx: Scope<'a, Grandchild<'a>>) -> Element {
cx.render(rsx!(div { "Hello {cx.props.name}!" })) render!( div { "Hello {cx.props.name}!" } )
} }
+4 -6
View File
@@ -3,7 +3,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let raw = match cx.generation() % 2 { let raw = match generation() % 2 {
0 => "123.123", 0 => "123.123",
1 => "123.123.123", 1 => "123.123.123",
_ => unreachable!(), _ => unreachable!(),
@@ -11,9 +11,7 @@ fn app(cx: Scope) -> Element {
let value = raw.parse::<f32>().unwrap_or(123.123); let value = raw.parse::<f32>().unwrap_or(123.123);
cx.render(rsx! { render! { div { "hello {value}" } }
div { "hello {value}" }
})
} }
#[test] #[test]
@@ -21,10 +19,10 @@ fn bubbles_error() {
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
{ {
let _edits = dom.rebuild().santize(); let _edits = dom.rebuild_to_vec().santize();
} }
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
+12 -12
View File
@@ -4,48 +4,48 @@ use dioxus::prelude::*;
#[test] #[test]
fn state_shares() { fn state_shares() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
cx.provide_context(cx.generation() as i32); cx.provide_context(generation() as i32);
cx.render(rsx!(child_1 {})) render!(child_1 {})
} }
fn child_1(cx: Scope) -> Element { fn child_1(cx: Scope) -> Element {
cx.render(rsx!(child_2 {})) render!(child_2 {})
} }
fn child_2(cx: Scope) -> Element { fn child_2(cx: Scope) -> Element {
let value = cx.consume_context::<i32>().unwrap(); let value = cx.consume_context::<i32>().unwrap();
cx.render(rsx!("Value is {value}")) render!("Value is {value}")
} }
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild_to_vec().santize().edits,
[ [
CreateTextNode { value: "Value is 0", id: ElementId(1,) }, CreateTextNode { value: "Value is 0".to_string(), id: ElementId(1,) },
AppendChildren { m: 1, id: ElementId(0) }, AppendChildren { m: 1, id: ElementId(0) },
] ]
); );
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
assert_eq!(dom.base_scope().consume_context::<i32>().unwrap(), 1); assert_eq!(dom.base_scope().consume_context::<i32>().unwrap(), 1);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
assert_eq!(dom.base_scope().consume_context::<i32>().unwrap(), 2); assert_eq!(dom.base_scope().consume_context::<i32>().unwrap(), 2);
dom.mark_dirty(ScopeId(2)); dom.mark_dirty(ScopeId(2));
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[SetText { value: "Value is 2", id: ElementId(1,) },] [SetText { value: "Value is 2".to_string(), id: ElementId(1,) },]
); );
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
dom.mark_dirty(ScopeId(2)); dom.mark_dirty(ScopeId(2));
let edits = dom.render_immediate(); let edits = dom.render_immediate_to_vec();
assert_eq!( assert_eq!(
edits.santize().edits, edits.santize().edits,
[SetText { value: "Value is 3", id: ElementId(1,) },] [SetText { value: "Value is 3".to_string(), id: ElementId(1,) },]
); );
} }
+25 -36
View File
@@ -2,8 +2,8 @@
//! Prove that the dom works normally through virtualdom methods. //! Prove that the dom works normally through virtualdom methods.
//! //!
//! This methods all use "rebuild" which completely bypasses the scheduler. //! This methods all use "rebuild_to_vec" which completely bypasses the scheduler.
//! Hard rebuilds don't consume any events from the event queue. //! Hard rebuild_to_vecs don't consume any events from the event queue.
use dioxus::core::Mutation::*; use dioxus::core::Mutation::*;
use dioxus::prelude::*; use dioxus::prelude::*;
@@ -12,16 +12,12 @@ use dioxus_core::ElementId;
#[test] #[test]
fn test_original_diff() { fn test_original_diff() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
cx.render(rsx! { render! {
div { div { div { "Hello, world!" } }
div { }
"Hello, world!"
}
}
})
}); });
let edits = dom.rebuild().santize(); let edits = dom.rebuild_to_vec().santize();
assert_eq!( assert_eq!(
edits.edits, edits.edits,
@@ -36,24 +32,21 @@ fn test_original_diff() {
#[test] #[test]
fn create() { fn create() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
cx.render(rsx! { render! {
div { div {
div { div {
"Hello, world!" "Hello, world!"
div { div {
div { div {
Fragment { Fragment { "hello""world" }
"hello"
"world"
}
} }
} }
} }
} }
}) }
}); });
let _edits = dom.rebuild().santize(); let _edits = dom.rebuild_to_vec().santize();
// todo: we don't test template mutations anymore since the templates are passed along // todo: we don't test template mutations anymore since the templates are passed along
@@ -82,13 +75,9 @@ fn create() {
#[test] #[test]
fn create_list() { fn create_list() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| render! {(0..3).map(|f| render!( div { "hello" } ))}));
cx.render(rsx! {
(0..3).map(|f| rsx!( div { "hello" } ))
})
});
let _edits = dom.rebuild().santize(); let _edits = dom.rebuild_to_vec().santize();
// note: we dont test template edits anymore // note: we dont test template edits anymore
// assert_eq!( // assert_eq!(
@@ -106,15 +95,15 @@ fn create_list() {
#[test] #[test]
fn create_simple() { fn create_simple() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
cx.render(rsx! { render! {
div {} div {}
div {} div {}
div {} div {}
div {} div {}
}) }
}); });
let edits = dom.rebuild().santize(); let edits = dom.rebuild_to_vec().santize();
// note: we dont test template edits anymore // note: we dont test template edits anymore
// assert_eq!( // assert_eq!(
@@ -133,11 +122,11 @@ fn create_simple() {
#[test] #[test]
fn create_components() { fn create_components() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
cx.render(rsx! { render! {
Child { "abc1" } Child { "abc1" }
Child { "abc2" } Child { "abc2" }
Child { "abc3" } Child { "abc3" }
}) }
}); });
#[derive(Props)] #[derive(Props)]
@@ -146,14 +135,14 @@ fn create_components() {
} }
fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element { fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element {
cx.render(rsx! { render! {
h1 {} h1 {}
div { &cx.props.children } div { &cx.props.children }
p {} p {}
}) }
} }
let _edits = dom.rebuild().santize(); let _edits = dom.rebuild_to_vec().santize();
// todo: test this // todo: test this
} }
@@ -161,18 +150,18 @@ fn create_components() {
#[test] #[test]
fn anchors() { fn anchors() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
cx.render(rsx! { render! {
if true { if true {
rsx!( div { "hello" } ) render!( div { "hello" } )
} }
if false { if false {
rsx!( div { "goodbye" } ) render!( div { "goodbye" } )
} }
}) }
}); });
// note that the template under "false" doesn't show up since it's not loaded // note that the template under "false" doesn't show up since it's not loaded
let edits = dom.rebuild().santize(); let edits = dom.rebuild_to_vec().santize();
// note: we dont test template edits anymore // note: we dont test template edits anymore
// assert_eq!( // assert_eq!(
+4 -4
View File
@@ -4,18 +4,18 @@ use dioxus::prelude::*;
#[test] #[test]
fn multiroot() { fn multiroot() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
cx.render(rsx! { render! {
div { "Hello a" } div { "Hello a" }
div { "Hello b" } div { "Hello b" }
div { "Hello c" } div { "Hello c" }
}) }
}); });
// note: we dont test template edits anymore // note: we dont test template edits anymore
let _templates = dom.rebuild().santize().templates; let _templates = dom.rebuild_to_vec().santize().templates;
// assert_eq!( // assert_eq!(
// dom.rebuild().santize().templates, // dom.rebuild_to_vec().santize().templates,
// [ // [
// CreateElement { name: "div" }, // CreateElement { name: "div" },
// CreateStaticText { value: "Hello a" }, // CreateStaticText { value: "Hello a" },
+20 -23
View File
@@ -7,11 +7,11 @@ use dioxus_core::ElementId;
#[test] #[test]
fn empty_fragment_creates_nothing() { fn empty_fragment_creates_nothing() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
cx.render(rsx!(())) render!(())
} }
let mut vdom = VirtualDom::new(app); let mut vdom = VirtualDom::new(app);
let edits = vdom.rebuild(); let edits = vdom.rebuild_to_vec();
assert_eq!( assert_eq!(
edits.edits, edits.edits,
@@ -25,14 +25,14 @@ fn empty_fragment_creates_nothing() {
#[test] #[test]
fn root_fragments_work() { fn root_fragments_work() {
let mut vdom = VirtualDom::new(|cx| { let mut vdom = VirtualDom::new(|cx| {
cx.render(rsx!( render!(
div { "hello" } div { "hello" }
div { "goodbye" } div { "goodbye" }
)) )
}); });
assert_eq!( assert_eq!(
vdom.rebuild().edits.last().unwrap(), vdom.rebuild_to_vec().edits.last().unwrap(),
&AppendChildren { id: ElementId(0), m: 2 } &AppendChildren { id: ElementId(0), m: 2 }
); );
} }
@@ -40,26 +40,26 @@ fn root_fragments_work() {
#[test] #[test]
fn fragments_nested() { fn fragments_nested() {
let mut vdom = VirtualDom::new(|cx| { let mut vdom = VirtualDom::new(|cx| {
cx.render(rsx!( render!(
div { "hello" } div { "hello" }
div { "goodbye" } div { "goodbye" }
rsx! { render! {
div { "hello" } div { "hello" }
div { "goodbye" } div { "goodbye" }
rsx! { render! {
div { "hello" } div { "hello" }
div { "goodbye" } div { "goodbye" }
rsx! { render! {
div { "hello" } div { "hello" }
div { "goodbye" } div { "goodbye" }
} }
} }
} }
)) )
}); });
assert_eq!( assert_eq!(
vdom.rebuild().edits.last().unwrap(), vdom.rebuild_to_vec().edits.last().unwrap(),
&AppendChildren { id: ElementId(0), m: 8 } &AppendChildren { id: ElementId(0), m: 8 }
); );
} }
@@ -67,24 +67,21 @@ fn fragments_nested() {
#[test] #[test]
fn fragments_across_components() { fn fragments_across_components() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
cx.render(rsx! { render! {
demo_child {} demo_child {}
demo_child {} demo_child {}
demo_child {} demo_child {}
demo_child {} demo_child {}
}) }
} }
fn demo_child(cx: Scope) -> Element { fn demo_child(cx: Scope) -> Element {
let world = "world"; let world = "world";
cx.render(rsx! { render! { "hellO!", world }
"hellO!"
world
})
} }
assert_eq!( assert_eq!(
VirtualDom::new(app).rebuild().edits.last().unwrap(), VirtualDom::new(app).rebuild_to_vec().edits.last().unwrap(),
&AppendChildren { id: ElementId(0), m: 8 } &AppendChildren { id: ElementId(0), m: 8 }
); );
} }
@@ -92,13 +89,13 @@ fn fragments_across_components() {
#[test] #[test]
fn list_fragments() { fn list_fragments() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
cx.render(rsx!( render!(
h1 {"hello"} h1 { "hello" }
(0..6).map(|f| rsx!( span { "{f}" })) (0..6).map(|f| render!( span { "{f}" }))
)) )
} }
assert_eq!( assert_eq!(
VirtualDom::new(app).rebuild().edits.last().unwrap(), VirtualDom::new(app).rebuild_to_vec().edits.last().unwrap(),
&AppendChildren { id: ElementId(0), m: 7 } &AppendChildren { id: ElementId(0), m: 7 }
); );
} }
+8 -8
View File
@@ -5,27 +5,27 @@ use dioxus_core::ElementId;
// A real-world usecase of templates at peak performance // A real-world usecase of templates at peak performance
// In react, this would be a lot of node creation. // In react, this would be a lot of node creation.
// //
// In Dioxus, we memoize the rsx! body and simplify it down to a few template loads // In Dioxus, we memoize the render! body and simplify it down to a few template loads
// //
// Also note that the IDs increase linearly. This lets us drive a vec on the renderer for O(1) re-indexing // Also note that the IDs increase linearly. This lets us drive a vec on the renderer for O(1) re-indexing
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
cx.render(rsx! { render! {
div { div {
(0..3).map(|i| rsx! { (0..3).map(|i| render! {
div { div {
h1 { "hello world! "} h1 { "hello world! "}
p { "{i}" } p { "{i}" }
} }
}) })
} }
}) }
} }
#[test] #[test]
fn list_renders() { fn list_renders() {
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
let edits = dom.rebuild().santize(); let edits = dom.rebuild_to_vec().santize();
// note: we dont test template edits anymore // note: we dont test template edits anymore
// assert_eq!( // assert_eq!(
@@ -58,11 +58,11 @@ fn list_renders() {
LoadTemplate { name: "template", index: 0, id: ElementId(1) }, LoadTemplate { name: "template", index: 0, id: ElementId(1) },
// Load each template one-by-one, rehydrating it // Load each template one-by-one, rehydrating it
LoadTemplate { name: "template", index: 0, id: ElementId(2) }, LoadTemplate { name: "template", index: 0, id: ElementId(2) },
HydrateText { path: &[1, 0], value: "0", id: ElementId(3) }, HydrateText { path: &[1, 0], value: "0".to_string(), id: ElementId(3) },
LoadTemplate { name: "template", index: 0, id: ElementId(4) }, LoadTemplate { name: "template", index: 0, id: ElementId(4) },
HydrateText { path: &[1, 0], value: "1", id: ElementId(5) }, HydrateText { path: &[1, 0], value: "1".to_string(), id: ElementId(5) },
LoadTemplate { name: "template", index: 0, id: ElementId(6) }, LoadTemplate { name: "template", index: 0, id: ElementId(6) },
HydrateText { path: &[1, 0], value: "2", id: ElementId(7) }, HydrateText { path: &[1, 0], value: "2".to_string(), id: ElementId(7) },
// Replace the 0th childn on the div with the 3 templates on the stack // Replace the 0th childn on the div with the 3 templates on the stack
ReplacePlaceholder { m: 3, path: &[0] }, ReplacePlaceholder { m: 3, path: &[0] },
// Append the container div to the dom // Append the container div to the dom
+14 -18
View File
@@ -7,24 +7,22 @@ use dioxus_core::ElementId;
fn nested_passthru_creates() { fn nested_passthru_creates() {
#[component] #[component]
fn App(cx: Scope) -> Element { fn App(cx: Scope) -> Element {
cx.render(rsx! { render! {
PassThru { PassThru {
PassThru { PassThru {
PassThru { PassThru { div { "hi" } }
div { "hi" }
}
} }
} }
}) }
} }
#[component] #[component]
fn PassThru<'a>(cx: Scope<'a>, children: Element) -> Element { fn PassThru<'a>(cx: Scope<'a>, children: Element) -> Element {
cx.render(rsx!(children)) render!(children)
} }
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
let edits = dom.rebuild().santize(); let edits = dom.rebuild_to_vec().santize();
assert_eq!( assert_eq!(
edits.edits, edits.edits,
@@ -42,31 +40,29 @@ fn nested_passthru_creates() {
fn nested_passthru_creates_add() { fn nested_passthru_creates_add() {
#[component] #[component]
fn App(cx: Scope) -> Element { fn App(cx: Scope) -> Element {
cx.render(rsx! { render! {
ChildComp { ChildComp {
"1" "1"
ChildComp { ChildComp {
"2" "2"
ChildComp { ChildComp {
"3" "3"
div { div { "hi" }
"hi"
}
} }
} }
} }
}) }
} }
#[component] #[component]
fn ChildComp<'a>(cx: Scope, children: Element) -> Element { fn ChildComp<'a>(cx: Scope, children: Element) -> Element {
cx.render(rsx! { children }) render! {children}
} }
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild_to_vec().santize().edits,
[ [
// load 1 // load 1
LoadTemplate { name: "template", index: 0, id: ElementId(1) }, LoadTemplate { name: "template", index: 0, id: ElementId(1) },
@@ -88,11 +84,11 @@ fn dynamic_node_as_root() {
fn App(cx: Scope) -> Element { fn App(cx: Scope) -> Element {
let a = 123; let a = 123;
let b = 456; let b = 456;
cx.render(rsx! { "{a}" "{b}" }) render! { "{a}", "{b}" }
} }
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
let edits = dom.rebuild().santize(); let edits = dom.rebuild_to_vec().santize();
// Since the roots were all dynamic, they should not cause any template muations // Since the roots were all dynamic, they should not cause any template muations
assert!(edits.templates.is_empty()); assert!(edits.templates.is_empty());
@@ -101,8 +97,8 @@ fn dynamic_node_as_root() {
assert_eq!( assert_eq!(
edits.edits, edits.edits,
[ [
CreateTextNode { value: "123", id: ElementId(1) }, CreateTextNode { value: "123".to_string(), id: ElementId(1) },
CreateTextNode { value: "456", id: ElementId(2) }, CreateTextNode { value: "456".to_string(), id: ElementId(2) },
AppendChildren { id: ElementId(0), m: 2 } AppendChildren { id: ElementId(0), m: 2 }
] ]
) )
+8 -10
View File
@@ -4,16 +4,14 @@ use dioxus::prelude::*;
/// As we clean up old templates, the ID for the node should cycle /// As we clean up old templates, the ID for the node should cycle
#[test] #[test]
fn cycling_elements() { fn cycling_elements() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| match generation() % 2 {
cx.render(match cx.generation() % 2 { 0 => render! { div { "wasd" } },
0 => rsx! { div { "wasd" } }, 1 => render! { div { "abcd" } },
1 => rsx! { div { "abcd" } }, _ => unreachable!(),
_ => unreachable!(),
})
}); });
{ {
let edits = dom.rebuild().santize(); let edits = dom.rebuild_to_vec().santize();
assert_eq!( assert_eq!(
edits.edits, edits.edits,
[ [
@@ -25,7 +23,7 @@ fn cycling_elements() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2,) }, LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
ReplaceWith { id: ElementId(1,), m: 1 }, ReplaceWith { id: ElementId(1,), m: 1 },
@@ -35,7 +33,7 @@ fn cycling_elements() {
// notice that the IDs cycle back to ElementId(1), preserving a minimal memory footprint // notice that the IDs cycle back to ElementId(1), preserving a minimal memory footprint
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1,) }, LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
ReplaceWith { id: ElementId(2,), m: 1 }, ReplaceWith { id: ElementId(2,), m: 1 },
@@ -44,7 +42,7 @@ fn cycling_elements() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2,) }, LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
ReplaceWith { id: ElementId(1,), m: 1 }, ReplaceWith { id: ElementId(1,), m: 1 },
+18 -21
View File
@@ -12,55 +12,52 @@ fn component_swap() {
*render_phase += 1; *render_phase += 1;
cx.render(match *render_phase { match *render_phase {
0 => rsx! { 0 => render! {
nav_bar {} nav_bar {}
dash_board {} dash_board {}
}, },
1 => rsx! { 1 => render! {
nav_bar {} nav_bar {}
dash_results {} dash_results {}
}, },
2 => rsx! { 2 => render! {
nav_bar {} nav_bar {}
dash_board {} dash_board {}
}, },
3 => rsx! { 3 => render! {
nav_bar {} nav_bar {}
dash_results {} dash_results {}
}, },
4 => rsx! { 4 => render! {
nav_bar {} nav_bar {}
dash_board {} dash_board {}
}, },
_ => rsx!("blah"), _ => render!("blah"),
}) }
} }
fn nav_bar(cx: Scope) -> Element { fn nav_bar(cx: Scope) -> Element {
cx.render(rsx! { render! {
h1 { h1 { "NavBar", (0..3).map(|_| render!(nav_link {})) }
"NavBar" }
(0..3).map(|_| rsx!(nav_link {}))
}
})
} }
fn nav_link(cx: Scope) -> Element { fn nav_link(cx: Scope) -> Element {
cx.render(rsx!( h1 { "nav_link" } )) render!( h1 { "nav_link" } )
} }
fn dash_board(cx: Scope) -> Element { fn dash_board(cx: Scope) -> Element {
cx.render(rsx!( div { "dashboard" } )) render!( div { "dashboard" } )
} }
fn dash_results(cx: Scope) -> Element { fn dash_results(cx: Scope) -> Element {
cx.render(rsx!( div { "results" } )) render!( div { "results" } )
} }
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
{ {
let edits = dom.rebuild().santize(); let edits = dom.rebuild_to_vec().santize();
assert_eq!( assert_eq!(
edits.edits, edits.edits,
[ [
@@ -77,7 +74,7 @@ fn component_swap() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(6) }, LoadTemplate { name: "template", index: 0, id: ElementId(6) },
ReplaceWith { id: ElementId(5), m: 1 } ReplaceWith { id: ElementId(5), m: 1 }
@@ -86,7 +83,7 @@ fn component_swap() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(5) }, LoadTemplate { name: "template", index: 0, id: ElementId(5) },
ReplaceWith { id: ElementId(6), m: 1 } ReplaceWith { id: ElementId(6), m: 1 }
@@ -95,7 +92,7 @@ fn component_swap() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(6) }, LoadTemplate { name: "template", index: 0, id: ElementId(6) },
ReplaceWith { id: ElementId(5), m: 1 } ReplaceWith { id: ElementId(5), m: 1 }
+17 -17
View File
@@ -5,50 +5,50 @@ use dioxus_core::ElementId;
#[test] #[test]
fn text_diff() { fn text_diff() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let gen = cx.generation(); let gen = generation();
cx.render(rsx!( h1 { "hello {gen}" } )) render!( h1 { "hello {gen}" } )
} }
let mut vdom = VirtualDom::new(app); let mut vdom = VirtualDom::new(app);
_ = vdom.rebuild(); _ = vdom.rebuild_to_vec();
vdom.mark_dirty(ScopeId::ROOT); vdom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
vdom.render_immediate().edits, vdom.render_immediate_to_vec().edits,
[SetText { value: "hello 1", id: ElementId(2) }] [SetText { value: "hello 1".to_string(), id: ElementId(2) }]
); );
vdom.mark_dirty(ScopeId::ROOT); vdom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
vdom.render_immediate().edits, vdom.render_immediate_to_vec().edits,
[SetText { value: "hello 2", id: ElementId(2) }] [SetText { value: "hello 2".to_string(), id: ElementId(2) }]
); );
vdom.mark_dirty(ScopeId::ROOT); vdom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
vdom.render_immediate().edits, vdom.render_immediate_to_vec().edits,
[SetText { value: "hello 3", id: ElementId(2) }] [SetText { value: "hello 3".to_string(), id: ElementId(2) }]
); );
} }
#[test] #[test]
fn element_swap() { fn element_swap() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let gen = cx.generation(); let gen = generation();
match gen % 2 { match gen % 2 {
0 => cx.render(rsx!( h1 { "hello 1" } )), 0 => render!( h1 { "hello 1" } ),
1 => cx.render(rsx!( h2 { "hello 2" } )), 1 => render!( h2 { "hello 2" } ),
_ => unreachable!(), _ => unreachable!(),
} }
} }
let mut vdom = VirtualDom::new(app); let mut vdom = VirtualDom::new(app);
_ = vdom.rebuild(); _ = vdom.rebuild_to_vec();
vdom.mark_dirty(ScopeId::ROOT); vdom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
vdom.render_immediate().santize().edits, vdom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2,) }, LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
ReplaceWith { id: ElementId(1,), m: 1 }, ReplaceWith { id: ElementId(1,), m: 1 },
@@ -57,7 +57,7 @@ fn element_swap() {
vdom.mark_dirty(ScopeId::ROOT); vdom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
vdom.render_immediate().santize().edits, vdom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1,) }, LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
ReplaceWith { id: ElementId(2,), m: 1 }, ReplaceWith { id: ElementId(2,), m: 1 },
@@ -66,7 +66,7 @@ fn element_swap() {
vdom.mark_dirty(ScopeId::ROOT); vdom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
vdom.render_immediate().santize().edits, vdom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2,) }, LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
ReplaceWith { id: ElementId(1,), m: 1 }, ReplaceWith { id: ElementId(1,), m: 1 },
@@ -75,7 +75,7 @@ fn element_swap() {
vdom.mark_dirty(ScopeId::ROOT); vdom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
vdom.render_immediate().santize().edits, vdom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1,) }, LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
ReplaceWith { id: ElementId(2,), m: 1 }, ReplaceWith { id: ElementId(2,), m: 1 },
+48 -48
View File
@@ -11,18 +11,18 @@ use dioxus::prelude::*;
#[test] #[test]
fn keyed_diffing_out_of_order() { fn keyed_diffing_out_of_order() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order = match cx.generation() % 2 { let order = match generation() % 2 {
0 => &[0, 1, 2, 3, /**/ 4, 5, 6, /**/ 7, 8, 9], 0 => &[0, 1, 2, 3, /**/ 4, 5, 6, /**/ 7, 8, 9],
1 => &[0, 1, 2, 3, /**/ 6, 4, 5, /**/ 7, 8, 9], 1 => &[0, 1, 2, 3, /**/ 6, 4, 5, /**/ 7, 8, 9],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
{ {
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1,) }, LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
LoadTemplate { name: "template", index: 0, id: ElementId(2,) }, LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
@@ -41,7 +41,7 @@ fn keyed_diffing_out_of_order() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().edits, dom.render_immediate_to_vec().edits,
[ [
PushRoot { id: ElementId(7,) }, PushRoot { id: ElementId(7,) },
InsertBefore { id: ElementId(5,), m: 1 }, InsertBefore { id: ElementId(5,), m: 1 },
@@ -53,20 +53,20 @@ fn keyed_diffing_out_of_order() {
#[test] #[test]
fn keyed_diffing_out_of_order_adds() { fn keyed_diffing_out_of_order_adds() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order = match cx.generation() % 2 { let order = match generation() % 2 {
0 => &[/**/ 4, 5, 6, 7, 8 /**/], 0 => &[/**/ 4, 5, 6, 7, 8 /**/],
1 => &[/**/ 8, 7, 4, 5, 6 /**/], 1 => &[/**/ 8, 7, 4, 5, 6 /**/],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().edits, dom.render_immediate_to_vec().edits,
[ [
PushRoot { id: ElementId(5,) }, PushRoot { id: ElementId(5,) },
PushRoot { id: ElementId(4,) }, PushRoot { id: ElementId(4,) },
@@ -79,20 +79,20 @@ fn keyed_diffing_out_of_order_adds() {
#[test] #[test]
fn keyed_diffing_out_of_order_adds_3() { fn keyed_diffing_out_of_order_adds_3() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order = match cx.generation() % 2 { let order = match generation() % 2 {
0 => &[/**/ 4, 5, 6, 7, 8 /**/], 0 => &[/**/ 4, 5, 6, 7, 8 /**/],
1 => &[/**/ 4, 8, 7, 5, 6 /**/], 1 => &[/**/ 4, 8, 7, 5, 6 /**/],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().edits, dom.render_immediate_to_vec().edits,
[ [
PushRoot { id: ElementId(5,) }, PushRoot { id: ElementId(5,) },
PushRoot { id: ElementId(4,) }, PushRoot { id: ElementId(4,) },
@@ -105,20 +105,20 @@ fn keyed_diffing_out_of_order_adds_3() {
#[test] #[test]
fn keyed_diffing_out_of_order_adds_4() { fn keyed_diffing_out_of_order_adds_4() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order = match cx.generation() % 2 { let order = match generation() % 2 {
0 => &[/**/ 4, 5, 6, 7, 8 /**/], 0 => &[/**/ 4, 5, 6, 7, 8 /**/],
1 => &[/**/ 4, 5, 8, 7, 6 /**/], 1 => &[/**/ 4, 5, 8, 7, 6 /**/],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().edits, dom.render_immediate_to_vec().edits,
[ [
PushRoot { id: ElementId(5,) }, PushRoot { id: ElementId(5,) },
PushRoot { id: ElementId(4,) }, PushRoot { id: ElementId(4,) },
@@ -131,20 +131,20 @@ fn keyed_diffing_out_of_order_adds_4() {
#[test] #[test]
fn keyed_diffing_out_of_order_adds_5() { fn keyed_diffing_out_of_order_adds_5() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order = match cx.generation() % 2 { let order = match generation() % 2 {
0 => &[/**/ 4, 5, 6, 7, 8 /**/], 0 => &[/**/ 4, 5, 6, 7, 8 /**/],
1 => &[/**/ 4, 5, 6, 8, 7 /**/], 1 => &[/**/ 4, 5, 6, 8, 7 /**/],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().edits, dom.render_immediate_to_vec().edits,
[ [
PushRoot { id: ElementId(5,) }, PushRoot { id: ElementId(5,) },
InsertBefore { id: ElementId(4,), m: 1 }, InsertBefore { id: ElementId(4,), m: 1 },
@@ -156,20 +156,20 @@ fn keyed_diffing_out_of_order_adds_5() {
#[test] #[test]
fn keyed_diffing_additions() { fn keyed_diffing_additions() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order: &[_] = match cx.generation() % 2 { let order: &[_] = match generation() % 2 {
0 => &[/**/ 4, 5, 6, 7, 8 /**/], 0 => &[/**/ 4, 5, 6, 7, 8 /**/],
1 => &[/**/ 4, 5, 6, 7, 8, 9, 10 /**/], 1 => &[/**/ 4, 5, 6, 7, 8, 9, 10 /**/],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(6) }, LoadTemplate { name: "template", index: 0, id: ElementId(6) },
LoadTemplate { name: "template", index: 0, id: ElementId(7) }, LoadTemplate { name: "template", index: 0, id: ElementId(7) },
@@ -181,20 +181,20 @@ fn keyed_diffing_additions() {
#[test] #[test]
fn keyed_diffing_additions_and_moves_on_ends() { fn keyed_diffing_additions_and_moves_on_ends() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order: &[_] = match cx.generation() % 2 { let order: &[_] = match generation() % 2 {
0 => &[/**/ 4, 5, 6, 7 /**/], 0 => &[/**/ 4, 5, 6, 7 /**/],
1 => &[/**/ 7, 4, 5, 6, 11, 12 /**/], 1 => &[/**/ 7, 4, 5, 6, 11, 12 /**/],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
// create 11, 12 // create 11, 12
LoadTemplate { name: "template", index: 0, id: ElementId(5) }, LoadTemplate { name: "template", index: 0, id: ElementId(5) },
@@ -210,21 +210,21 @@ fn keyed_diffing_additions_and_moves_on_ends() {
#[test] #[test]
fn keyed_diffing_additions_and_moves_in_middle() { fn keyed_diffing_additions_and_moves_in_middle() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order: &[_] = match cx.generation() % 2 { let order: &[_] = match generation() % 2 {
0 => &[/**/ 1, 2, 3, 4 /**/], 0 => &[/**/ 1, 2, 3, 4 /**/],
1 => &[/**/ 4, 1, 7, 8, 2, 5, 6, 3 /**/], 1 => &[/**/ 4, 1, 7, 8, 2, 5, 6, 3 /**/],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
// LIS: 4, 5, 6 // LIS: 4, 5, 6
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
// create 5, 6 // create 5, 6
LoadTemplate { name: "template", index: 0, id: ElementId(5) }, LoadTemplate { name: "template", index: 0, id: ElementId(5) },
@@ -244,21 +244,21 @@ fn keyed_diffing_additions_and_moves_in_middle() {
#[test] #[test]
fn controlled_keyed_diffing_out_of_order() { fn controlled_keyed_diffing_out_of_order() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order: &[_] = match cx.generation() % 2 { let order: &[_] = match generation() % 2 {
0 => &[4, 5, 6, 7], 0 => &[4, 5, 6, 7],
1 => &[0, 5, 9, 6, 4], 1 => &[0, 5, 9, 6, 4],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
// LIS: 5, 6 // LIS: 5, 6
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
// remove 7 // remove 7
Remove { id: ElementId(4,) }, Remove { id: ElementId(4,) },
@@ -278,20 +278,20 @@ fn controlled_keyed_diffing_out_of_order() {
#[test] #[test]
fn controlled_keyed_diffing_out_of_order_max_test() { fn controlled_keyed_diffing_out_of_order_max_test() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order: &[_] = match cx.generation() % 2 { let order: &[_] = match generation() % 2 {
0 => &[0, 1, 2, 3, 4], 0 => &[0, 1, 2, 3, 4],
1 => &[3, 0, 1, 10, 2], 1 => &[3, 0, 1, 10, 2],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
Remove { id: ElementId(5,) }, Remove { id: ElementId(5,) },
LoadTemplate { name: "template", index: 0, id: ElementId(5) }, LoadTemplate { name: "template", index: 0, id: ElementId(5) },
@@ -307,20 +307,20 @@ fn controlled_keyed_diffing_out_of_order_max_test() {
#[test] #[test]
fn remove_list() { fn remove_list() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order: &[_] = match cx.generation() % 2 { let order: &[_] = match generation() % 2 {
0 => &[9, 8, 7, 6, 5], 0 => &[9, 8, 7, 6, 5],
1 => &[9, 8], 1 => &[9, 8],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
Remove { id: ElementId(5) }, Remove { id: ElementId(5) },
Remove { id: ElementId(4) }, Remove { id: ElementId(4) },
@@ -332,20 +332,20 @@ fn remove_list() {
#[test] #[test]
fn no_common_keys() { fn no_common_keys() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let order: &[_] = match cx.generation() % 2 { let order: &[_] = match generation() % 2 {
0 => &[1, 2, 3], 0 => &[1, 2, 3],
1 => &[4, 5, 6], 1 => &[4, 5, 6],
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" })))) render!(order.iter().map(|i| render!(div { key: "{i}" })))
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
Remove { id: ElementId(3) }, Remove { id: ElementId(3) },
Remove { id: ElementId(2) }, Remove { id: ElementId(2) },
+78 -80
View File
@@ -5,20 +5,20 @@ use pretty_assertions::assert_eq;
#[test] #[test]
fn list_creates_one_by_one() { fn list_creates_one_by_one() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let gen = cx.generation(); let gen = generation();
cx.render(rsx! { render! {
div { div {
(0..gen).map(|i| rsx! { (0..gen).map(|i| render! {
div { "{i}" } div { "{i}" }
}) })
} }
}) }
}); });
// load the div and then assign the empty fragment as a placeholder // load the div and then assign the empty fragment as a placeholder
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1,) }, LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
AssignId { path: &[0], id: ElementId(2,) }, AssignId { path: &[0], id: ElementId(2,) },
@@ -29,10 +29,10 @@ fn list_creates_one_by_one() {
// Rendering the first item should replace the placeholder with an element // Rendering the first item should replace the placeholder with an element
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(3,) }, LoadTemplate { name: "template", index: 0, id: ElementId(3,) },
HydrateText { path: &[0], value: "0", id: ElementId(4,) }, HydrateText { path: &[0], value: "0".to_string(), id: ElementId(4,) },
ReplaceWith { id: ElementId(2,), m: 1 }, ReplaceWith { id: ElementId(2,), m: 1 },
] ]
); );
@@ -40,10 +40,10 @@ fn list_creates_one_by_one() {
// Rendering the next item should insert after the previous // Rendering the next item should insert after the previous
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2,) }, LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
HydrateText { path: &[0], value: "1", id: ElementId(5,) }, HydrateText { path: &[0], value: "1".to_string(), id: ElementId(5,) },
InsertAfter { id: ElementId(3,), m: 1 }, InsertAfter { id: ElementId(3,), m: 1 },
] ]
); );
@@ -51,10 +51,10 @@ fn list_creates_one_by_one() {
// ... and again! // ... and again!
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(6,) }, LoadTemplate { name: "template", index: 0, id: ElementId(6,) },
HydrateText { path: &[0], value: "2", id: ElementId(7,) }, HydrateText { path: &[0], value: "2".to_string(), id: ElementId(7,) },
InsertAfter { id: ElementId(2,), m: 1 }, InsertAfter { id: ElementId(2,), m: 1 },
] ]
); );
@@ -62,10 +62,10 @@ fn list_creates_one_by_one() {
// once more // once more
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(8,) }, LoadTemplate { name: "template", index: 0, id: ElementId(8,) },
HydrateText { path: &[0], value: "3", id: ElementId(9,) }, HydrateText { path: &[0], value: "3".to_string(), id: ElementId(9,) },
InsertAfter { id: ElementId(6,), m: 1 }, InsertAfter { id: ElementId(6,), m: 1 },
] ]
); );
@@ -74,30 +74,30 @@ fn list_creates_one_by_one() {
#[test] #[test]
fn removes_one_by_one() { fn removes_one_by_one() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let gen = 3 - cx.generation() % 4; let gen = 3 - generation() % 4;
cx.render(rsx! { render! {
div { div {
(0..gen).map(|i| rsx! { (0..gen).map(|i| render! {
div { "{i}" } div { "{i}" }
}) })
} }
}) }
}); });
// load the div and then assign the empty fragment as a placeholder // load the div and then assign the empty fragment as a placeholder
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild_to_vec().santize().edits,
[ [
// The container // The container
LoadTemplate { name: "template", index: 0, id: ElementId(1) }, LoadTemplate { name: "template", index: 0, id: ElementId(1) },
// each list item // each list item
LoadTemplate { name: "template", index: 0, id: ElementId(2) }, LoadTemplate { name: "template", index: 0, id: ElementId(2) },
HydrateText { path: &[0], value: "0", id: ElementId(3) }, HydrateText { path: &[0], value: "0".to_string(), id: ElementId(3) },
LoadTemplate { name: "template", index: 0, id: ElementId(4) }, LoadTemplate { name: "template", index: 0, id: ElementId(4) },
HydrateText { path: &[0], value: "1", id: ElementId(5) }, HydrateText { path: &[0], value: "1".to_string(), id: ElementId(5) },
LoadTemplate { name: "template", index: 0, id: ElementId(6) }, LoadTemplate { name: "template", index: 0, id: ElementId(6) },
HydrateText { path: &[0], value: "2", id: ElementId(7) }, HydrateText { path: &[0], value: "2".to_string(), id: ElementId(7) },
// replace the placeholder in the template with the 3 templates on the stack // replace the placeholder in the template with the 3 templates on the stack
ReplacePlaceholder { m: 3, path: &[0] }, ReplacePlaceholder { m: 3, path: &[0] },
// Mount the div // Mount the div
@@ -109,14 +109,14 @@ fn removes_one_by_one() {
// Rendering the first item should replace the placeholder with an element // Rendering the first item should replace the placeholder with an element
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[Remove { id: ElementId(6) }] [Remove { id: ElementId(6) }]
); );
// Remove div(2) // Remove div(2)
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[Remove { id: ElementId(4) }] [Remove { id: ElementId(4) }]
); );
@@ -124,7 +124,7 @@ fn removes_one_by_one() {
// todo: this should just be a remove with no placeholder // todo: this should just be a remove with no placeholder
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
CreatePlaceholder { id: ElementId(4) }, CreatePlaceholder { id: ElementId(4) },
ReplaceWith { id: ElementId(2), m: 1 } ReplaceWith { id: ElementId(2), m: 1 }
@@ -135,14 +135,14 @@ fn removes_one_by_one() {
// todo: this should actually be append to, but replace placeholder is fine for now // todo: this should actually be append to, but replace placeholder is fine for now
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2) }, LoadTemplate { name: "template", index: 0, id: ElementId(2) },
HydrateText { path: &[0], value: "0", id: ElementId(3) }, HydrateText { path: &[0], value: "0".to_string(), id: ElementId(3) },
LoadTemplate { name: "template", index: 0, id: ElementId(5) }, LoadTemplate { name: "template", index: 0, id: ElementId(5) },
HydrateText { path: &[0], value: "1", id: ElementId(6) }, HydrateText { path: &[0], value: "1".to_string(), id: ElementId(6) },
LoadTemplate { name: "template", index: 0, id: ElementId(7) }, LoadTemplate { name: "template", index: 0, id: ElementId(7) },
HydrateText { path: &[0], value: "2", id: ElementId(8) }, HydrateText { path: &[0], value: "2".to_string(), id: ElementId(8) },
ReplaceWith { id: ElementId(4), m: 3 } ReplaceWith { id: ElementId(4), m: 3 }
] ]
); );
@@ -151,18 +151,18 @@ fn removes_one_by_one() {
#[test] #[test]
fn list_shrink_multiroot() { fn list_shrink_multiroot() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
cx.render(rsx! { render! {
div { div {
(0..cx.generation()).map(|i| rsx! { (0..generation()).map(|i| render! {
div { "{i}" } div { "{i}" }
div { "{i}" } div { "{i}" }
}) })
} }
}) }
}); });
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1,) }, LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
AssignId { path: &[0,], id: ElementId(2,) }, AssignId { path: &[0,], id: ElementId(2,) },
@@ -172,36 +172,36 @@ fn list_shrink_multiroot() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(3) }, LoadTemplate { name: "template", index: 0, id: ElementId(3) },
HydrateText { path: &[0], value: "0", id: ElementId(4) }, HydrateText { path: &[0], value: "0".to_string(), id: ElementId(4) },
LoadTemplate { name: "template", index: 1, id: ElementId(5) }, LoadTemplate { name: "template", index: 1, id: ElementId(5) },
HydrateText { path: &[0], value: "0", id: ElementId(6) }, HydrateText { path: &[0], value: "0".to_string(), id: ElementId(6) },
ReplaceWith { id: ElementId(2), m: 2 } ReplaceWith { id: ElementId(2), m: 2 }
] ]
); );
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2) }, LoadTemplate { name: "template", index: 0, id: ElementId(2) },
HydrateText { path: &[0], value: "1", id: ElementId(7) }, HydrateText { path: &[0], value: "1".to_string(), id: ElementId(7) },
LoadTemplate { name: "template", index: 1, id: ElementId(8) }, LoadTemplate { name: "template", index: 1, id: ElementId(8) },
HydrateText { path: &[0], value: "1", id: ElementId(9) }, HydrateText { path: &[0], value: "1".to_string(), id: ElementId(9) },
InsertAfter { id: ElementId(5), m: 2 } InsertAfter { id: ElementId(5), m: 2 }
] ]
); );
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(10) }, LoadTemplate { name: "template", index: 0, id: ElementId(10) },
HydrateText { path: &[0], value: "2", id: ElementId(11) }, HydrateText { path: &[0], value: "2".to_string(), id: ElementId(11) },
LoadTemplate { name: "template", index: 1, id: ElementId(12) }, LoadTemplate { name: "template", index: 1, id: ElementId(12) },
HydrateText { path: &[0], value: "2", id: ElementId(13) }, HydrateText { path: &[0], value: "2".to_string(), id: ElementId(13) },
InsertAfter { id: ElementId(8), m: 2 } InsertAfter { id: ElementId(8), m: 2 }
] ]
); );
@@ -210,38 +210,38 @@ fn list_shrink_multiroot() {
#[test] #[test]
fn removes_one_by_one_multiroot() { fn removes_one_by_one_multiroot() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let gen = 3 - cx.generation() % 4; let gen = 3 - generation() % 4;
cx.render(rsx! { render! {
div { div {
(0..gen).map(|i| rsx! { (0..gen).map(|i| render! {
div { "{i}" } div { "{i}" }
div { "{i}" } div { "{i}" }
}) })
} }
}) }
}); });
// load the div and then assign the empty fragment as a placeholder // load the div and then assign the empty fragment as a placeholder
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1) }, LoadTemplate { name: "template", index: 0, id: ElementId(1) },
// //
LoadTemplate { name: "template", index: 0, id: ElementId(2) }, LoadTemplate { name: "template", index: 0, id: ElementId(2) },
HydrateText { path: &[0], value: "0", id: ElementId(3) }, HydrateText { path: &[0], value: "0".to_string(), id: ElementId(3) },
LoadTemplate { name: "template", index: 1, id: ElementId(4) }, LoadTemplate { name: "template", index: 1, id: ElementId(4) },
HydrateText { path: &[0], value: "0", id: ElementId(5) }, HydrateText { path: &[0], value: "0".to_string(), id: ElementId(5) },
// //
LoadTemplate { name: "template", index: 0, id: ElementId(6) }, LoadTemplate { name: "template", index: 0, id: ElementId(6) },
HydrateText { path: &[0], value: "1", id: ElementId(7) }, HydrateText { path: &[0], value: "1".to_string(), id: ElementId(7) },
LoadTemplate { name: "template", index: 1, id: ElementId(8) }, LoadTemplate { name: "template", index: 1, id: ElementId(8) },
HydrateText { path: &[0], value: "1", id: ElementId(9) }, HydrateText { path: &[0], value: "1".to_string(), id: ElementId(9) },
// //
LoadTemplate { name: "template", index: 0, id: ElementId(10) }, LoadTemplate { name: "template", index: 0, id: ElementId(10) },
HydrateText { path: &[0], value: "2", id: ElementId(11) }, HydrateText { path: &[0], value: "2".to_string(), id: ElementId(11) },
LoadTemplate { name: "template", index: 1, id: ElementId(12) }, LoadTemplate { name: "template", index: 1, id: ElementId(12) },
HydrateText { path: &[0], value: "2", id: ElementId(13) }, HydrateText { path: &[0], value: "2".to_string(), id: ElementId(13) },
// //
ReplacePlaceholder { path: &[0], m: 6 }, ReplacePlaceholder { path: &[0], m: 6 },
// //
@@ -251,19 +251,19 @@ fn removes_one_by_one_multiroot() {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[Remove { id: ElementId(10) }, Remove { id: ElementId(12) }] [Remove { id: ElementId(10) }, Remove { id: ElementId(12) }]
); );
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[Remove { id: ElementId(6) }, Remove { id: ElementId(8) }] [Remove { id: ElementId(6) }, Remove { id: ElementId(8) }]
); );
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
assert_eq!( assert_eq!(
dom.render_immediate().santize().edits, dom.render_immediate_to_vec().santize().edits,
[ [
CreatePlaceholder { id: ElementId(8) }, CreatePlaceholder { id: ElementId(8) },
Remove { id: ElementId(2) }, Remove { id: ElementId(2) },
@@ -275,48 +275,46 @@ fn removes_one_by_one_multiroot() {
#[test] #[test]
fn two_equal_fragments_are_equal_static() { fn two_equal_fragments_are_equal_static() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
cx.render(rsx! { render! {
(0..5).map(|_| rsx! { (0..5).map(|_| render! {
div { "hello" } div { "hello" }
}) })
}) }
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
assert!(dom.render_immediate().edits.is_empty()); assert!(dom.render_immediate_to_vec().edits.is_empty());
} }
#[test] #[test]
fn two_equal_fragments_are_equal() { fn two_equal_fragments_are_equal() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
cx.render(rsx! { render! {
(0..5).map(|i| rsx! { (0..5).map(|i| render! {
div { "hello {i}" } div { "hello {i}" }
}) })
}) }
}); });
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
assert!(dom.render_immediate().edits.is_empty()); assert!(dom.render_immediate_to_vec().edits.is_empty());
} }
#[test] #[test]
fn remove_many() { fn remove_many() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let num = match cx.generation() % 3 { let num = match generation() % 3 {
0 => 0, 0 => 0,
1 => 1, 1 => 1,
2 => 5, 2 => 5,
_ => unreachable!(), _ => unreachable!(),
}; };
cx.render(rsx! { render! {(0..num).map(|i| render! { div { "hello {i}" } })}
(0..num).map(|i| rsx! { div { "hello {i}" } })
})
}); });
{ {
let edits = dom.rebuild().santize(); let edits = dom.rebuild_to_vec().santize();
assert!(edits.templates.is_empty()); assert!(edits.templates.is_empty());
assert_eq!( assert_eq!(
edits.edits, edits.edits,
@@ -329,12 +327,12 @@ fn remove_many() {
{ {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
let edits = dom.render_immediate().santize(); let edits = dom.render_immediate_to_vec().santize();
assert_eq!( assert_eq!(
edits.edits, edits.edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2,) }, LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
HydrateText { path: &[0,], value: "hello 0", id: ElementId(3,) }, HydrateText { path: &[0,], value: "hello 0".to_string(), id: ElementId(3,) },
ReplaceWith { id: ElementId(1,), m: 1 }, ReplaceWith { id: ElementId(1,), m: 1 },
] ]
); );
@@ -342,18 +340,18 @@ fn remove_many() {
{ {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
let edits = dom.render_immediate().santize(); let edits = dom.render_immediate_to_vec().santize();
assert_eq!( assert_eq!(
edits.edits, edits.edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(1,) }, LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
HydrateText { path: &[0,], value: "hello 1", id: ElementId(4,) }, HydrateText { path: &[0,], value: "hello 1".to_string(), id: ElementId(4,) },
LoadTemplate { name: "template", index: 0, id: ElementId(5,) }, LoadTemplate { name: "template", index: 0, id: ElementId(5,) },
HydrateText { path: &[0,], value: "hello 2", id: ElementId(6,) }, HydrateText { path: &[0,], value: "hello 2".to_string(), id: ElementId(6,) },
LoadTemplate { name: "template", index: 0, id: ElementId(7,) }, LoadTemplate { name: "template", index: 0, id: ElementId(7,) },
HydrateText { path: &[0,], value: "hello 3", id: ElementId(8,) }, HydrateText { path: &[0,], value: "hello 3".to_string(), id: ElementId(8,) },
LoadTemplate { name: "template", index: 0, id: ElementId(9,) }, LoadTemplate { name: "template", index: 0, id: ElementId(9,) },
HydrateText { path: &[0,], value: "hello 4", id: ElementId(10,) }, HydrateText { path: &[0,], value: "hello 4".to_string(), id: ElementId(10,) },
InsertAfter { id: ElementId(2,), m: 4 }, InsertAfter { id: ElementId(2,), m: 4 },
] ]
); );
@@ -361,7 +359,7 @@ fn remove_many() {
{ {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
let edits = dom.render_immediate().santize(); let edits = dom.render_immediate_to_vec().santize();
assert_eq!( assert_eq!(
edits.edits, edits.edits,
[ [
@@ -377,12 +375,12 @@ fn remove_many() {
{ {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
let edits = dom.render_immediate().santize(); let edits = dom.render_immediate_to_vec().santize();
assert_eq!( assert_eq!(
edits.edits, edits.edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(2,) }, LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
HydrateText { path: &[0,], value: "hello 0", id: ElementId(3,) }, HydrateText { path: &[0,], value: "hello 0".to_string(), id: ElementId(3,) },
ReplaceWith { id: ElementId(11,), m: 1 }, ReplaceWith { id: ElementId(11,), m: 1 },
] ]
) )
+4 -6
View File
@@ -5,18 +5,18 @@ use dioxus::prelude::*;
#[test] #[test]
fn catches_panic() { fn catches_panic() {
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
} }
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
cx.render(rsx! { render! {
div { div {
h1 { "Title" } h1 { "Title" }
NoneChild {} NoneChild {}
ThrowChild {} ThrowChild {}
} }
}) }
} }
fn NoneChild(_cx: Scope) -> Element { fn NoneChild(_cx: Scope) -> Element {
@@ -28,7 +28,5 @@ fn ThrowChild(cx: Scope) -> Element {
let _g: i32 = "123123".parse().throw()?; let _g: i32 = "123123".parse().throw()?;
cx.render(rsx! { render! { div {} }
div {}
})
} }
+3 -3
View File
@@ -9,7 +9,7 @@ fn events_propagate() {
set_event_converter(Box::new(dioxus_html::SerializedHtmlEventConverter)); set_event_converter(Box::new(dioxus_html::SerializedHtmlEventConverter));
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
// Top-level click is registered // Top-level click is registered
dom.handle_event( dom.handle_event(
@@ -23,7 +23,7 @@ fn events_propagate() {
// break reference.... // break reference....
for _ in 0..5 { for _ in 0..5 {
dom.mark_dirty(ScopeId(0)); dom.mark_dirty(ScopeId(0));
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
// Lower click is registered // Lower click is registered
@@ -38,7 +38,7 @@ fn events_propagate() {
// break reference.... // break reference....
for _ in 0..5 { for _ in 0..5 {
dom.mark_dirty(ScopeId(0)); dom.mark_dirty(ScopeId(0));
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
// Stop propagation occurs // Stop propagation occurs
+3 -3
View File
@@ -311,7 +311,7 @@ fn create() {
for _ in 0..repeat_count { for _ in 0..repeat_count {
let mut vdom = let mut vdom =
VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true }); VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true });
let _ = vdom.rebuild(); let _ = vdom.rebuild_to_vec();
} }
} }
@@ -323,7 +323,7 @@ fn diff() {
for _ in 0..repeat_count { for _ in 0..repeat_count {
let mut vdom = let mut vdom =
VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true }); VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true });
let _ = vdom.rebuild(); let _ = vdom.rebuild_to_vec();
// A list of all elements that have had event listeners // A list of all elements that have had event listeners
// This is intentionally never cleared, so that we can test that calling event listeners that are removed doesn't cause a panic // This is intentionally never cleared, so that we can test that calling event listeners that are removed doesn't cause a panic
let mut event_listeners = HashSet::new(); let mut event_listeners = HashSet::new();
@@ -338,7 +338,7 @@ fn diff() {
); );
} }
{ {
let muts = vdom.render_immediate(); let muts = vdom.render_immediate_to_vec();
for mut_ in muts.edits { for mut_ in muts.edits {
if let Mutation::NewEventListener { name, id } = mut_ { if let Mutation::NewEventListener { name, id } = mut_ {
println!("new event listener on {:?} for {:?}", id, name); println!("new event listener on {:?} for {:?}", id, name);
+15 -13
View File
@@ -6,32 +6,34 @@ fn basic_syntax_is_a_template(cx: Scope) -> Element {
let asd = 123; let asd = 123;
let var = 123; let var = 123;
cx.render(rsx! { render! {
div { key: "12345", div { key: "12345", class: "asd", class: "{asd}", class: if true {
class: "asd", "{asd}"
class: "{asd}", }, class: if false {
class: if true { "{asd}" }, "{asd}"
class: if false { "{asd}" }, }, onclick: move |_| {},
onclick: move |_| {},
div { "{var}" } div { "{var}" }
div { div {
h1 { "var" } h1 { "var" }
p { "you're great!" } p { "you're great!" }
div { background_color: "red", div { background_color: "red",
h1 { "var" } h1 { "var" }
div { b { "asd" } "not great" } div {
b { "asd" }
"not great"
}
} }
p { "you're great!" } p { "you're great!" }
} }
} }
}) }
} }
#[test] #[test]
fn dual_stream() { fn dual_stream() {
let mut dom = VirtualDom::new(basic_syntax_is_a_template); let mut dom = VirtualDom::new(basic_syntax_is_a_template);
let bump = Bump::new(); let bump = Bump::new();
let edits = dom.rebuild().santize(); let edits = dom.rebuild_to_vec().santize();
use Mutation::*; use Mutation::*;
assert_eq!(edits.edits, { assert_eq!(edits.edits, {
@@ -39,12 +41,12 @@ fn dual_stream() {
LoadTemplate { name: "template", index: 0, id: ElementId(1) }, LoadTemplate { name: "template", index: 0, id: ElementId(1) },
SetAttribute { SetAttribute {
name: "class", name: "class",
value: (&*bump.alloc("asd 123 123".into_value(&bump))).into(), value: "asd 123 123".into_value(),
id: ElementId(1), id: ElementId(1),
ns: None, ns: None,
}, },
NewEventListener { name: "click", id: ElementId(1) }, NewEventListener { name: "click".to_string(), id: ElementId(1) },
HydrateText { path: &[0, 0], value: "123", id: ElementId(2) }, HydrateText { path: &[0, 0], value: "123".to_string(), id: ElementId(2) },
AppendChildren { id: ElementId(0), m: 1 }, AppendChildren { id: ElementId(0), m: 1 },
] ]
}); });
+12 -12
View File
@@ -18,21 +18,21 @@ fn manual_diffing() {
fn app(cx: Scope<AppProps>) -> Element { fn app(cx: Scope<AppProps>) -> Element {
let val = cx.props.value.lock().unwrap(); let val = cx.props.value.lock().unwrap();
cx.render(rsx! { div { "{val}" } }) render! { div { "{val}" } }
}; };
let value = Arc::new(Mutex::new("Hello")); let value = Arc::new(Mutex::new("Hello"));
let mut dom = VirtualDom::new_with_props(app, AppProps { value: value.clone() }); let mut dom = VirtualDom::new_with_props(app, AppProps { value: value.clone() });
let _ = dom.rebuild(&mut dioxus_core::NoOpMutations); let _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
*value.lock().unwrap() = "goodbye"; *value.lock().unwrap() = "goodbye";
assert_eq!( assert_eq!(
dom.rebuild().santize().edits, dom.rebuild_to_vec().santize().edits,
[ [
LoadTemplate { name: "template", index: 0, id: ElementId(3) }, LoadTemplate { name: "template", index: 0, id: ElementId(3) },
HydrateText { path: &[0], value: "goodbye", id: ElementId(4) }, HydrateText { path: &[0], value: "goodbye".to_string(), id: ElementId(4) },
AppendChildren { m: 1, id: ElementId(0) } AppendChildren { m: 1, id: ElementId(0) }
] ]
); );
@@ -45,18 +45,18 @@ fn events_generate() {
let count = cx.use_hook(|| 0); let count = cx.use_hook(|| 0);
match *count { match *count {
0 => cx.render(rsx! { 0 => render! {
div { onclick: move |_| *count += 1, div { onclick: move |_| *count += 1,
div { "nested" } div { "nested" }
"Click me!" "Click me!"
} }
}), },
_ => cx.render(rsx!(())), _ => render!(()),
} }
}; };
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.handle_event( dom.handle_event(
"click", "click",
@@ -66,7 +66,7 @@ fn events_generate() {
); );
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
let edits = dom.render_immediate(); let edits = dom.render_immediate_to_vec();
assert_eq!( assert_eq!(
edits.edits, edits.edits,
@@ -83,7 +83,7 @@ fn events_generate() {
// let render_phase = cx.use_hook(|| 0); // let render_phase = cx.use_hook(|| 0);
// *render_phase += 1; // *render_phase += 1;
// cx.render(match *render_phase { // match *render_phase {
// 1 => rsx_without_templates!("Text0"), // 1 => rsx_without_templates!("Text0"),
// 2 => rsx_without_templates!(div {}), // 2 => rsx_without_templates!(div {}),
// 3 => rsx_without_templates!("Text2"), // 3 => rsx_without_templates!("Text2"),
@@ -98,13 +98,13 @@ fn events_generate() {
// fn Child(cx: Scope) -> Element { // fn Child(cx: Scope) -> Element {
// println!("Running child"); // println!("Running child");
// cx.render(rsx_without_templates! { // render_without_templates! {
// h1 {} // h1 {}
// }) // })
// } // }
// let mut dom = VirtualDom::new(app); // let mut dom = VirtualDom::new(app);
// let edits = dom.rebuild(); // let edits = dom.rebuild_to_vec();
// assert_eq!( // assert_eq!(
// edits.edits, // edits.edits,
// [ // [
+6 -11
View File
@@ -9,7 +9,7 @@ fn miri_rollover() {
set_event_converter(Box::new(SerializedHtmlEventConverter)); set_event_converter(Box::new(SerializedHtmlEventConverter));
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
for _ in 0..3 { for _ in 0..3 {
dom.handle_event( dom.handle_event(
@@ -19,7 +19,7 @@ fn miri_rollover() {
true, true,
); );
dom.process_events(); dom.process_events();
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
} }
@@ -28,7 +28,7 @@ fn App(cx: Scope) -> Element {
let mut idx = use_state(cx, || 0); let mut idx = use_state(cx, || 0);
let onhover = |_| println!("go!"); let onhover = |_| println!("go!");
cx.render(rsx! { render! {
div { div {
button { button {
onclick: move |_| { onclick: move |_| {
@@ -39,20 +39,15 @@ fn App(cx: Scope) -> Element {
} }
button { onclick: move |_| idx -= 1, "-" } button { onclick: move |_| idx -= 1, "-" }
ul { ul {
(0..**idx).map(|i| rsx! { (0..**idx).map(|i| render! {
ChildExample { i: i, onhover: onhover } ChildExample { i: i, onhover: onhover }
}) })
} }
} }
}) }
} }
#[component] #[component]
fn ChildExample<'a>(cx: Scope<'a>, i: i32, onhover: EventHandler<'a, MouseEvent>) -> Element { fn ChildExample<'a>(cx: Scope<'a>, i: i32, onhover: EventHandler<'a, MouseEvent>) -> Element {
cx.render(rsx! { render! { li { onmouseover: move |e| onhover.call(e), "{i}" } }
li {
onmouseover: move |e| onhover.call(e),
"{i}"
}
})
} }
+27 -37
View File
@@ -4,16 +4,14 @@ use dioxus::prelude::*;
fn app_drops() { fn app_drops() {
#[component] #[component]
fn App(cx: Scope) -> Element { fn App(cx: Scope) -> Element {
cx.render(rsx! { render! { div {} }
div {}
})
} }
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
#[test] #[test]
@@ -25,16 +23,14 @@ fn hooks_drop() {
cx.use_hook(|| String::from("asd")); cx.use_hook(|| String::from("asd"));
cx.use_hook(|| String::from("asd")); cx.use_hook(|| String::from("asd"));
cx.render(rsx! { render! { div {} }
div {}
})
} }
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
#[test] #[test]
@@ -43,27 +39,23 @@ fn contexts_drop() {
fn App(cx: Scope) -> Element { fn App(cx: Scope) -> Element {
cx.provide_context(String::from("asd")); cx.provide_context(String::from("asd"));
cx.render(rsx! { render! {
div { div { ChildComp {} }
ChildComp {} }
}
})
} }
#[component] #[component]
fn ChildComp(cx: Scope) -> Element { fn ChildComp(cx: Scope) -> Element {
let el = cx.consume_context::<String>().unwrap(); let el = cx.consume_context::<String>().unwrap();
cx.render(rsx! { render! { div { "hello {el}" } }
div { "hello {el}" }
})
} }
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
#[test] #[test]
@@ -74,16 +66,14 @@ fn tasks_drop() {
// tokio::time::sleep(std::time::Duration::from_millis(100000)).await; // tokio::time::sleep(std::time::Duration::from_millis(100000)).await;
}); });
cx.render(rsx! { render! { div {} }
div { }
})
} }
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
#[test] #[test]
@@ -91,43 +81,43 @@ fn root_props_drop() {
struct RootProps(String); struct RootProps(String);
let mut dom = VirtualDom::new_with_props( let mut dom = VirtualDom::new_with_props(
|cx| cx.render(rsx!( div { "{cx.props.0}" } )), |cx| render!( div { "{cx.props.0}" } ),
RootProps("asdasd".to_string()), RootProps("asdasd".to_string()),
); );
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
#[test] #[test]
fn diffing_drops_old() { fn diffing_drops_old() {
#[component] #[component]
fn App(cx: Scope) -> Element { fn App(cx: Scope) -> Element {
cx.render(rsx! { render! {
div { div {
match cx.generation() % 2 { match generation() % 2 {
0 => rsx!( ChildComp1 { name: "asdasd".to_string() }), 0 => render!( ChildComp1 { name: "asdasd".to_string() }),
1 => rsx!( ChildComp2 { name: "asdasd".to_string() }), 1 => render!( ChildComp2 { name: "asdasd".to_string() }),
_ => todo!() _ => todo!()
} }
} }
}) }
} }
#[component] #[component]
fn ChildComp1(cx: Scope, name: String) -> Element { fn ChildComp1(cx: Scope, name: String) -> Element {
cx.render(rsx! { "Hello {name}" }) render! {"Hello {name}"}
} }
#[component] #[component]
fn ChildComp2(cx: Scope, name: String) -> Element { fn ChildComp2(cx: Scope, name: String) -> Element {
cx.render(rsx! { "Goodbye {name}" }) render! {"Goodbye {name}"}
} }
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
+26 -46
View File
@@ -10,19 +10,19 @@ use dioxus::prelude::*;
#[test] #[test]
fn test_memory_leak() { fn test_memory_leak() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let val = cx.generation(); let val = generation();
cx.spawn(async {}); cx.spawn(async {});
if val == 2 || val == 4 { if val == 2 || val == 4 {
return cx.render(rsx!(())); return render!(());
} }
let name = cx.use_hook(|| String::from("numbers: ")); let name = cx.use_hook(|| String::from("numbers: "));
name.push_str("123 "); name.push_str("123 ");
cx.render(rsx!( render!(
div { "Hello, world!" } div { "Hello, world!" }
Child {} Child {}
Child {} Child {}
@@ -35,7 +35,7 @@ fn test_memory_leak() {
BorrowedChild { name: name } BorrowedChild { name: name }
BorrowedChild { name: name } BorrowedChild { name: name }
BorrowedChild { name: name } BorrowedChild { name: name }
)) )
} }
#[derive(Props)] #[derive(Props)]
@@ -44,44 +44,44 @@ fn test_memory_leak() {
} }
fn BorrowedChild<'a>(cx: Scope<'a, BorrowedProps<'a>>) -> Element { fn BorrowedChild<'a>(cx: Scope<'a, BorrowedProps<'a>>) -> Element {
cx.render(rsx! { render! {
div { div {
"goodbye {cx.props.name}" "goodbye {cx.props.name}"
Child {} Child {}
Child {} Child {}
} }
}) }
} }
fn Child(cx: Scope) -> Element { fn Child(cx: Scope) -> Element {
render!(div { "goodbye world" }) render!( div { "goodbye world" } )
} }
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
for _ in 0..5 { for _ in 0..5 {
dom.mark_dirty(ScopeId::ROOT); dom.mark_dirty(ScopeId::ROOT);
_ = dom.render_immediate(); _ = dom.render_immediate_to_vec();
} }
} }
#[test] #[test]
fn memo_works_properly() { fn memo_works_properly() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let val = cx.generation(); let val = generation();
if val == 2 || val == 4 { if val == 2 || val == 4 {
return cx.render(rsx!(())); return render!(());
} }
let name = cx.use_hook(|| String::from("asd")); let name = cx.use_hook(|| String::from("asd"));
cx.render(rsx!( render!(
div { "Hello, world! {name}" } div { "Hello, world! {name}" }
Child { na: "asdfg".to_string() } Child { na: "asdfg".to_string() }
)) )
} }
#[derive(PartialEq, Props)] #[derive(PartialEq, Props)]
@@ -90,12 +90,12 @@ fn memo_works_properly() {
} }
fn Child(cx: Scope<ChildProps>) -> Element { fn Child(cx: Scope<ChildProps>) -> Element {
render!(div { "goodbye world" }) render!( div { "goodbye world" } )
} }
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
// todo!() // todo!()
// dom.hard_diff(ScopeId::ROOT); // dom.hard_diff(ScopeId::ROOT);
// dom.hard_diff(ScopeId::ROOT); // dom.hard_diff(ScopeId::ROOT);
@@ -122,12 +122,12 @@ fn free_works_on_root_hooks() {
} }
fn child_component(cx: Scope<AppProps>) -> Element { fn child_component(cx: Scope<AppProps>) -> Element {
render!(div { "{cx.props.inner}" }) render!( div { "{cx.props.inner}" } )
} }
let ptr = Rc::new("asdasd".to_string()); let ptr = Rc::new("asdasd".to_string());
let mut dom = VirtualDom::new_with_props(app, AppProps { inner: ptr.clone() }); let mut dom = VirtualDom::new_with_props(app, AppProps { inner: ptr.clone() });
let _ = dom.rebuild(&mut dioxus_core::NoOpMutations); let _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
// ptr gets cloned into props and then into the hook // ptr gets cloned into props and then into the hook
assert_eq!(Rc::strong_count(&ptr), 4); assert_eq!(Rc::strong_count(&ptr), 4);
@@ -166,35 +166,15 @@ fn supports_async() {
let mid = colors[1]; let mid = colors[1];
let small = colors[2]; let small = colors[2];
cx.render(rsx! { render! {
div { div { background: "{big}", height: "stretch", width: "stretch", padding: "50",
background: "{big}", label { "hello" }
height: "stretch", div { background: "{mid}", height: "auto", width: "stretch", padding: "{padding}",
width: "stretch", label { "World" }
padding: "50", div { background: "{small}", height: "auto", width: "stretch", padding: "20", label { "ddddddd" } }
label {
"hello",
} }
div {
background: "{mid}",
height: "auto",
width: "stretch",
padding: "{padding}",
label {
"World",
}
div {
background: "{small}",
height: "auto",
width: "stretch",
padding: "20",
label {
"ddddddd",
}
}
},
} }
}) }
} }
let rt = tokio::runtime::Builder::new_current_thread() let rt = tokio::runtime::Builder::new_current_thread()
@@ -204,11 +184,11 @@ fn supports_async() {
rt.block_on(async { rt.block_on(async {
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
let _ = dom.rebuild(&mut dioxus_core::NoOpMutations); let _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
for _ in 0..10 { for _ in 0..10 {
dom.wait_for_work().await; dom.wait_for_work().await;
let _edits = dom.render_immediate(); let _edits = dom.render_immediate_to_vec();
} }
}); });
} }
+1 -1
View File
@@ -2,7 +2,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
/// Ensure no issues with not calling rebuild /// Ensure no issues with not calling rebuild_to_vec
#[test] #[test]
fn root_node_isnt_null() { fn root_node_isnt_null() {
let dom = VirtualDom::new(|cx| render!("Hello world!")); let dom = VirtualDom::new(|cx| render!("Hello world!"));
+3 -3
View File
@@ -9,7 +9,7 @@ fn it_works() {
.unwrap() .unwrap()
.block_on(async { .block_on(async {
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
_ = dom.rebuild(&mut dioxus_core::NoOpMutations); _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
dom.wait_for_suspense().await; dom.wait_for_suspense().await;
let out = dioxus_ssr::render(&dom); let out = dioxus_ssr::render(&dom);
@@ -20,12 +20,12 @@ fn it_works() {
} }
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
cx.render(rsx!( render!(
div { div {
"Waiting for... " "Waiting for... "
suspended_child {} suspended_child {}
} }
)) )
} }
fn suspended_child(cx: Scope) -> Element { fn suspended_child(cx: Scope) -> Element {
+2 -2
View File
@@ -25,12 +25,12 @@ async fn it_works() {
}); });
}); });
cx.render(rsx!(())) render!(())
} }
let mut dom = VirtualDom::new(app); let mut dom = VirtualDom::new(app);
let _ = dom.rebuild(&mut dioxus_core::NoOpMutations); let _ = dom.rebuild_to_vec(&mut dioxus_core::NoOpMutations);
tokio::select! { tokio::select! {
_ = dom.wait_for_work() => {} _ = dom.wait_for_work() => {}
@@ -300,7 +300,7 @@ fn persist_removes() {
use dioxus::prelude::*; use dioxus::prelude::*;
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn Base(cx: Scope) -> Element { fn Base(cx: Scope) -> Element {
let children = match cx.generation() % 2 { let children = match generation() % 2 {
0 => 3, 0 => 3,
1 => 2, 1 => 2,
_ => unreachable!(), _ => unreachable!(),
@@ -381,7 +381,7 @@ fn persist_instertions_before() {
use dioxus::prelude::*; use dioxus::prelude::*;
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn Base(cx: Scope) -> Element { fn Base(cx: Scope) -> Element {
let children = match cx.generation() % 2 { let children = match generation() % 2 {
0 => 3, 0 => 3,
1 => 2, 1 => 2,
_ => unreachable!(), _ => unreachable!(),
@@ -439,7 +439,7 @@ fn persist_instertions_after() {
use dioxus::prelude::*; use dioxus::prelude::*;
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn Base(cx: Scope) -> Element { fn Base(cx: Scope) -> Element {
let children = match cx.generation() % 2 { let children = match generation() % 2 {
0 => 3, 0 => 3,
1 => 2, 1 => 2,
_ => unreachable!(), _ => unreachable!(),
+1 -1
View File
@@ -56,7 +56,7 @@ fn deref_signal() {
#[test] #[test]
fn drop_signals() { fn drop_signals() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {
let generation = cx.generation(); let generation = generation();
let count = if generation % 2 == 0 { 10 } else { 0 }; let count = if generation % 2 == 0 { 10 } else { 0 };
render! { render! {
+3 -3
View File
@@ -65,10 +65,10 @@ fn memos_prevents_component_rerun() {
|cx| { |cx| {
let mut signal = use_signal(cx, || 0); let mut signal = use_signal(cx, || 0);
if cx.generation() == 1 { if generation() == 1 {
*signal.write() = 0; *signal.write() = 0;
} }
if cx.generation() == 2 { if generation() == 2 {
println!("Writing to signal"); println!("Writing to signal");
*signal.write() = 1; *signal.write() = 1;
} }
@@ -108,7 +108,7 @@ fn memos_prevents_component_rerun() {
signal.value() signal.value()
}) })
}); });
match cx.generation() { match generation() {
0 => { 0 => {
assert_eq!(memo.value(), 0); assert_eq!(memo.value(), 0);
} }
+1 -1
View File
@@ -22,7 +22,7 @@ fn reading_subscribes() {
let mut signal = use_signal(cx, || 0); let mut signal = use_signal(cx, || 0);
println!("Parent: {:?}", cx.scope_id()); println!("Parent: {:?}", cx.scope_id());
if cx.generation() == 1 { if generation() == 1 {
signal += 1; signal += 1;
} }