wip: more modifications to templates

This commit is contained in:
Jonathan Kelley 2022-10-21 18:54:14 -07:00
parent 90982e0ccb
commit 7cbb4d52dd
16 changed files with 342 additions and 1520 deletions

View file

@ -77,9 +77,12 @@
//! More info on how to improve this diffing algorithm: //! More info on how to improve this diffing algorithm:
//! - <https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/> //! - <https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/>
use crate::innerlude::{ use crate::{
AnyProps, ElementId, Renderer, ScopeArena, ScopeId, TemplateNode, VComponent, VElement, innerlude::{
VFragment, VNode, VTemplate, VText, AnyProps, ElementId, Renderer, ScopeArena, ScopeId, TemplateNode, VComponent, VElement,
VFragment, VNode, VTemplate, VText,
},
AttributeValue,
}; };
use fxhash::{FxHashMap, FxHashSet}; use fxhash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec}; 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>) { 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) { match (old_node, new_node) {
(Text(old), Text(new)) => { (Text(old), Text(new)) => {
self.diff_text_nodes(old, new, old_node, new_node); 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); 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(_) | Placeholder(_),
Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_), Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_) | Placeholder(_),
) => self.replace_node(old_node, new_node), ) => 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::Fragment(frag) => self.create_fragment_node(*frag),
VNode::Component(component) => self.create_component_node(*component), VNode::Component(component) => self.create_component_node(*component),
VNode::Template(template) => self.create_template_node(template, node), 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() { 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() { 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()) { for (left, right) in old.dynamic_nodes.iter().zip(new.dynamic_nodes.iter()) {
self.diff_node(left, right); 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 {
// else, diff them manually, taking the slow path // else, diff them manually, taking the slow path
self.replace_node(old_node, new_node); 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 /// Create the template from scratch using instructions, cache it, and then use the instructions to build it
fn create_template_node( fn create_template_node(&mut self, template: &'b VTemplate<'b>, node: &'b VNode<'b>) -> usize {
&mut self, let template_id = template.template.id;
template: &'b VTemplate<'b>, let templates = self.scopes.template_cache.borrow_mut();
temp_node: &'b VNode<'b>,
) -> usize { // 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) {
- Use a document fragment for holding nodes template
- Assign IDs to any root nodes so we can find them later for shuffling around .template
- Build dynamic nodes in reverse order so indexing is preserved .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!() todo!()
@ -357,7 +433,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
// nodes_created // 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!() todo!()
// let mut created = 0; // let mut created = 0;
// for node in nodes { // 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() { if old.attributes.len() == new.attributes.len() {
for (old_attr, new_attr) in old.attributes.iter().zip(new.attributes.iter()) { for (old_attr, new_attr) in old.attributes.iter().zip(new.attributes.iter()) {
if old_attr.value != new_attr.value || new_attr.volatile { 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 { } else {
@ -450,7 +531,12 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
self.mutations.remove_attribute(attribute, root); self.mutations.remove_attribute(attribute, root);
} }
for attribute in new.attributes { 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); self.scopes.collect_garbage(id);
} }
VNode::Text(_) => { VNode::Text(_) | VNode::Placeholder(_) => {
let id = old let id = old
.try_mounted_id() .try_mounted_id()
.unwrap_or_else(|| panic!("broke on {:?}", old)); .unwrap_or_else(|| panic!("broke on {:?}", old));
@ -1059,15 +1145,15 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
} }
} }
} }
// VNode::Placeholder(a) => { VNode::Placeholder(a) => {
// let id = a.id.get().unwrap(); let id = a.id.get().unwrap();
// self.scopes.collect_garbage(id); self.scopes.collect_garbage(id);
// a.id.set(None); a.id.set(None);
// if gen_muts { if gen_muts {
// self.mutations.remove(id); self.mutations.remove(id);
// } }
// } }
VNode::Element(e) => { VNode::Element(e) => {
let id = e.id.get().unwrap(); let id = e.id.get().unwrap();
@ -1157,6 +1243,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
VNode::Template(c) => { VNode::Template(c) => {
todo!() todo!()
} }
VNode::Placeholder(_) => todo!(),
} }
} }
} }
@ -1175,6 +1262,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
VNode::Template(t) => { VNode::Template(t) => {
todo!() 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 // 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 { fn push_all_real_nodes(&mut self, node: &'b VNode<'b>) -> usize {
match node { match node {
VNode::Text(_) | VNode::Element(_) => { VNode::Text(_) | VNode::Element(_) | VNode::Placeholder(_) => {
self.mutations.push_root(node.mounted_id()); self.mutations.push_root(node.mounted_id());
1 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!()
}
} }

View file

@ -59,7 +59,7 @@ pub(crate) mod innerlude {
} }
pub use crate::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, EventHandler, EventPriority, IntoVNode, LazyNodes, Listener, NodeFactory, Properties, Renderer,
SchedulerMsg, Scope, ScopeId, ScopeState, TaskId, Template, TemplateAttribute, TemplateNode, SchedulerMsg, Scope, ScopeId, ScopeState, TaskId, Template, TemplateAttribute, TemplateNode,
UiEvent, UserEvent, VComponent, VElement, VNode, VTemplate, VText, VirtualDom, UiEvent, UserEvent, VComponent, VElement, VNode, VTemplate, VText, VirtualDom,

View file

@ -50,7 +50,13 @@ pub trait Renderer<'a> {
/// Set the text content of a node /// Set the text content of a node
fn set_text(&mut self, text: &'a str, root: ElementId); fn set_text(&mut self, text: &'a str, root: ElementId);
/// Set an attribute on an element /// 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 /// Save the current n nodes to the ID to be loaded later
fn save(&mut self, id: &str, num: u32); fn save(&mut self, id: &str, num: u32);

View file

@ -4,19 +4,28 @@ use std::{
}; };
use bumpalo::Bump; use bumpalo::Bump;
use serde::{Deserialize, Serialize};
/// Possible values for an attribute /// Possible values for an attribute
// trying to keep values at 3 bytes #[derive(Clone, Copy)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", serde(untagged))]
#[derive(Clone, PartialEq)]
#[allow(missing_docs)]
pub enum AttributeValue<'a> { pub enum AttributeValue<'a> {
Text(&'a str), Text(&'a str),
Float32(f32), Float32(f32),
Bool(bool), 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> { impl<'a> Display for AttributeValue<'a> {
@ -112,61 +121,25 @@ impl<'a> AttributeValue<'a> {
} }
} }
#[derive(Clone, Copy)] /// A trait that allows for comparing two values of the same type through the Any trait
#[allow(missing_docs)] ///
pub struct ArbitraryAttributeValue<'a> { /// Defaults to false if the types are not the same
pub value: &'a dyn Any, ///
// pub value: &'a dyn AnyClone, /// This is an implicit trait, so any value that is 'static and PartialEq can be used directly
// pub cmp: fn(&dyn AnyClone, &dyn AnyClone) -> bool, ///
} /// If you want to override the default behavior, you should implement PartialEq through a wrapper type
pub trait AnyAttributeValue: Any {
#[cfg(feature = "serialize")] /// Perform a comparison between two values
impl<'a> Serialize for ArbitraryAttributeValue<'a> { fn cmp_any(&self, _other: &dyn Any) -> bool {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> false
where
S: serde::Serializer,
{
todo!()
}
}
#[cfg(feature = "serialize")]
impl<'a, 'de> Deserialize<'de> for ArbitraryAttributeValue<'a> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
todo!()
} }
} }
impl PartialEq for ArbitraryAttributeValue<'_> { impl<T: Any + PartialEq> AnyAttributeValue for T {
fn eq(&self, other: &Self) -> bool { fn cmp_any(&self, other: &dyn Any) -> bool {
todo!() match other.downcast_ref::<T>() {
// (self.cmp)(self.value, other.value) Some(t) => self == t,
} None => false,
}
// 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<f32> {
match self {
AttributeValue::Float32(f) => Some(*f),
_ => None,
}
}
pub fn as_any(&self) -> Option<&'a ArbitraryAttributeValue> {
match self {
AttributeValue::Any(a) => Some(a),
_ => None,
} }
} }
} }

