feat: define VNode, FlatVDom types with Element round-trip conversion
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
|
||||||
use super::reactive::{ElementId, ReactiveTracker};
|
use super::reactive::{ElementId, ReactiveTracker};
|
||||||
@@ -214,6 +215,95 @@ pub struct Document<'a> {
|
|||||||
pub tracker: ReactiveTracker,
|
pub tracker: ReactiveTracker,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type NodeId = u32;
|
||||||
|
pub type PropertyIdx = usize;
|
||||||
|
pub type NodeIdx = usize;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct VNode<'a> {
|
||||||
|
pub id: NodeId,
|
||||||
|
pub type_name: &'a str,
|
||||||
|
pub properties: Range<PropertyIdx>,
|
||||||
|
pub children_range: Range<NodeIdx>,
|
||||||
|
pub computed_style: ComputedStyle,
|
||||||
|
pub element_id: ElementId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FlatVDom<'a> {
|
||||||
|
pub nodes: Vec<VNode<'a>>,
|
||||||
|
pub properties: Vec<(String, String)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FlatVDom<'a> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
nodes: Vec::new(),
|
||||||
|
properties: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_elements(elements: &[Element<'a>]) -> Self {
|
||||||
|
let mut fv = FlatVDom::new();
|
||||||
|
fv.append_elements(elements);
|
||||||
|
fv
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_elements(&mut self, elements: &[Element<'a>]) -> Range<NodeIdx> {
|
||||||
|
let start = self.nodes.len();
|
||||||
|
for el in elements {
|
||||||
|
let node_idx = self.nodes.len();
|
||||||
|
let prop_start = self.properties.len();
|
||||||
|
for (k, v) in &el.properties {
|
||||||
|
self.properties.push((k.clone().into_owned(), v.clone().into_owned()));
|
||||||
|
}
|
||||||
|
self.nodes.push(VNode {
|
||||||
|
id: 0,
|
||||||
|
type_name: el.type_name,
|
||||||
|
properties: prop_start..self.properties.len(),
|
||||||
|
children_range: 0..0,
|
||||||
|
computed_style: el.computed_style,
|
||||||
|
element_id: el.element_id,
|
||||||
|
});
|
||||||
|
let child_range = self.append_elements(&el.children);
|
||||||
|
self.nodes[node_idx].children_range = child_range;
|
||||||
|
}
|
||||||
|
start..self.nodes.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_elements(self) -> Vec<Element<'a>> {
|
||||||
|
Self::nodes_to_elements(&self.nodes, &self.properties, 0..self.nodes.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nodes_to_elements(nodes: &[VNode<'a>], props: &[(String, String)], range: Range<NodeIdx>) -> Vec<Element<'a>> {
|
||||||
|
let mut result = Vec::with_capacity(range.len());
|
||||||
|
for idx in range {
|
||||||
|
let vn = &nodes[idx];
|
||||||
|
let mut el = Element::new(vn.type_name);
|
||||||
|
el.element_id = vn.element_id;
|
||||||
|
el.computed_style = vn.computed_style;
|
||||||
|
for i in vn.properties.clone() {
|
||||||
|
if i < props.len() {
|
||||||
|
let (k, v) = &props[i];
|
||||||
|
el.push_prop(k.clone(), v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let child_range = vn.children_range.clone();
|
||||||
|
el.children = Self::nodes_to_elements(nodes, props, child_range);
|
||||||
|
result.push(el);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_node(&self, idx: NodeIdx) -> Option<&VNode<'a>> {
|
||||||
|
self.nodes.get(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn node_count(&self) -> usize {
|
||||||
|
self.nodes.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InterpError {
|
pub enum InterpError {
|
||||||
BadMagic,
|
BadMagic,
|
||||||
|
|||||||
Reference in New Issue
Block a user