From 73344d0dbfd38e9512091a8156ccda784cc474a7 Mon Sep 17 00:00:00 2001 From: Bodil Stokke Date: Mon, 12 Nov 2018 16:29:48 +0000 Subject: [PATCH] Build a virtual DOM structure. --- clippy.toml | 5 ++++ macros/src/declare.rs | 59 +++++++++++++++++++++++++++++++++----- typed-html/src/bin/main.rs | 2 ++ typed-html/src/elements.rs | 23 +++++++++++++-- 4 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 clippy.toml diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..d6f2aca --- /dev/null +++ b/clippy.toml @@ -0,0 +1,5 @@ +blacklisted-names = [] +cyclomatic-complexity-threshold = 100 +single-char-binding-names-threshold = 15 +# I HAVE THE POWER OF OLEG +type-complexity-threshold = 999999 diff --git a/macros/src/declare.rs b/macros/src/declare.rs index 6058b39..197b4b6 100644 --- a/macros/src/declare.rs +++ b/macros/src/declare.rs @@ -96,11 +96,6 @@ impl Declare { let mut body = TokenStream::new(); - body.extend(quote!( - pub attrs: $attr_type_name, - pub data_attributes: std::collections::BTreeMap, - )); - for (child_name, child_type, _) in self.req_children() { body.extend(quote!( pub $child_name: Box<$child_type>, )); } @@ -112,6 +107,8 @@ impl Declare { quote!( pub struct $elem_name { + pub attrs: $attr_type_name, + pub data_attributes: std::collections::BTreeMap, $body } ) @@ -154,10 +151,58 @@ impl Declare { ) } + fn impl_vnode(&self) -> TokenStream { + let elem_name = TokenTree::Literal(Literal::string(self.name.to_string().as_str())); + let mut req_children = TokenStream::new(); + for (child_name, _, _) in self.req_children() { + req_children.extend(quote!( + children.push(self.$child_name.vnode()); + )); + } + let mut opt_children = TokenStream::new(); + if self.opt_children.is_some() { + opt_children.extend(quote!(for child in &self.children { + children.push(child.vnode()); + })); + } + + let mut push_attrs = TokenStream::new(); + for (attr_name, _, attr_str) in self.attrs() { + push_attrs.extend(quote!( + if let Some(ref value) = self.attrs.$attr_name { + attributes.push(($attr_str.to_string(), value.to_string())); + } + )); + } + + quote!( + let mut attributes = Vec::new(); + $push_attrs + for (key, value) in &self.data_attributes { + attributes.push((format!("data-{}", key), value.to_string())); + } + + let mut children = Vec::new(); + $req_children + $opt_children + + ::elements::VNode::Element(::elements::VElement { + name: $elem_name, + attributes, + children + }) + ) + } + fn impl_node(&self) -> TokenStream { let elem_name = self.elem_name(); + let vnode = self.impl_vnode(); quote!( - impl ::elements::Node for $elem_name {} + impl ::elements::Node for $elem_name { + fn vnode(&self) -> ::elements::VNode { + $vnode + } + } ) } @@ -270,7 +315,7 @@ impl Declare { quote!( impl std::fmt::Display for $elem_name { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - write!(f, "<{}", $name); + write!(f, "<{}", $name)?; $print_attrs for (key, value) in &self.data_attributes { write!(f, " data-{}={:?}", key, value)?; diff --git a/typed-html/src/bin/main.rs b/typed-html/src/bin/main.rs index de7cbb6..df52532 100644 --- a/typed-html/src/bin/main.rs +++ b/typed-html/src/bin/main.rs @@ -5,6 +5,7 @@ extern crate typed_html; extern crate typed_html_macros; +use typed_html::elements::Node; use typed_html::types::*; use typed_html_macros::html; @@ -37,4 +38,5 @@ fn main() { ); println!("{}", doc.to_string()); + println!("{:?}", doc.vnode()); } diff --git a/typed-html/src/elements.rs b/typed-html/src/elements.rs index 7292991..47f4f3c 100644 --- a/typed-html/src/elements.rs +++ b/typed-html/src/elements.rs @@ -6,7 +6,22 @@ use typed_html_macros::declare_element; use super::types::*; -pub trait Node: Display {} +#[derive(Clone, Debug)] +pub enum VNode { + Text(String), + Element(VElement), +} + +#[derive(Clone, Debug)] +pub struct VElement { + pub name: &'static str, + pub attributes: Vec<(String, String)>, + pub children: Vec, +} + +pub trait Node: Display { + fn vnode(&self) -> VNode; +} pub trait Element: Node { fn name() -> &'static str; @@ -61,7 +76,11 @@ impl Display for TextNode { } } -impl Node for TextNode {} +impl Node for TextNode { + fn vnode(&self) -> VNode { + VNode::Text(self.0.clone()) + } +} impl FlowContent for TextNode {} impl PhrasingContent for TextNode {}