View file

@ -70,6 +70,10 @@ pub struct Attribute<'a> {
/// Used in controlled components to ensure changes are propagated. /// Used in controlled components to ensure changes are propagated.
pub volatile: bool, pub volatile: bool,
/// A reverse lookup for tracking down attributes for templates
/// Not used for anything else
pub mounted_node: Cell<Option<ElementId>>,
/// The value of the attribute. /// The value of the attribute.
pub value: AttributeValue<'a>, pub value: AttributeValue<'a>,
} }

View file

@ -35,7 +35,6 @@ impl<'a> NodeFactory<'a> {
VNode::Text(self.bump.alloc(VText { VNode::Text(self.bump.alloc(VText {
id: Default::default(), id: Default::default(),
text, text,
is_static: true,
})) }))
} }
@ -57,11 +56,10 @@ impl<'a> NodeFactory<'a> {
/// Create some text that's allocated along with the other vnodes /// Create some text that's allocated along with the other vnodes
/// ///
pub fn text(&self, args: Arguments) -> VNode<'a> { pub fn text(&self, args: Arguments) -> VNode<'a> {
let (text, is_static) = self.raw_text(args); let (text, _is_static) = self.raw_text(args);
VNode::Text(self.bump.alloc(VText { VNode::Text(self.bump.alloc(VText {
text, text,
is_static,
id: Default::default(), id: Default::default(),
})) }))
} }
@ -110,6 +108,7 @@ impl<'a> NodeFactory<'a> {
name, name,
namespace, namespace,
volatile: is_volatile, volatile: is_volatile,
mounted_node: Default::default(),
value: val.into_value(self.bump), value: val.into_value(self.bump),
} }
} }
@ -126,6 +125,7 @@ impl<'a> NodeFactory<'a> {
name, name,
namespace, namespace,
volatile: is_volatile, volatile: is_volatile,
mounted_node: Default::default(),
value, value,
} }
} }
@ -234,7 +234,7 @@ impl<'a> NodeFactory<'a> {
/// Create a refrence to a template /// Create a refrence to a template
pub fn template_ref( pub fn template_ref(
&self, &self,
template: Template, template: fn() -> Template<'static>,
nodes: &'a [VNode<'a>], nodes: &'a [VNode<'a>],
attributes: &'a [Attribute<'a>], attributes: &'a [Attribute<'a>],
listeners: &'a [Listener<'a>], listeners: &'a [Listener<'a>],

