mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 12:43:08 +00:00
wip: more modifications to templates
This commit is contained in:
parent
90982e0ccb
commit
7cbb4d52dd
16 changed files with 342 additions and 1520 deletions
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
|
|
@ -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>],
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
8
packages/core/src/nodes/placeholder.rs
Normal file
8
packages/core/src/nodes/placeholder.rs
Normal 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>,
|
||||
}
|
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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
|
||||
)
|
||||
})
|
||||
|
|
|
@ -237,6 +237,9 @@ impl<'a: 'c, 'c> TextRenderer<'a, '_, 'c> {
|
|||
panic!("Cannot render template without vdom");
|
||||
}
|
||||
}
|
||||
VNode::Placeholder(_) => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue