Files
dioxus/packages/rsx/src/template.rs
T
Jon Kelley 8ea61e1b3e feat: simple iterators and conditionals in rsx (#564)
* feat: simple iterators

* fix: into_iter

* feat: add support for unterminated conditionasl

* fix: add tempalte mapping for helpers
2022-11-16 22:10:50 -08:00

1065 lines
43 KiB
Rust

// use proc_macro2::TokenStream;
// use quote::TokenStreamExt;
// use quote::{quote, ToTokens};
// use syn::{Expr, Ident, LitStr};
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// pub fn try_parse_template(
// rsx: &str,
// location: OwnedCodeLocation,
// previous_template: Option<DynamicTemplateContextBuilder>,
// ) -> Result<(OwnedTemplate, DynamicTemplateContextBuilder), Error> {
// use crate::CallBody;
// let call_body: CallBody =
// syn::parse_str(rsx).map_err(|e| Error::ParseError(ParseError::new(e, location.clone())))?;
// let mut template_builder = TemplateBuilder::from_roots_always(call_body.roots);
// if let Some(prev) = previous_template {
// template_builder = template_builder
// .try_switch_dynamic_context(prev)
// .ok_or_else(|| {
// Error::RecompileRequiredError(RecompileReason::Variable(
// "dynamic context updated".to_string(),
// ))
// })?;
// }
// let dyn_ctx = template_builder.dynamic_context.clone();
// Ok((template_builder.try_into_owned(&location)?, dyn_ctx))
// }
// use crate::{BodyNode, ElementAttr, FormattedSegment, Segment};
// struct TemplateElementBuilder {
// tag: Ident,
// attributes: Vec<TemplateAttributeBuilder>,
// children: Vec<TemplateNodeId>,
// listeners: Vec<usize>,
// locally_static: bool,
// }
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// type OwndedTemplateElement = TemplateElement<
// Vec<TemplateAttribute<OwnedAttributeValue>>,
// OwnedAttributeValue,
// Vec<TemplateNodeId>,
// Vec<usize>,
// >;
// impl TemplateElementBuilder {
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// fn try_into_owned(self, location: &OwnedCodeLocation) -> Result<OwndedTemplateElement, Error> {
// let Self {
// tag,
// attributes,
// children,
// listeners,
// ..
// } = self;
// let (element_tag, element_ns) =
// element_to_static_str(&tag.to_string()).ok_or_else(|| {
// Error::ParseError(ParseError::new(
// syn::Error::new(tag.span(), format!("unknown element: {}", tag)),
// location.clone(),
// ))
// })?;
// let mut owned_attributes = Vec::new();
// for a in attributes {
// owned_attributes.push(a.try_into_owned(location, element_tag, element_ns)?);
// }
// Ok(TemplateElement::new(
// element_tag,
// element_ns,
// owned_attributes,
// children,
// listeners,
// ))
// }
// }
// impl ToTokens for TemplateElementBuilder {
// fn to_tokens(&self, tokens: &mut TokenStream) {
// let Self {
// tag,
// attributes,
// children,
// listeners,
// ..
// } = self;
// let children = children.iter().map(|id| {
// let raw = id.0;
// quote! {TemplateNodeId(#raw)}
// });
// tokens.append_all(quote! {
// TemplateElement::new(
// dioxus_elements::#tag::TAG_NAME,
// dioxus_elements::#tag::NAME_SPACE,
// &[#(#attributes),*],
// &[#(#children),*],
// &[#(#listeners),*],
// )
// })
// }
// }
// enum AttributeName {
// Ident(Ident),
// Str(LitStr),
// }
// struct TemplateAttributeBuilder {
// element_tag: Ident,
// name: AttributeName,
// value: TemplateAttributeValue<OwnedAttributeValue>,
// }
// impl TemplateAttributeBuilder {
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// fn try_into_owned(
// self,
// location: &OwnedCodeLocation,
// element_tag: &'static str,
// element_ns: Option<&'static str>,
// ) -> Result<TemplateAttribute<OwnedAttributeValue>, Error> {
// let Self { name, value, .. } = self;
// let (name, span, literal) = match name {
// AttributeName::Ident(name) => (name.to_string(), name.span(), false),
// AttributeName::Str(name) => (name.value(), name.span(), true),
// };
// let (name, namespace, volatile) = attrbute_to_static_str(&name, element_tag, element_ns)
// .ok_or_else(|| {
// if literal {
// // literals will be captured when a full recompile is triggered
// Error::RecompileRequiredError(RecompileReason::Attribute(name.to_string()))
// } else {
// Error::ParseError(ParseError::new(
// syn::Error::new(span, format!("unknown attribute: {}", name)),
// location.clone(),
// ))
// }
// })?;
// let attribute = AttributeDiscription {
// name,
// namespace,
// volatile,
// };
// Ok(TemplateAttribute { value, attribute })
// }
// }
// impl ToTokens for TemplateAttributeBuilder {
// fn to_tokens(&self, tokens: &mut TokenStream) {
// let Self {
// element_tag,
// name,
// value,
// } = self;
// let value = match value {
// TemplateAttributeValue::Static(val) => {
// let val = match val {
// OwnedAttributeValue::Text(txt) => quote! {StaticAttributeValue::Text(#txt)},
// OwnedAttributeValue::Float32(f) => quote! {StaticAttributeValue::Float32(#f)},
// OwnedAttributeValue::Float64(f) => quote! {StaticAttributeValue::Float64(#f)},
// OwnedAttributeValue::Int32(i) => quote! {StaticAttributeValue::Int32(#i)},
// OwnedAttributeValue::Int64(i) => quote! {StaticAttributeValue::Int64(#i)},
// OwnedAttributeValue::Uint32(u) => quote! {StaticAttributeValue::Uint32(#u)},
// OwnedAttributeValue::Uint64(u) => quote! {StaticAttributeValue::Uint64(#u)},
// OwnedAttributeValue::Bool(b) => quote! {StaticAttributeValue::Bool(#b)},
// OwnedAttributeValue::Vec3Float(f1, f2, f3) => {
// quote! {StaticAttributeValue::Vec3Float(#f1, #f2, #f3)}
// }
// OwnedAttributeValue::Vec3Int(f1, f2, f3) => {
// quote! {StaticAttributeValue::Vec3Int(#f1, #f2, #f3)}
// }
// OwnedAttributeValue::Vec3Uint(f1, f2, f3) => {
// quote! {StaticAttributeValue::Vec3Uint(#f1, #f2, #f3)}
// }
// OwnedAttributeValue::Vec4Float(f1, f2, f3, f4) => {
// quote! {StaticAttributeValue::Vec4Float(#f1, #f2, #f3, #f4)}
// }
// OwnedAttributeValue::Vec4Int(f1, f2, f3, f4) => {
// quote! {StaticAttributeValue::Vec4Int(#f1, #f2, #f3, #f4)}
// }
// OwnedAttributeValue::Vec4Uint(f1, f2, f3, f4) => {
// quote! {StaticAttributeValue::Vec4Uint(#f1, #f2, #f3, #f4)}
// }
// OwnedAttributeValue::Bytes(b) => {
// quote! {StaticAttributeValue::Bytes(&[#(#b),*])}
// }
// OwnedAttributeValue::Any(_) => todo!(),
// };
// quote! {TemplateAttributeValue::Static(#val)}
// }
// TemplateAttributeValue::Dynamic(idx) => quote! {TemplateAttributeValue::Dynamic(#idx)},
// };
// match name {
// AttributeName::Ident(name) => tokens.append_all(quote! {
// TemplateAttribute{
// attribute: dioxus_elements::#element_tag::#name,
// value: #value,
// }
// }),
// AttributeName::Str(lit) => tokens.append_all(quote! {
// TemplateAttribute{
// attribute: dioxus::prelude::AttributeDiscription{
// name: #lit,
// namespace: None,
// volatile: false
// },
// value: #value,
// }
// }),
// }
// }
// }
// enum TemplateNodeTypeBuilder {
// Element(TemplateElementBuilder),
// Text(TextTemplate<Vec<TextTemplateSegment<String>>, String>),
// DynamicNode(usize),
// }
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// type OwnedTemplateNodeType = TemplateNodeType<
// Vec<TemplateAttribute<OwnedAttributeValue>>,
// OwnedAttributeValue,
// Vec<TemplateNodeId>,
// Vec<usize>,
// Vec<TextTemplateSegment<String>>,
// String,
// >;
// impl TemplateNodeTypeBuilder {
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// fn try_into_owned(self, location: &OwnedCodeLocation) -> Result<OwnedTemplateNodeType, Error> {
// match self {
// TemplateNodeTypeBuilder::Element(el) => {
// Ok(TemplateNodeType::Element(el.try_into_owned(location)?))
// }
// TemplateNodeTypeBuilder::Text(txt) => Ok(TemplateNodeType::Text(txt)),
// TemplateNodeTypeBuilder::DynamicNode(idx) => Ok(TemplateNodeType::DynamicNode(idx)),
// }
// }
// }
// impl ToTokens for TemplateNodeTypeBuilder {
// fn to_tokens(&self, tokens: &mut TokenStream) {
// match self {
// TemplateNodeTypeBuilder::Element(el) => tokens.append_all(quote! {
// TemplateNodeType::Element(#el)
// }),
// TemplateNodeTypeBuilder::Text(txt) => {
// let mut length = 0;
// let segments = txt.segments.iter().map(|seg| match seg {
// TextTemplateSegment::Static(s) => {
// length += s.len();
// quote!(TextTemplateSegment::Static(#s))
// }
// TextTemplateSegment::Dynamic(idx) => quote!(TextTemplateSegment::Dynamic(#idx)),
// });
// tokens.append_all(quote! {
// TemplateNodeType::Text(TextTemplate::new(&[#(#segments),*], #length))
// });
// }
// TemplateNodeTypeBuilder::DynamicNode(idx) => tokens.append_all(quote! {
// TemplateNodeType::DynamicNode(#idx)
// }),
// }
// }
// }
// struct TemplateNodeBuilder {
// id: TemplateNodeId,
// depth: usize,
// parent: Option<TemplateNodeId>,
// node_type: TemplateNodeTypeBuilder,
// fully_static: bool,
// }
// impl TemplateNodeBuilder {
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// fn try_into_owned(self, location: &OwnedCodeLocation) -> Result<OwnedTemplateNode, Error> {
// let TemplateNodeBuilder {
// id,
// node_type,
// parent,
// depth,
// ..
// } = self;
// let node_type = node_type.try_into_owned(location)?;
// Ok(OwnedTemplateNode {
// id,
// node_type,
// parent,
// depth,
// })
// }
// fn to_tokens(&self, tokens: &mut TokenStream) {
// let Self {
// id,
// node_type,
// parent,
// depth,
// ..
// } = self;
// let raw_id = id.0;
// let parent = match parent {
// Some(id) => {
// let id = id.0;
// quote! {Some(TemplateNodeId(#id))}
// }
// None => quote! {None},
// };
// tokens.append_all(quote! {
// TemplateNode {
// id: TemplateNodeId(#raw_id),
// node_type: #node_type,
// parent: #parent,
// depth: #depth,
// }
// })
// }
// }
// #[derive(Default)]
// pub struct TemplateBuilder {
// nodes: Vec<TemplateNodeBuilder>,
// root_nodes: Vec<TemplateNodeId>,
// dynamic_context: DynamicTemplateContextBuilder,
// }
// impl TemplateBuilder {
// /// Create a template builder from nodes if it would improve performance to do so.
// pub fn from_roots(roots: Vec<BodyNode>) -> Option<Self> {
// let mut builder = Self::default();
// for (i, root) in roots.into_iter().enumerate() {
// let id = builder.build_node(root, None, vec![i], 0);
// builder.root_nodes.push(id);
// }
// // only build a template if there is at least one static node
// if builder
// .nodes
// .iter()
// .all(|r| matches!(&r.node_type, TemplateNodeTypeBuilder::DynamicNode(_)))
// {
// None
// } else {
// Some(builder)
// }
// }
// /// Create a template builder from nodes regardless of performance.
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// fn from_roots_always(roots: Vec<BodyNode>) -> Self {
// let mut builder = Self::default();
// for (i, root) in roots.into_iter().enumerate() {
// let id = builder.build_node(root, None, vec![i], 0);
// builder.root_nodes.push(id);
// }
// builder
// }
// fn build_node(
// &mut self,
// node: BodyNode,
// parent: Option<TemplateNodeId>,
// path: Vec<usize>,
// depth: usize,
// ) -> TemplateNodeId {
// let id = TemplateNodeId(self.nodes.len());
// match node {
// BodyNode::Element(el) => {
// let mut locally_static = true;
// let mut attributes = Vec::new();
// let mut listeners = Vec::new();
// for attr in el.attributes {
// match attr.attr {
// ElementAttr::AttrText { name, value } => {
// if let Some(static_value) = value.to_static() {
// attributes.push(TemplateAttributeBuilder {
// element_tag: el.name.clone(),
// name: AttributeName::Ident(name),
// value: TemplateAttributeValue::Static(
// OwnedAttributeValue::Text(static_value),
// ),
// })
// } else {
// locally_static = false;
// attributes.push(TemplateAttributeBuilder {
// element_tag: el.name.clone(),
// name: AttributeName::Ident(name),
// value: TemplateAttributeValue::Dynamic(
// self.dynamic_context.add_attr(quote!(#value)),
// ),
// })
// }
// }
// ElementAttr::CustomAttrText { name, value } => {
// if let Some(static_value) = value.to_static() {
// attributes.push(TemplateAttributeBuilder {
// element_tag: el.name.clone(),
// name: AttributeName::Str(name),
// value: TemplateAttributeValue::Static(
// OwnedAttributeValue::Text(static_value),
// ),
// })
// } else {
// locally_static = false;
// attributes.push(TemplateAttributeBuilder {
// element_tag: el.name.clone(),
// name: AttributeName::Str(name),
// value: TemplateAttributeValue::Dynamic(
// self.dynamic_context.add_attr(quote!(#value)),
// ),
// })
// }
// }
// ElementAttr::AttrExpression { name, value } => {
// locally_static = false;
// attributes.push(TemplateAttributeBuilder {
// element_tag: el.name.clone(),
// name: AttributeName::Ident(name),
// value: TemplateAttributeValue::Dynamic(
// self.dynamic_context.add_attr(quote!(#value)),
// ),
// })
// }
// ElementAttr::CustomAttrExpression { name, value } => {
// locally_static = false;
// attributes.push(TemplateAttributeBuilder {
// element_tag: el.name.clone(),
// name: AttributeName::Str(name),
// value: TemplateAttributeValue::Dynamic(
// self.dynamic_context.add_attr(quote!(#value)),
// ),
// })
// }
// ElementAttr::EventTokens { name, tokens } => {
// locally_static = false;
// listeners.push(self.dynamic_context.add_listener(name, tokens))
// }
// }
// }
// if let Some(key) = el.key {
// self.dynamic_context.add_key(quote!(
// dioxus::core::exports::bumpalo::format!(in __bump, "{}", #key)
// .into_bump_str()
// ));
// }
// self.nodes.push(TemplateNodeBuilder {
// id,
// node_type: TemplateNodeTypeBuilder::Element(TemplateElementBuilder {
// tag: el.name,
// attributes,
// children: Vec::new(),
// listeners,
// locally_static,
// }),
// parent,
// depth,
// fully_static: false,
// });
// let children: Vec<_> = el
// .children
// .into_iter()
// .enumerate()
// .map(|(i, child)| {
// let mut new_path = path.clone();
// new_path.push(i);
// self.build_node(child, Some(id), new_path, depth + 1)
// })
// .collect();
// let children_fully_static = children.iter().all(|c| self.nodes[c.0].fully_static);
// let parent = &mut self.nodes[id.0];
// parent.fully_static = locally_static && children_fully_static;
// if let TemplateNodeTypeBuilder::Element(element) = &mut parent.node_type {
// element.children = children;
// }
// }
// BodyNode::Component(comp) => {
// self.nodes.push(TemplateNodeBuilder {
// id,
// node_type: TemplateNodeTypeBuilder::DynamicNode(
// self.dynamic_context.add_node(BodyNode::Component(comp)),
// ),
// parent,
// depth,
// fully_static: false,
// });
// }
// BodyNode::Text(txt) => {
// let mut segments = Vec::new();
// let mut length = 0;
// let mut fully_static = true;
// for segment in txt.segments {
// segments.push(match segment {
// Segment::Literal(lit) => {
// length += lit.len();
// TextTemplateSegment::Static(lit)
// }
// Segment::Formatted(fmted) => {
// fully_static = false;
// TextTemplateSegment::Dynamic(self.dynamic_context.add_text(fmted))
// }
// })
// }
// self.nodes.push(TemplateNodeBuilder {
// id,
// node_type: TemplateNodeTypeBuilder::Text(TextTemplate::new(segments, length)),
// parent,
// depth,
// fully_static,
// });
// }
// BodyNode::RawExpr(expr) => {
// self.nodes.push(TemplateNodeBuilder {
// id,
// node_type: TemplateNodeTypeBuilder::DynamicNode(
// self.dynamic_context.add_node(BodyNode::RawExpr(expr)),
// ),
// parent,
// depth,
// fully_static: false,
// });
// }
// }
// id
// }
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// pub fn try_switch_dynamic_context(
// mut self,
// dynamic_context: DynamicTemplateContextBuilder,
// ) -> Option<Self> {
// let attribute_mapping: HashMap<String, usize> = dynamic_context
// .attributes
// .iter()
// .enumerate()
// .map(|(i, ts)| (ts.to_string(), i))
// .collect();
// let text_mapping: HashMap<String, usize> = dynamic_context
// .text
// .iter()
// .enumerate()
// .map(|(i, ts)| (ts.to_token_stream().to_string(), i))
// .collect();
// let listener_mapping: HashMap<(String, Expr), usize> = dynamic_context
// .listeners
// .iter()
// .enumerate()
// .map(|(i, ts)| (ts.clone(), i))
// .collect();
// let node_mapping: HashMap<String, usize> = dynamic_context
// .nodes
// .iter()
// .enumerate()
// .map(|(i, ts)| (ts.to_token_stream().to_string(), i))
// .collect();
// for node in &mut self.nodes {
// match &mut node.node_type {
// TemplateNodeTypeBuilder::Element(element) => {
// for listener in &mut element.listeners {
// *listener =
// *listener_mapping.get(&self.dynamic_context.listeners[*listener])?;
// }
// for attribute in &mut element.attributes {
// if let TemplateAttributeValue::Dynamic(idx) = &mut attribute.value {
// *idx = *attribute_mapping
// .get(&self.dynamic_context.attributes[*idx].to_string())?;
// }
// }
// }
// TemplateNodeTypeBuilder::Text(txt) => {
// for seg in &mut txt.segments {
// if let TextTemplateSegment::Dynamic(idx) = seg {
// *idx = *text_mapping.get(
// &self.dynamic_context.text[*idx]
// .to_token_stream()
// .to_string(),
// )?;
// }
// }
// }
// TemplateNodeTypeBuilder::DynamicNode(idx) => {
// *idx = *node_mapping.get(
// &self.dynamic_context.nodes[*idx]
// .to_token_stream()
// .to_string(),
// )?;
// }
// }
// }
// self.dynamic_context = dynamic_context;
// Some(self)
// }
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// pub fn try_into_owned(self, location: &OwnedCodeLocation) -> Result<OwnedTemplate, Error> {
// let mut nodes = Vec::new();
// let dynamic_mapping = self.dynamic_mapping(&nodes);
// let dynamic_path = self.dynamic_path();
// for node in self.nodes {
// nodes.push(node.try_into_owned(location)?);
// }
// Ok(OwnedTemplate {
// nodes,
// root_nodes: self.root_nodes,
// dynamic_mapping,
// dynamic_path,
// })
// }
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// pub fn dynamic_mapping(
// &self,
// resolved_nodes: &Vec<OwnedTemplateNode>,
// ) -> OwnedDynamicNodeMapping {
// let dynamic_context = &self.dynamic_context;
// let mut node_mapping = vec![None; dynamic_context.nodes.len()];
// let nodes = &self.nodes;
// for n in nodes {
// if let TemplateNodeTypeBuilder::DynamicNode(idx) = &n.node_type {
// node_mapping[*idx] = Some(n.id)
// }
// }
// let mut text_mapping = vec![Vec::new(); dynamic_context.text.len()];
// for n in nodes {
// if let TemplateNodeTypeBuilder::Text(txt) = &n.node_type {
// for seg in &txt.segments {
// match seg {
// TextTemplateSegment::Static(_) => (),
// TextTemplateSegment::Dynamic(idx) => text_mapping[*idx].push(n.id),
// }
// }
// }
// }
// let mut attribute_mapping = vec![Vec::new(); dynamic_context.attributes.len()];
// for n in nodes {
// if let TemplateNodeTypeBuilder::Element(el) = &n.node_type {
// for (i, attr) in el.attributes.iter().enumerate() {
// match attr.value {
// TemplateAttributeValue::Static(_) => (),
// TemplateAttributeValue::Dynamic(idx) => {
// attribute_mapping[idx].push((n.id, i));
// }
// }
// }
// }
// }
// let mut listener_mapping = Vec::new();
// for n in nodes {
// if let TemplateNodeTypeBuilder::Element(el) = &n.node_type {
// if !el.listeners.is_empty() {
// listener_mapping.push(n.id);
// }
// }
// }
// let mut volatile_mapping = Vec::new();
// for n in resolved_nodes {
// if let TemplateNodeType::Element(el) = &n.node_type {
// for (i, attr) in el.attributes.iter().enumerate() {
// if attr.attribute.volatile {
// volatile_mapping.push((n.id, i));
// }
// }
// }
// }
// OwnedDynamicNodeMapping::new(
// node_mapping,
// text_mapping,
// attribute_mapping,
// volatile_mapping,
// listener_mapping,
// )
// }
// fn dynamic_path(&self) -> Option<OwnedPathSeg> {
// let mut last_seg: Option<OwnedPathSeg> = None;
// let mut nodes_to_insert_after = Vec::new();
// // iterating from the last root to the first
// for root in self.root_nodes.iter().rev() {
// let root_node = &self.nodes[root.0];
// if let TemplateNodeTypeBuilder::DynamicNode(_) = root_node.node_type {
// match &mut last_seg {
// // if there has been no static nodes, we can append the child to the parent node
// None => nodes_to_insert_after.push(*root),
// // otherwise we insert the child before the last static node
// Some(seg) => {
// seg.ops.push(UpdateOp::InsertBefore(*root));
// }
// }
// } else if let Some(mut new) = self.construct_path_segment(*root) {
// if let Some(last) = last_seg.take() {
// match new.traverse {
// OwnedTraverse::Halt => {
// new.traverse = OwnedTraverse::NextSibling(Box::new(last));
// }
// OwnedTraverse::FirstChild(b) => {
// new.traverse = OwnedTraverse::Both(Box::new((*b, last)));
// }
// _ => unreachable!(),
// }
// } else {
// for node in nodes_to_insert_after.drain(..) {
// new.ops.push(UpdateOp::InsertAfter(node));
// }
// }
// last_seg = Some(new);
// } else if let Some(last) = last_seg.take() {
// last_seg = Some(OwnedPathSeg {
// ops: Vec::new(),
// traverse: OwnedTraverse::NextSibling(Box::new(last)),
// });
// }
// }
// last_seg
// }
// fn construct_path_segment(&self, node_id: TemplateNodeId) -> Option<OwnedPathSeg> {
// let n = &self.nodes[node_id.0];
// if n.fully_static {
// return None;
// }
// match &n.node_type {
// TemplateNodeTypeBuilder::Element(el) => {
// let mut last_seg: Option<OwnedPathSeg> = None;
// let mut children_to_append = Vec::new();
// // iterating from the last child to the first
// for child in el.children.iter().rev() {
// let child_node = &self.nodes[child.0];
// if let TemplateNodeTypeBuilder::DynamicNode(_) = child_node.node_type {
// match &mut last_seg {
// // if there has been no static nodes, we can append the child to the parent node
// None => children_to_append.push(*child),
// // otherwise we insert the child before the last static node
// Some(seg) => {
// seg.ops.push(UpdateOp::InsertBefore(*child));
// }
// }
// } else if let Some(mut new) = self.construct_path_segment(*child) {
// if let Some(last) = last_seg.take() {
// match new.traverse {
// OwnedTraverse::Halt => {
// new.traverse = OwnedTraverse::NextSibling(Box::new(last));
// }
// OwnedTraverse::FirstChild(b) => {
// new.traverse = OwnedTraverse::Both(Box::new((*b, last)));
// }
// _ => unreachable!(),
// }
// }
// last_seg = Some(new);
// } else if let Some(last) = last_seg.take() {
// last_seg = Some(OwnedPathSeg {
// ops: Vec::new(),
// traverse: OwnedTraverse::NextSibling(Box::new(last)),
// });
// }
// }
// let mut ops = Vec::new();
// if !el.locally_static || n.parent.is_none() {
// ops.push(UpdateOp::StoreNode(node_id));
// }
// for child in children_to_append.into_iter().rev() {
// ops.push(UpdateOp::AppendChild(child));
// }
// Some(OwnedPathSeg {
// ops,
// traverse: match last_seg {
// Some(last) => OwnedTraverse::FirstChild(Box::new(last)),
// None => OwnedTraverse::Halt,
// },
// })
// }
// TemplateNodeTypeBuilder::Text(_) => Some(OwnedPathSeg {
// ops: vec![UpdateOp::StoreNode(n.id)],
// traverse: dioxus_core::OwnedTraverse::Halt,
// }),
// TemplateNodeTypeBuilder::DynamicNode(_) => unreachable!(
// "constructing path segment for dynamic nodes is handled in the parent node"
// ),
// }
// }
// }
// impl ToTokens for TemplateBuilder {
// fn to_tokens(&self, tokens: &mut TokenStream) {
// let Self {
// nodes,
// root_nodes,
// dynamic_context,
// } = self;
// let mut node_mapping = vec![None; dynamic_context.nodes.len()];
// for n in nodes {
// if let TemplateNodeTypeBuilder::DynamicNode(idx) = &n.node_type {
// node_mapping[*idx] = Some(n.id);
// }
// }
// let mut text_mapping = vec![Vec::new(); dynamic_context.text.len()];
// for n in nodes {
// if let TemplateNodeTypeBuilder::Text(txt) = &n.node_type {
// for seg in &txt.segments {
// match seg {
// TextTemplateSegment::Static(_) => (),
// TextTemplateSegment::Dynamic(idx) => text_mapping[*idx].push(n.id),
// }
// }
// }
// }
// let mut attribute_mapping = vec![Vec::new(); dynamic_context.attributes.len()];
// for n in nodes {
// if let TemplateNodeTypeBuilder::Element(el) = &n.node_type {
// for (i, attr) in el.attributes.iter().enumerate() {
// match attr.value {
// TemplateAttributeValue::Static(_) => (),
// TemplateAttributeValue::Dynamic(idx) => {
// attribute_mapping[idx].push((n.id, i));
// }
// }
// }
// }
// }
// let mut listener_mapping = Vec::new();
// for n in nodes {
// if let TemplateNodeTypeBuilder::Element(el) = &n.node_type {
// if !el.listeners.is_empty() {
// listener_mapping.push(n.id);
// }
// }
// }
// let root_nodes = root_nodes.iter().map(|id| {
// let raw = id.0;
// quote! { TemplateNodeId(#raw) }
// });
// let node_mapping_quoted = node_mapping.iter().map(|op| match op {
// Some(id) => {
// let raw_id = id.0;
// quote! {Some(TemplateNodeId(#raw_id))}
// }
// None => quote! {None},
// });
// let text_mapping_quoted = text_mapping.iter().map(|inner| {
// let raw = inner.iter().map(|id| id.0);
// quote! {&[#(TemplateNodeId(#raw)),*]}
// });
// let attribute_mapping_quoted = attribute_mapping.iter().map(|inner| {
// let raw = inner.iter().map(|(id, _)| id.0);
// let indecies = inner.iter().map(|(_, idx)| idx);
// quote! {&[#((TemplateNodeId(#raw), #indecies)),*]}
// });
// let listener_mapping_quoted = listener_mapping.iter().map(|id| {
// let raw = id.0;
// quote! {TemplateNodeId(#raw)}
// });
// let mut nodes_quoted = TokenStream::new();
// for n in nodes {
// n.to_tokens(&mut nodes_quoted);
// quote! {,}.to_tokens(&mut nodes_quoted);
// }
// let dynamic_path = match self.dynamic_path() {
// Some(seg) => {
// let seg = quote_owned_segment(seg);
// quote! {Some(#seg)}
// }
// None => quote! {None},
// };
// let quoted = quote! {
// {
// const __NODES: dioxus::prelude::StaticTemplateNodes = &[#nodes_quoted];
// const __TEXT_MAPPING: &'static [&'static [dioxus::prelude::TemplateNodeId]] = &[#(#text_mapping_quoted),*];
// const __ATTRIBUTE_MAPPING: &'static [&'static [(dioxus::prelude::TemplateNodeId, usize)]] = &[#(#attribute_mapping_quoted),*];
// const __ROOT_NODES: &'static [dioxus::prelude::TemplateNodeId] = &[#(#root_nodes),*];
// const __NODE_MAPPING: &'static [Option<dioxus::prelude::TemplateNodeId>] = &[#(#node_mapping_quoted),*];
// const __NODES_WITH_LISTENERS: &'static [dioxus::prelude::TemplateNodeId] = &[#(#listener_mapping_quoted),*];
// static __VOLITALE_MAPPING_INNER: dioxus::core::exports::once_cell::sync::Lazy<Vec<(dioxus::prelude::TemplateNodeId, usize)>> = dioxus::core::exports::once_cell::sync::Lazy::new(||{
// // check each property to see if it is volatile
// let mut volatile = Vec::new();
// for n in __NODES {
// if let TemplateNodeType::Element(el) = &n.node_type {
// for (i, attr) in el.attributes.iter().enumerate() {
// if attr.attribute.volatile {
// volatile.push((n.id, i));
// }
// }
// }
// }
// volatile
// });
// static __VOLITALE_MAPPING: &'static dioxus::core::exports::once_cell::sync::Lazy<Vec<(dioxus::prelude::TemplateNodeId, usize)>> = &__VOLITALE_MAPPING_INNER;
// static __STATIC_VOLITALE_MAPPING: dioxus::prelude::LazyStaticVec<(dioxus::prelude::TemplateNodeId, usize)> = LazyStaticVec(__VOLITALE_MAPPING);
// static __TEMPLATE: dioxus::prelude::Template = Template::Static(&StaticTemplate {
// nodes: __NODES,
// root_nodes: __ROOT_NODES,
// dynamic_mapping: StaticDynamicNodeMapping::new(__NODE_MAPPING, __TEXT_MAPPING, __ATTRIBUTE_MAPPING, __STATIC_VOLITALE_MAPPING, __NODES_WITH_LISTENERS),
// dynamic_path: #dynamic_path,
// });
// let __bump = __cx.bump();
// __cx.template_ref(dioxus::prelude::TemplateId(get_line_num!()), __TEMPLATE.clone(), #dynamic_context)
// }
// };
// tokens.append_all(quoted)
// }
// }
// #[derive(Default, Clone, Debug)]
// pub struct DynamicTemplateContextBuilder {
// nodes: Vec<BodyNode>,
// text: Vec<FormattedSegment>,
// attributes: Vec<TokenStream>,
// listeners: Vec<(String, Expr)>,
// key: Option<TokenStream>,
// }
// impl DynamicTemplateContextBuilder {
// fn add_node(&mut self, node: BodyNode) -> usize {
// let node_id = self.nodes.len();
// self.nodes.push(node);
// node_id
// }
// fn add_text(&mut self, text: FormattedSegment) -> usize {
// let text_id = self.text.len();
// self.text.push(text);
// text_id
// }
// fn add_attr(&mut self, attr: TokenStream) -> usize {
// let attr_id = self.attributes.len();
// self.attributes.push(attr);
// attr_id
// }
// fn add_listener(&mut self, name: Ident, listener: Expr) -> usize {
// let listener_id = self.listeners.len();
// self.listeners.push((name.to_string(), listener));
// listener_id
// }
// fn add_key(&mut self, key: TokenStream) {
// self.key = Some(key);
// }
// }
// impl ToTokens for DynamicTemplateContextBuilder {
// fn to_tokens(&self, tokens: &mut TokenStream) {
// let nodes = &self.nodes;
// let text = &self.text;
// let attributes = &self.attributes;
// let listeners_names = self
// .listeners
// .iter()
// .map(|(n, _)| syn::parse_str::<Ident>(n).expect(n));
// let listeners_exprs = self.listeners.iter().map(|(_, e)| e);
// let key = match &self.key {
// Some(k) => quote!(Some(#k)),
// None => quote!(None),
// };
// tokens.append_all(quote! {
// TemplateContext {
// nodes: __cx.bump().alloc([#(#nodes),*]),
// text_segments: __cx.bump().alloc([#(&*dioxus::core::exports::bumpalo::format!(in __bump, "{}", #text).into_bump_str()),*]),
// attributes: __cx.bump().alloc([#({#attributes}.into_value(__cx.bump())),*]),
// listeners: __cx.bump().alloc([#(dioxus_elements::on::#listeners_names(__cx, #listeners_exprs)),*]),
// key: #key,
// }
// })
// }
// }
// fn quote_owned_segment(seg: OwnedPathSeg) -> proc_macro2::TokenStream {
// let OwnedPathSeg { ops, traverse } = seg;
// let ops = ops
// .into_iter()
// .map(|op| match op {
// UpdateOp::StoreNode(id) => {
// let id = quote_template_node_id(id);
// quote!(UpdateOp::StoreNode(#id))
// }
// UpdateOp::InsertBefore(id) => {
// let id = quote_template_node_id(id);
// quote!(UpdateOp::InsertBefore(#id))
// }
// UpdateOp::InsertAfter(id) => {
// let id = quote_template_node_id(id);
// quote!(UpdateOp::InsertAfter(#id))
// }
// UpdateOp::AppendChild(id) => {
// let id = quote_template_node_id(id);
// quote!(UpdateOp::AppendChild(#id))
// }
// })
// .collect::<Vec<_>>();
// let traverse = quote_owned_traverse(traverse);
// quote! {
// StaticPathSeg {
// ops: &[#(#ops),*],
// traverse: #traverse,
// }
// }
// }
// fn quote_owned_traverse(traverse: OwnedTraverse) -> proc_macro2::TokenStream {
// match traverse {
// OwnedTraverse::Halt => {
// quote! {StaticTraverse::Halt}
// }
// OwnedTraverse::FirstChild(seg) => {
// let seg = quote_owned_segment(*seg);
// quote! {StaticTraverse::FirstChild(&#seg)}
// }
// OwnedTraverse::NextSibling(seg) => {
// let seg = quote_owned_segment(*seg);
// quote! {StaticTraverse::NextSibling(&#seg)}
// }
// OwnedTraverse::Both(b) => {
// let (child, sibling) = *b;
// let child = quote_owned_segment(child);
// let sibling = quote_owned_segment(sibling);
// quote! {StaticTraverse::Both(&(#child, #sibling))}
// }
// }
// }
// fn quote_template_node_id(id: TemplateNodeId) -> proc_macro2::TokenStream {
// let raw = id.0;
// quote! {
// TemplateNodeId(#raw)
// }
// }