View file

@ -5,11 +5,13 @@
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
mod Placeholder;
mod arbitrary_value; mod arbitrary_value;
mod component; mod component;
mod element; mod element;
mod factory; mod factory;
mod fragment; mod fragment;
mod placeholder;
mod suspense; mod suspense;
mod template; mod template;
mod text; mod text;
@ -23,6 +25,8 @@ pub use suspense::*;
pub use template::*; pub use template::*;
pub use text::*; pub use text::*;
use self::Placeholder::VPlaceholder;
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM. /// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
/// ///
/// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of: /// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
@ -113,6 +117,9 @@ pub enum VNode<'src> {
/// ///
/// ///
Template(&'src VTemplate<'src>), Template(&'src VTemplate<'src>),
///
Placeholder(&'src VPlaceholder),
} }
/// An Element's unique identifier. /// An Element's unique identifier.
@ -131,8 +138,9 @@ impl<'src> VNode<'src> {
VNode::Element(el) => el.key, VNode::Element(el) => el.key,
VNode::Component(c) => c.key, VNode::Component(c) => c.key,
VNode::Fragment(f) => f.key, VNode::Fragment(f) => f.key,
VNode::Text(_t) => None,
VNode::Template(t) => t.key, VNode::Template(t) => t.key,
VNode::Text(_t) => None,
VNode::Placeholder(_p) => None,
} }
} }
@ -153,6 +161,7 @@ impl<'src> VNode<'src> {
VNode::Fragment(_) => None, VNode::Fragment(_) => None,
VNode::Component(_) => None, VNode::Component(_) => None,
VNode::Template(_) => None, VNode::Template(_) => None,
VNode::Placeholder(el) => el.id.get(),
} }
} }
@ -164,6 +173,7 @@ impl<'src> VNode<'src> {
VNode::Component(c) => VNode::Component(c), VNode::Component(c) => VNode::Component(c),
VNode::Fragment(f) => VNode::Fragment(f), VNode::Fragment(f) => VNode::Fragment(f),
VNode::Template(t) => VNode::Template(t), VNode::Template(t) => VNode::Template(t),
VNode::Placeholder(p) => VNode::Placeholder(p),
} }
} }
} }
@ -199,6 +209,10 @@ impl Debug for VNode<'_> {
.debug_struct("VNode::Templates") .debug_struct("VNode::Templates")
.field("template_id", &temp.template.id) .field("template_id", &temp.template.id)
.finish(), .finish(),
VNode::Placeholder(place) => s
.debug_struct("VNode::Placeholder")
.field("id", &place.id)
.finish(),
} }
} }
} }

