1use super::resolve::resolve_props;
2use crate::ir::{Element, NodeId, IRNode, Props};
3use indexmap::IndexMap;
4use slotmap::SlotMap;
5use std::sync::Arc;
6
7#[derive(Debug, Clone)]
9pub enum ControlFlowKind {
10 ForEach {
12 item_name: String,
13 key_path: Option<String>,
14 },
15 Conditional,
17}
18
19#[derive(Debug, Clone)]
24pub struct InstanceNode {
25 pub id: NodeId,
27
28 pub element_type: String,
30
31 pub props: IndexMap<String, serde_json::Value>,
33
34 pub raw_props: Props,
36
37 pub element_template: Option<Arc<Element>>,
41
42 pub ir_node_template: Option<Arc<IRNode>>,
46
47 pub control_flow: Option<ControlFlowKind>,
49
50 pub key: Option<String>,
54
55 pub parent: Option<NodeId>,
57
58 pub children: im::Vector<NodeId>,
60}
61
62impl InstanceNode {
63 pub fn new(id: NodeId, element: &Element, state: &serde_json::Value) -> Self {
64 let props = resolve_props(&element.props, state);
65
66 Self {
67 id,
68 element_type: element.element_type.clone(),
69 props,
70 raw_props: element.props.clone(),
71 element_template: None,
72 ir_node_template: None,
73 control_flow: None,
74 key: element.key.clone(),
75 parent: None,
76 children: im::Vector::new(),
77 }
78 }
79
80 pub fn new_control_flow(
82 id: NodeId,
83 element_type: &str,
84 props: IndexMap<String, serde_json::Value>,
85 raw_props: Props,
86 control_flow: ControlFlowKind,
87 ir_node_template: IRNode,
88 ) -> Self {
89 Self {
90 id,
91 element_type: element_type.to_string(),
92 props,
93 raw_props,
94 element_template: None,
95 ir_node_template: Some(Arc::new(ir_node_template)),
96 control_flow: Some(control_flow),
97 key: None,
98 parent: None,
99 children: im::Vector::new(),
100 }
101 }
102
103 pub fn update_props(&mut self, state: &serde_json::Value) {
105 self.props = resolve_props(&self.raw_props, state);
106 }
107
108 pub fn is_foreach(&self) -> bool {
110 matches!(self.control_flow, Some(ControlFlowKind::ForEach { .. }))
111 }
112
113 pub fn is_conditional(&self) -> bool {
115 matches!(self.control_flow, Some(ControlFlowKind::Conditional))
116 }
117}
118
119pub struct InstanceTree {
121 nodes: SlotMap<NodeId, InstanceNode>,
123
124 root: Option<NodeId>,
126}
127
128impl InstanceTree {
129 pub fn new() -> Self {
130 Self {
131 nodes: SlotMap::with_key(),
132 root: None,
133 }
134 }
135
136 pub fn clear(&mut self) {
138 self.nodes.clear();
139 self.root = None;
140 }
141
142 pub fn create_node(&mut self, element: &Element, state: &serde_json::Value) -> NodeId {
144
145 self.nodes.insert_with_key(|id| InstanceNode::new(id, element, state))
146 }
147
148 pub fn create_control_flow_node(
150 &mut self,
151 element_type: &str,
152 props: IndexMap<String, serde_json::Value>,
153 raw_props: Props,
154 control_flow: ControlFlowKind,
155 ir_node_template: IRNode,
156 ) -> NodeId {
157 self.nodes.insert_with_key(|id| {
158 InstanceNode::new_control_flow(id, element_type, props, raw_props, control_flow, ir_node_template)
159 })
160 }
161
162 pub fn get(&self, id: NodeId) -> Option<&InstanceNode> {
164 self.nodes.get(id)
165 }
166
167 pub fn get_mut(&mut self, id: NodeId) -> Option<&mut InstanceNode> {
169 self.nodes.get_mut(id)
170 }
171
172 pub fn remove(&mut self, id: NodeId) -> Option<InstanceNode> {
174 if let Some(node) = self.nodes.get(id) {
175 let children = node.children.clone();
176 for child_id in children {
178 self.remove(child_id);
179 }
180 }
181 self.nodes.remove(id)
182 }
183
184 pub fn set_root(&mut self, id: NodeId) {
186 self.root = Some(id);
187 }
188
189 pub fn root(&self) -> Option<NodeId> {
191 self.root
192 }
193
194 pub fn add_child(&mut self, parent_id: NodeId, child_id: NodeId, before: Option<NodeId>) {
196 if let Some(parent) = self.nodes.get_mut(parent_id) {
197 if let Some(before_id) = before {
198 if let Some(pos) = parent.children.iter().position(|&id| id == before_id) {
199 parent.children.insert(pos, child_id);
200 } else {
201 parent.children.push_back(child_id);
202 }
203 } else {
204 parent.children.push_back(child_id);
205 }
206 }
207
208 if let Some(child) = self.nodes.get_mut(child_id) {
209 child.parent = Some(parent_id);
210 }
211 }
212
213 pub fn remove_child(&mut self, parent_id: NodeId, child_id: NodeId) {
215 if let Some(parent) = self.nodes.get_mut(parent_id) {
216 parent.children = parent.children.iter().filter(|&&id| id != child_id).copied().collect();
217 }
218
219 if let Some(child) = self.nodes.get_mut(child_id) {
220 child.parent = None;
221 }
222 }
223
224 pub fn update_nodes(&mut self, node_ids: &indexmap::IndexSet<NodeId>, state: &serde_json::Value) {
226 for &node_id in node_ids {
227 if let Some(node) = self.nodes.get_mut(node_id) {
228 node.update_props(state);
229 }
230 }
231 }
232
233 pub fn iter(&self) -> impl Iterator<Item = (NodeId, &InstanceNode)> {
235 self.nodes.iter()
236 }
237}
238
239impl Default for InstanceTree {
240 fn default() -> Self {
241 Self::new()
242 }
243}
244
245#[cfg(test)]
246mod tests {
247
248 use crate::reconcile::resolve::evaluate_binding;
249 use serde_json::json;
250
251 #[test]
252 fn test_evaluate_binding() {
253 use crate::reactive::Binding;
254
255 let state = json!({
256 "user": {
257 "name": "Alice",
258 "age": 30
259 }
260 });
261
262 let name_binding = Binding::state(vec!["user".to_string(), "name".to_string()]);
263 let age_binding = Binding::state(vec!["user".to_string(), "age".to_string()]);
264 let email_binding = Binding::state(vec!["user".to_string(), "email".to_string()]);
265
266 assert_eq!(
267 evaluate_binding(&name_binding, &state),
268 Some(json!("Alice"))
269 );
270 assert_eq!(
271 evaluate_binding(&age_binding, &state),
272 Some(json!(30))
273 );
274 assert_eq!(evaluate_binding(&email_binding, &state), None);
275 }
276}