diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs
index b2d9b0c0a..6f9277aa1 100644
--- a/packages/core/src/diff.rs
+++ b/packages/core/src/diff.rs
@@ -77,9 +77,12 @@
//! More info on how to improve this diffing algorithm:
//! -
-use crate::innerlude::{
- AnyProps, ElementId, Renderer, ScopeArena, ScopeId, TemplateNode, VComponent, VElement,
- VFragment, VNode, VTemplate, VText,
+use crate::{
+ innerlude::{
+ AnyProps, ElementId, Renderer, ScopeArena, ScopeId, TemplateNode, VComponent, VElement,
+ VFragment, VNode, VTemplate, VText,
+ },
+ AttributeValue,
};
use fxhash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec};
@@ -119,7 +122,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
}
pub fn diff_node(&mut self, old_node: &'b VNode<'b>, new_node: &'b VNode<'b>) {
- use VNode::{Component, Element, Fragment, Template, Text};
+ use VNode::{Component, Element, Fragment, Placeholder, Template, Text};
match (old_node, new_node) {
(Text(old), Text(new)) => {
self.diff_text_nodes(old, new, old_node, new_node);
@@ -141,9 +144,13 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
self.diff_templates(old, new, old_node, new_node);
}
+ (Placeholder(_), Placeholder(_)) => {
+ self.diff_placeholder_nodes(old_node, new_node);
+ }
+
(
- Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_),
- Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_),
+ Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_) | Placeholder(_),
+ Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_) | Placeholder(_),
) => self.replace_node(old_node, new_node),
}
}
@@ -155,6 +162,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
VNode::Fragment(frag) => self.create_fragment_node(*frag),
VNode::Component(component) => self.create_component_node(*component),
VNode::Template(template) => self.create_template_node(template, node),
+ VNode::Placeholder(placeholder) => todo!(),
}
}
@@ -195,7 +203,8 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
}
for attr in attributes.iter() {
- self.mutations.set_attribute(attr, real_id);
+ self.mutations
+ .set_attribute(attr.name, attr.value, attr.namespace, real_id);
}
if !children.is_empty() {
@@ -303,23 +312,90 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
for (left, right) in old.dynamic_nodes.iter().zip(new.dynamic_nodes.iter()) {
self.diff_node(left, right);
}
+
+ // todo: need a way to load up the element bound to these attributes
+ for (left, right) in old.dynamic_attrs.iter().zip(new.dynamic_attrs.iter()) {
+ //
+ }
+
+ // hmm, what we do here?
+ for (left, right) in old.listeners.iter().zip(new.listeners.iter()) {
+ //
+ }
} else {
// else, diff them manually, taking the slow path
self.replace_node(old_node, new_node);
}
}
+ fn create_static_template_nodes(&mut self, node: &'b TemplateNode) {
+ let id = ElementId(999999);
+ match node {
+ TemplateNode::Element {
+ tag,
+ attrs,
+ children,
+ } => {
+ self.mutations.create_element(tag, None, id);
+
+ for attr in *attrs {
+ match attr {
+ crate::TemplateAttribute::Dynamic(_) => todo!(),
+ crate::TemplateAttribute::Static { name, value } => {
+ self.mutations.set_attribute(
+ name,
+ AttributeValue::Text(value),
+ None,
+ id,
+ );
+ }
+ }
+ }
+
+ for child in children.iter() {
+ self.create_static_template_nodes(child);
+ }
+ self.mutations.append_children(children.len() as u32);
+ }
+ TemplateNode::Text(ref text) => self.mutations.create_text_node(text, id),
+ TemplateNode::Dynamic(_) => self.mutations.create_placeholder(id),
+ }
+ }
+
/// Create the template from scratch using instructions, cache it, and then use the instructions to build it
- fn create_template_node(
- &mut self,
- template: &'b VTemplate<'b>,
- temp_node: &'b VNode<'b>,
- ) -> usize {
- /*
- - Use a document fragment for holding nodes
- - Assign IDs to any root nodes so we can find them later for shuffling around
- - Build dynamic nodes in reverse order so indexing is preserved
- */
+ fn create_template_node(&mut self, template: &'b VTemplate<'b>, node: &'b VNode<'b>) -> usize {
+ let template_id = template.template.id;
+ let templates = self.scopes.template_cache.borrow_mut();
+
+ // create and insert the template if it doesn't exist within the VirtualDom (it won't exist on the renderer either)
+ if !templates.contains(&template.template) {
+ template
+ .template
+ .roots
+ .into_iter()
+ .for_each(|node| self.create_static_template_nodes(node));
+
+ self.mutations
+ .save(template_id, template.template.roots.len() as u32);
+ }
+
+ self.mutations.load(template_id);
+
+ let mut created = 0;
+
+ // create the dynamic nodes
+ for node in template.dynamic_nodes.iter() {
+ created += self.create_node(node);
+ }
+
+ // set any dynamic attributes
+ for attr in template.dynamic_attrs.iter() {
+ // assign an ID to the element
+ let id = self.scopes.reserve_node(node);
+
+ self.mutations
+ .set_attribute(attr.name, attr.value, attr.namespace, id);
+ }
todo!()
@@ -357,7 +433,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
// nodes_created
}
- fn create_template_static_node(&mut self, nodes: &'static [TemplateNode]) -> usize {
+ fn create_template_static_node(&mut self, nodes: &'static [VNode<'static>]) -> usize {
todo!()
// let mut created = 0;
// for node in nodes {
@@ -442,7 +518,12 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
if old.attributes.len() == new.attributes.len() {
for (old_attr, new_attr) in old.attributes.iter().zip(new.attributes.iter()) {
if old_attr.value != new_attr.value || new_attr.volatile {
- self.mutations.set_attribute(new_attr, root);
+ self.mutations.set_attribute(
+ new_attr.name,
+ new_attr.value,
+ new_attr.namespace,
+ root,
+ );
}
}
} else {
@@ -450,7 +531,12 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
self.mutations.remove_attribute(attribute, root);
}
for attribute in new.attributes {
- self.mutations.set_attribute(attribute, root);
+ self.mutations.set_attribute(
+ attribute.name,
+ attribute.value,
+ attribute.namespace,
+ root,
+ );
}
}
@@ -1000,7 +1086,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
self.scopes.collect_garbage(id);
}
- VNode::Text(_) => {
+ VNode::Text(_) | VNode::Placeholder(_) => {
let id = old
.try_mounted_id()
.unwrap_or_else(|| panic!("broke on {:?}", old));
@@ -1059,15 +1145,15 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
}
}
}
- // VNode::Placeholder(a) => {
- // let id = a.id.get().unwrap();
- // self.scopes.collect_garbage(id);
- // a.id.set(None);
+ VNode::Placeholder(a) => {
+ let id = a.id.get().unwrap();
+ self.scopes.collect_garbage(id);
+ a.id.set(None);
- // if gen_muts {
- // self.mutations.remove(id);
- // }
- // }
+ if gen_muts {
+ self.mutations.remove(id);
+ }
+ }
VNode::Element(e) => {
let id = e.id.get().unwrap();
@@ -1157,6 +1243,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
VNode::Template(c) => {
todo!()
}
+ VNode::Placeholder(_) => todo!(),
}
}
}
@@ -1175,6 +1262,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
VNode::Template(t) => {
todo!()
}
+ VNode::Placeholder(_) => todo!(),
}
}
}
@@ -1182,7 +1270,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
// recursively push all the nodes of a tree onto the stack and return how many are there
fn push_all_real_nodes(&mut self, node: &'b VNode<'b>) -> usize {
match node {
- VNode::Text(_) | VNode::Element(_) => {
+ VNode::Text(_) | VNode::Element(_) | VNode::Placeholder(_) => {
self.mutations.push_root(node.mounted_id());
1
}
@@ -1205,4 +1293,8 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
}
}
}
+
+ pub(crate) fn diff_placeholder_nodes(&self, old_node: &VNode, new_node: &VNode) {
+ todo!()
+ }
}
diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs
index 3213c05b8..c909e11f7 100644
--- a/packages/core/src/lib.rs
+++ b/packages/core/src/lib.rs
@@ -59,7 +59,7 @@ pub(crate) mod innerlude {
}
pub use crate::innerlude::{
- AnyEvent, ArbitraryAttributeValue, Attribute, AttributeValue, Component, Element, ElementId,
+ AnyAttributeValue, AnyEvent, Attribute, AttributeValue, Component, Element, ElementId,
EventHandler, EventPriority, IntoVNode, LazyNodes, Listener, NodeFactory, Properties, Renderer,
SchedulerMsg, Scope, ScopeId, ScopeState, TaskId, Template, TemplateAttribute, TemplateNode,
UiEvent, UserEvent, VComponent, VElement, VNode, VTemplate, VText, VirtualDom,
diff --git a/packages/core/src/mutations.rs b/packages/core/src/mutations.rs
index 1bb768d72..2c347f24d 100644
--- a/packages/core/src/mutations.rs
+++ b/packages/core/src/mutations.rs
@@ -50,7 +50,13 @@ pub trait Renderer<'a> {
/// Set the text content of a node
fn set_text(&mut self, text: &'a str, root: ElementId);
/// Set an attribute on an element
- fn set_attribute(&mut self, attribute: &'a Attribute<'a>, root: ElementId);
+ fn set_attribute(
+ &mut self,
+ name: &'static str,
+ value: AttributeValue<'a>,
+ namespace: Option<&'a str>,
+ root: ElementId,
+ );
/// Save the current n nodes to the ID to be loaded later
fn save(&mut self, id: &str, num: u32);
diff --git a/packages/core/src/nodes/arbitrary_value.rs b/packages/core/src/nodes/arbitrary_value.rs
index 4b3e44c53..f9590f208 100644
--- a/packages/core/src/nodes/arbitrary_value.rs
+++ b/packages/core/src/nodes/arbitrary_value.rs
@@ -4,19 +4,28 @@ use std::{
};
use bumpalo::Bump;
-use serde::{Deserialize, Serialize};
/// Possible values for an attribute
-// trying to keep values at 3 bytes
-#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serialize", serde(untagged))]
-#[derive(Clone, PartialEq)]
-#[allow(missing_docs)]
+#[derive(Clone, Copy)]
pub enum AttributeValue<'a> {
Text(&'a str),
Float32(f32),
Bool(bool),
- Any(ArbitraryAttributeValue<'a>),
+ Any(&'a dyn AnyAttributeValue),
+}
+
+// #[cfg(feature = "serialize")]
+
+impl<'a> PartialEq for AttributeValue<'a> {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Self::Text(l0), Self::Text(r0)) => l0 == r0,
+ (Self::Float32(l0), Self::Float32(r0)) => l0 == r0,
+ (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
+ // (Self::Any(l0), Self::Any(r0)) => l0.cmp(r0),
+ _ => false,
+ }
+ }
}
impl<'a> Display for AttributeValue<'a> {
@@ -112,61 +121,25 @@ impl<'a> AttributeValue<'a> {
}
}
-#[derive(Clone, Copy)]
-#[allow(missing_docs)]
-pub struct ArbitraryAttributeValue<'a> {
- pub value: &'a dyn Any,
- // pub value: &'a dyn AnyClone,
- // pub cmp: fn(&dyn AnyClone, &dyn AnyClone) -> bool,
-}
-
-#[cfg(feature = "serialize")]
-impl<'a> Serialize for ArbitraryAttributeValue<'a> {
- fn serialize(&self, serializer: S) -> Result
- where
- S: serde::Serializer,
- {
- todo!()
- }
-}
-#[cfg(feature = "serialize")]
-impl<'a, 'de> Deserialize<'de> for ArbitraryAttributeValue<'a> {
- fn deserialize(deserializer: D) -> Result
- where
- D: serde::Deserializer<'de>,
- {
- todo!()
+/// A trait that allows for comparing two values of the same type through the Any trait
+///
+/// Defaults to false if the types are not the same
+///
+/// This is an implicit trait, so any value that is 'static and PartialEq can be used directly
+///
+/// If you want to override the default behavior, you should implement PartialEq through a wrapper type
+pub trait AnyAttributeValue: Any {
+ /// Perform a comparison between two values
+ fn cmp_any(&self, _other: &dyn Any) -> bool {
+ false
}
}
-impl PartialEq for ArbitraryAttributeValue<'_> {
- fn eq(&self, other: &Self) -> bool {
- todo!()
- // (self.cmp)(self.value, other.value)
- }
-}
-
-// todo
-#[allow(missing_docs)]
-impl<'a> AttributeValue<'a> {
- pub fn as_text(&self) -> Option<&'a str> {
- match self {
- AttributeValue::Text(s) => Some(s),
- _ => None,
- }
- }
-
- pub fn as_float32(&self) -> Option {
- match self {
- AttributeValue::Float32(f) => Some(*f),
- _ => None,
- }
- }
-
- pub fn as_any(&self) -> Option<&'a ArbitraryAttributeValue> {
- match self {
- AttributeValue::Any(a) => Some(a),
- _ => None,
+impl AnyAttributeValue for T {
+ fn cmp_any(&self, other: &dyn Any) -> bool {
+ match other.downcast_ref::() {
+ Some(t) => self == t,
+ None => false,
}
}
}
diff --git a/packages/core/src/nodes/element.rs b/packages/core/src/nodes/element.rs
index 88e537ae4..11aeb7327 100644
--- a/packages/core/src/nodes/element.rs
+++ b/packages/core/src/nodes/element.rs
@@ -70,6 +70,10 @@ pub struct Attribute<'a> {
/// Used in controlled components to ensure changes are propagated.
pub volatile: bool,
+ /// A reverse lookup for tracking down attributes for templates
+ /// Not used for anything else
+ pub mounted_node: Cell