View file

@ -0,0 +1,8 @@
use std::cell::Cell;
use crate::ElementId;
pub struct VPlaceholder {
pub id: Cell<Option<ElementId>>,
pub dynamic_index: Option<usize>,
}

View file

@ -1,6 +1,6 @@
use std::hash::Hash; use std::hash::Hash;
use crate::{Attribute, ElementId, Listener, VNode}; use crate::{Attribute, Listener, VNode};
/// A reference to a template along with any context needed to hydrate it /// A reference to a template along with any context needed to hydrate it
pub struct VTemplate<'a> { pub struct VTemplate<'a> {
@ -43,18 +43,15 @@ impl<'a> Hash for Template<'a> {
pub enum TemplateNode<'a> { pub enum TemplateNode<'a> {
Element { Element {
tag: &'static str, tag: &'static str,
attrs: &'a [TemplateAttribute], attrs: &'a [TemplateAttribute<'a>],
children: &'a [TemplateNode<'a>], children: &'a [TemplateNode<'a>],
}, },
Text(&'static str), Text(&'static str),
Dynamic(usize), Dynamic(usize),
} }
pub enum TemplateAttribute { pub enum TemplateAttribute<'a> {
// todo: more values // todo: more values
Static { Static { name: &'static str, value: &'a str },
name: &'static str,
value: &'static str,
},
Dynamic(usize), Dynamic(usize),
} }

View file

@ -18,8 +18,4 @@ pub struct VText<'src> {
/// The text of the VText. /// The text of the VText.
pub text: &'src str, pub text: &'src str,
/// An indiciation if this VText can be ignored during diffing
/// Is usually only when there are no strings to be formatted (so the text is &'static str)
pub is_static: bool,
} }

View file

