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:
//! - <https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/>
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!()
}
}

View file

@ -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,

View file

@ -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);

View file

@ -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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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!()
/// 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<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,
impl<T: Any + PartialEq> AnyAttributeValue for T {
fn cmp_any(&self, other: &dyn Any) -> bool {
match other.downcast_ref::<T>() {
Some(t) => self == t,
None => false,
}
}
}

View file

@ -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<Option<ElementId>>,
/// The value of the attribute.
pub value: AttributeValue<'a>,
}

View file

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

View file

@ -5,11 +5,13 @@
use std::fmt::{Debug, Formatter};
mod Placeholder;
mod arbitrary_value;
mod component;
mod element;
mod factory;
mod fragment;
mod placeholder;
mod suspense;
mod template;
mod text;
@ -23,6 +25,8 @@ pub use suspense::*;
pub use template::*;
pub use text::*;
use self::Placeholder::VPlaceholder;
/// 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:
@ -113,6 +117,9 @@ pub enum VNode<'src> {
///
///
Template(&'src VTemplate<'src>),
///
Placeholder(&'src VPlaceholder),
}
/// An Element's unique identifier.
@ -131,8 +138,9 @@ impl<'src> VNode<'src> {
VNode::Element(el) => el.key,
VNode::Component(c) => c.key,
VNode::Fragment(f) => f.key,
VNode::Text(_t) => None,
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::Component(_) => 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::Fragment(f) => VNode::Fragment(f),
VNode::Template(t) => VNode::Template(t),
VNode::Placeholder(p) => VNode::Placeholder(p),
}
}
}
@ -199,6 +209,10 @@ impl Debug for VNode<'_> {
.debug_struct("VNode::Templates")
.field("template_id", &temp.template.id)
.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 crate::{Attribute, ElementId, Listener, VNode};
use crate::{Attribute, Listener, VNode};
/// A reference to a template along with any context needed to hydrate it
pub struct VTemplate<'a> {
@ -43,18 +43,15 @@ impl<'a> Hash for Template<'a> {
pub enum TemplateNode<'a> {
Element {
tag: &'static str,
attrs: &'a [TemplateAttribute],
attrs: &'a [TemplateAttribute<'a>],
children: &'a [TemplateNode<'a>],
},
Text(&'static str),
Dynamic(usize),
}
pub enum TemplateAttribute {
pub enum TemplateAttribute<'a> {
// todo: more values
Static {
name: &'static str,
value: &'static str,
},
Static { name: &'static str, value: &'a str },
Dynamic(usize),
}

View file

@ -18,8 +18,4 @@ pub struct VText<'src> {
/// The text of the VText.
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 {
id: Cell::default(),
text: "asd",
is_static: false,
})));
frame.node.set(unsafe { extend_vnode(node) });
}
@ -943,7 +942,6 @@ impl BumpFrame {
let node = bump.alloc(VText {
text: "placeholdertext",
id: Cell::default(),
is_static: false,
});
let node = bump.alloc(VNode::Text(unsafe {
&*(node as *mut VText as *const VText)
@ -957,7 +955,6 @@ impl BumpFrame {
let node = self.bump.alloc(VText {
text: "placeholdertext",
id: Cell::default(),
is_static: false,
});
let node = self.bump.alloc(VNode::Text(unsafe {
&*(node as *mut VText as *const VText)

View file

@ -1,17 +1,87 @@
use dioxus::prelude::*;
use dioxus_core::{Attribute, TemplateAttribute};
#[test]
fn basic_syntax_is_a_template() {
//
let var = 123;
fn basic_syntax_is_a_template(cx: Scope) -> Element {
let asd = 123;
let g = rsx! {
div {
class: "asd",
class: "{asd}",
onclick: move |_| {},
div { "{var}" }
// class: "{asd}",
// onclick: move |_| {},
// 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 {
ElementAttr::AttrText { name, value } => {
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 } => {
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 } => {
quote! {
__cx.attr( #name, #value, None, false )
__cx.attr(
dioxus_elements::#el_name::#name.0,
#value,
None,
false
)
}
}
ElementAttr::CustomAttrExpression { name, value } => {
quote! {
__cx.attr( #name, #value, None, false )
__cx.attr(
dioxus_elements::#el_name::#name.0,
#value,
None,
false
)
}
}
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 {
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
// 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> {
dynamic_nodes: Vec<&'a BodyNode>,
dynamic_attributes: Vec<&'a ElementAttrNamed>,
@ -95,11 +95,28 @@ impl ToTokens for CallBody {
match &attr.attr {
ElementAttr::AttrText { name, value } if value.is_static() => {
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() => {
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 { .. }
@ -155,16 +172,20 @@ impl ToTokens for CallBody {
out_tokens.append_all(quote! {
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(
TEMPLATE,
&[ #( #dyn_printer ),* ],
&[ #( #attr_printer ),* ],
&[ #( #listener_printer ),* ],
|| ::dioxus::core::Template {
id: ::dioxus::core::get_line_num!(),
roots: &[ #roots ]
},
__cx.bump().alloc([
#( #dyn_printer ),*
]),
__cx.bump().alloc([
#( #attr_printer ),*
]),
__cx.bump().alloc([
#( #listener_printer ),*
]),
None
)
})

View file

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