From 0d89ff68bebf756cde365b4727de78ca89b46b69 Mon Sep 17 00:00:00 2001 From: Glint Dev Date: Wed, 22 Jul 2026 13:36:25 +0300 Subject: [PATCH] feat: define VNode, FlatVDom types with Element round-trip conversion --- src/interpreter/types.rs | 90 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/interpreter/types.rs b/src/interpreter/types.rs index be230d2..d256463 100644 --- a/src/interpreter/types.rs +++ b/src/interpreter/types.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::collections::HashMap; use std::fmt; +use std::ops::Range; use super::reactive::{ElementId, ReactiveTracker}; @@ -214,6 +215,95 @@ pub struct Document<'a> { 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, + pub children_range: Range, + pub computed_style: ComputedStyle, + pub element_id: ElementId, +} + +#[derive(Debug, Clone)] +pub struct FlatVDom<'a> { + pub nodes: Vec>, + 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 { + 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> { + Self::nodes_to_elements(&self.nodes, &self.properties, 0..self.nodes.len()) + } + + fn nodes_to_elements(nodes: &[VNode<'a>], props: &[(String, String)], range: Range) -> Vec> { + 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)] pub enum InterpError { BadMagic,