@ -306,7 +306,6 @@ impl ScopeArena {
let node = frame.bump.alloc(VNode::Text(frame.bump.alloc(VText { let node = frame.bump.alloc(VNode::Text(frame.bump.alloc(VText {
id: Cell::default(), id: Cell::default(),
text: "asd", text: "asd",
is_static: false,
}))); })));
frame.node.set(unsafe { extend_vnode(node) }); frame.node.set(unsafe { extend_vnode(node) });
} }
@ -943,7 +942,6 @@ impl BumpFrame {
let node = bump.alloc(VText { let node = bump.alloc(VText {
text: "placeholdertext", text: "placeholdertext",
id: Cell::default(), id: Cell::default(),
is_static: false,
}); });
let node = bump.alloc(VNode::Text(unsafe { let node = bump.alloc(VNode::Text(unsafe {
&*(node as *mut VText as *const VText) &*(node as *mut VText as *const VText)
@ -957,7 +955,6 @@ impl BumpFrame {
let node = self.bump.alloc(VText { let node = self.bump.alloc(VText {
text: "placeholdertext", text: "placeholdertext",
id: Cell::default(), id: Cell::default(),
is_static: false,
}); });
let node = self.bump.alloc(VNode::Text(unsafe { let node = self.bump.alloc(VNode::Text(unsafe {
&*(node as *mut VText as *const VText) &*(node as *mut VText as *const VText)

View file

@ -1,17 +1,87 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core::{Attribute, TemplateAttribute};
#[test] fn basic_syntax_is_a_template(cx: Scope) -> Element {
fn basic_syntax_is_a_template() {
//
let var = 123;
let asd = 123; let asd = 123;
let g = rsx! { let g = rsx! {
div { div {
class: "asd", class: "asd",
class: "{asd}", // class: "{asd}",
onclick: move |_| {}, // onclick: move |_| {},
div { "{var}" } // div { "{var}" }
} }
}; };
let __cx = NodeFactory::new(&cx);
static attrs: &'static [TemplateAttribute<'static>] =
&[::dioxus::core::TemplateAttribute::Static(
::dioxus::core::Attribute {
name: "class",
namespace: None,
volatile: false,
mounted_node: Default::default(),
value: ::dioxus::core::AttributeValue::Text("asd"),
},
)];
__cx . template_ref (
|| :: dioxus :: core :: Template {
id : "packages/dioxus/tests/rsx_syntax.rs:7:13:/Users/jonkelley/Development/dioxus/packages/dioxus" ,
roots : &[
:: dioxus :: core :: TemplateNode :: Element {
tag : dioxus_elements :: div :: TAG_NAME ,
attrs : attrs,
children : & [] ,
}] ,
} ,
__cx . bump () . alloc ([]) , __cx . bump () . alloc ([]) , __cx . bump () . alloc ([]) ,
None
);
// let static_attr = ::dioxus::core::TemplateAttribute::Static(::dioxus::core::Attribute {
// name: "class",
// namespace: None,
// volatile: false,
// mounted_node: Default::default(),
// value: ::dioxus::core::AttributeValue::Text("asd"),
// });
// __cx . template_ref (|| :: dioxus :: core :: Template { id : "packages/dioxus/tests/rsx_syntax.rs:7:13:/Users/jonkelley/Development/dioxus/packages/dioxus" , roots : & [:: dioxus :: core :: TemplateNode :: Element { tag : dioxus_elements :: div :: TAG_NAME , attrs : & [static_attr , :: dioxus :: core :: TemplateAttribute :: Dynamic (0usize)] , children : & [] , }] , } , __cx . bump () . alloc ([]) , __cx . bump () . alloc ([__cx . attr (dioxus_elements :: div :: class . 0 , :: core :: fmt :: Arguments :: new_v1 (& [""] , & [:: core :: fmt :: ArgumentV1 :: new_display (& asd)]) , None , false)]) , __cx . bump () . alloc ([]) , None);
cx.render(g)
// let __cx = NodeFactory::new(&cx);
// let t = __cx.template_ref (
// || :: dioxus :: core :: Template {
// id : "packages/dioxus/tests/rsx_syntax.rs:8:13:/Users/jonkelley/Development/dioxus/packages/dioxus" ,
// roots : & [
// :: dioxus :: core :: TemplateNode :: Element {
// tag : dioxus_elements :: div :: TAG_NAME ,
// attrs : & [:: dioxus :: core :: TemplateAttribute :: Dynamic (0usize)] ,
// children : & [] ,
// }
// ],
// },
// &[] ,
// {
// let mut arr = dioxus_core::exports::bumpalo::vec![in __cx.bump()];
// arr.push(Attribute {
// name: "asd",
// namespace: None,
// volatile: false,
// mounted_node: Default::default(),
// value: dioxus_core::AttributeValue::Text(
// __cx.raw_text(format_args!("{asd}")).0
// ),
// });
// arr.into_bump_slice() as &[::dioxus::core::Attribute]
// },
// & [] ,
// None
// );
// Some(t)
} }

View file

@ -244,22 +244,42 @@ impl ToTokens for ElementAttrNamed {
tokens.append_all(match attr { tokens.append_all(match attr {
ElementAttr::AttrText { name, value } => { ElementAttr::AttrText { name, value } => {
quote! { quote! {
__cx.attr_disciption( dioxus_elements::#el_name::#name, #value) __cx.attr(
dioxus_elements::#el_name::#name.0,
#value,
None,
false
)
} }
} }
ElementAttr::AttrExpression { name, value } => { ElementAttr::AttrExpression { name, value } => {
quote! { quote! {
__cx.attr_disciption( dioxus_elements::#el_name::#name, #value) __cx.attr(
dioxus_elements::#el_name::#name.0,
#value,
None,
false
)
} }
} }
ElementAttr::CustomAttrText { name, value } => { ElementAttr::CustomAttrText { name, value } => {
quote! { quote! {
__cx.attr( #name, #value, None, false ) __cx.attr(
dioxus_elements::#el_name::#name.0,
#value,
None,
false
)
} }
} }
ElementAttr::CustomAttrExpression { name, value } => { ElementAttr::CustomAttrExpression { name, value } => {
quote! { quote! {
__cx.attr( #name, #value, None, false ) __cx.attr(
dioxus_elements::#el_name::#name.0,
#value,
None,
false
)
} }
} }
ElementAttr::EventTokens { name, tokens } => { ElementAttr::EventTokens { name, tokens } => {
@ -270,3 +290,11 @@ impl ToTokens for ElementAttrNamed {
}); });
} }
} }
// ::dioxus::core::Attribute {
// name: stringify!(#name),
// namespace: None,
// volatile: false,
// mounted_node: Default::default(),
// value: ::dioxus::core::AttributeValue::Text(#value),
// }

File diff suppressed because it is too large Load diff

View file

@ -67,7 +67,7 @@ impl Parse for CallBody {
impl ToTokens for CallBody { impl ToTokens for CallBody {
fn to_tokens(&self, out_tokens: &mut TokenStream2) { fn to_tokens(&self, out_tokens: &mut TokenStream2) {
// As we print out the dynamic nodes, we want to keep track of them in a linear fashion // As we print out the dynamic nodes, we want to keep track of them in a linear fashion
// We'll use the size of the vecs to determine the index of the dynamic node in the final output // We'll use the size of the vecs to determine the index of the dynamic node in the final
struct DynamicContext<'a> { struct DynamicContext<'a> {
dynamic_nodes: Vec<&'a BodyNode>, dynamic_nodes: Vec<&'a BodyNode>,
dynamic_attributes: Vec<&'a ElementAttrNamed>, dynamic_attributes: Vec<&'a ElementAttrNamed>,
@ -95,11 +95,28 @@ impl ToTokens for CallBody {
match &attr.attr { match &attr.attr {
ElementAttr::AttrText { name, value } if value.is_static() => { ElementAttr::AttrText { name, value } if value.is_static() => {
let value = value.source.as_ref().unwrap(); let value = value.source.as_ref().unwrap();
quote! { ::dioxus::core::TemplateAttribute::Static { name: stringify!(#name), value: #value } } quote! {
::dioxus::core::TemplateAttribute::Static(::dioxus::core::Attribute {
name: stringify!(#name),
namespace: None,
volatile: false,
mounted_node: Default::default(),
value: ::dioxus::core::AttributeValue::Text(#value),
})
}
} }
ElementAttr::CustomAttrText { name, value } if value.is_static() => { ElementAttr::CustomAttrText { name, value } if value.is_static() => {
quote! { ::dioxus::core::TemplateAttribute::Static { name: #name, value: #value } } let value = value.source.as_ref().unwrap();
quote! {
::dioxus::core::TemplateAttribute::Static(::dioxus::core::Attribute {
name: stringify!(#name),
namespace: None,
volatile: false,
mounted_node: Default::default(),
value: ::dioxus::core::AttributeValue::Text(#value),
})
}
}, },
ElementAttr::AttrExpression { .. } ElementAttr::AttrExpression { .. }
@ -155,16 +172,20 @@ impl ToTokens for CallBody {
out_tokens.append_all(quote! { out_tokens.append_all(quote! {
LazyNodes::new(move | __cx: ::dioxus::core::NodeFactory| -> ::dioxus::core::VNode { LazyNodes::new(move | __cx: ::dioxus::core::NodeFactory| -> ::dioxus::core::VNode {
static TEMPLATE: ::dioxus::core::Template = ::dioxus::core::Template {
id: ::dioxus::core::get_line_num!(),
roots: &[ #roots ]
};
__cx.template_ref( __cx.template_ref(
TEMPLATE, || ::dioxus::core::Template {
&[ #( #dyn_printer ),* ], id: ::dioxus::core::get_line_num!(),
&[ #( #attr_printer ),* ], roots: &[ #roots ]
&[ #( #listener_printer ),* ], },
__cx.bump().alloc([
#( #dyn_printer ),*
]),
__cx.bump().alloc([
#( #attr_printer ),*
]),
__cx.bump().alloc([
#( #listener_printer ),*
]),
None None
) )
}) })

View file

@ -237,6 +237,9 @@ impl<'a: 'c, 'c> TextRenderer<'a, '_, 'c> {
panic!("Cannot render template without vdom"); panic!("Cannot render template without vdom");
} }
} }
VNode::Placeholder(_) => {
todo!()
}
} }
Ok(()) Ok(())
} }