1use super::resolve::{resolve_props, resolve_props_full};
2use crate::ir::{Element, IRNode, NodeId, Props};
3use indexmap::IndexMap;
4use slotmap::SlotMap;
5use std::sync::Arc;
6
7type DataSources = indexmap::IndexMap<String, serde_json::Value>;
9
10#[derive(Debug, Clone)]
12pub enum ControlFlowKind {
13 ForEach {
15 item_name: String,
16 key_path: Option<String>,
17 },
18 Conditional,
20}
21
22#[derive(Debug, Clone)]
27pub struct InstanceNode {
28 pub id: NodeId,
30
31 pub element_type: String,
33
34 pub props: IndexMap<String, serde_json::Value>,
36
37 pub raw_props: Props,
39
40 pub element_template: Option<Arc<Element>>,
44
45 pub ir_node_template: Option<Arc<IRNode>>,
49
50 pub control_flow: Option<ControlFlowKind>,
52
53 pub key: Option<String>,
56
57 pub parent: Option<NodeId>,
59
60 pub children: im::Vector<NodeId>,
62}
63
64impl InstanceNode {
65 pub fn new(id: NodeId, element: &Element, state: &serde_json::Value) -> Self {
66 Self::new_full(id, element, state, None)
67 }
68
69 pub fn new_full(
70 id: NodeId,
71 element: &Element,
72 state: &serde_json::Value,
73 data_sources: Option<&DataSources>,
74 ) -> Self {
75 let props = resolve_props_full(&element.props, state, None, data_sources);
76
77 Self {
78 id,
79 element_type: element.element_type.clone(),
80 props,
81 raw_props: element.props.clone(),
82 element_template: None,
83 ir_node_template: None,
84 control_flow: None,
85 key: element.key.clone(),
86 parent: None,
87 children: im::Vector::new(),
88 }
89 }
90
91 pub fn new_control_flow(
93 id: NodeId,
94 element_type: &str,
95 props: IndexMap<String, serde_json::Value>,
96 raw_props: Props,
97 control_flow: ControlFlowKind,
98 ir_node_template: IRNode,
99 ) -> Self {
100 Self {
101 id,
102 element_type: element_type.to_string(),
103 props,
104 raw_props,
105 element_template: None,
106 ir_node_template: Some(Arc::new(ir_node_template)),
107 control_flow: Some(control_flow),
108 key: None,
109 parent: None,
110 children: im::Vector::new(),
111 }
112 }
113
114 pub fn update_props(&mut self, state: &serde_json::Value) {
116 self.props = resolve_props(&self.raw_props, state);
117 }
118
119 pub fn update_props_with_data_sources(
121 &mut self,
122 state: &serde_json::Value,
123 data_sources: Option<&indexmap::IndexMap<String, serde_json::Value>>,
124 ) {
125 self.props = resolve_props_full(&self.raw_props, state, None, data_sources);
126 }
127
128 pub fn is_foreach(&self) -> bool {
130 matches!(self.control_flow, Some(ControlFlowKind::ForEach { .. }))
131 }
132
133 pub fn is_conditional(&self) -> bool {
135 matches!(self.control_flow, Some(ControlFlowKind::Conditional))
136 }
137}
138
139pub struct InstanceTree {
141 nodes: SlotMap<NodeId, InstanceNode>,
143
144 root: Option<NodeId>,
146}
147
148impl InstanceTree {
149 pub fn new() -> Self {
150 Self {
151 nodes: SlotMap::with_key(),
152 root: None,
153 }
154 }
155
156 pub fn clear(&mut self) {
158 self.nodes.clear();
159 self.root = None;
160 }
161
162 pub fn create_node(&mut self, element: &Element, state: &serde_json::Value) -> NodeId {
164 self.nodes
165 .insert_with_key(|id| InstanceNode::new(id, element, state))
166 }
167
168 pub fn create_node_full(
170 &mut self,
171 element: &Element,
172 state: &serde_json::Value,
173 data_sources: Option<&DataSources>,
174 ) -> NodeId {
175 self.nodes
176 .insert_with_key(|id| InstanceNode::new_full(id, element, state, data_sources))
177 }
178
179 pub fn create_control_flow_node(
181 &mut self,
182 element_type: &str,
183 props: IndexMap<String, serde_json::Value>,
184 raw_props: Props,
185 control_flow: ControlFlowKind,
186 ir_node_template: IRNode,
187 ) -> NodeId {
188 self.nodes.insert_with_key(|id| {
189 InstanceNode::new_control_flow(
190 id,
191 element_type,
192 props,
193 raw_props,
194 control_flow,
195 ir_node_template,
196 )
197 })
198 }
199
200 pub fn get(&self, id: NodeId) -> Option<&InstanceNode> {
202 self.nodes.get(id)
203 }
204
205 pub fn get_mut(&mut self, id: NodeId) -> Option<&mut InstanceNode> {
207 self.nodes.get_mut(id)
208 }
209
210 pub fn remove(&mut self, id: NodeId) -> Option<InstanceNode> {
212 if let Some(node) = self.nodes.get(id) {
213 let children = node.children.clone();
214 for child_id in children {
216 self.remove(child_id);
217 }
218 }
219 self.nodes.remove(id)
220 }
221
222 pub fn set_root(&mut self, id: NodeId) {
224 self.root = Some(id);
225 }
226
227 pub fn root(&self) -> Option<NodeId> {
229 self.root
230 }
231
232 pub fn add_child(&mut self, parent_id: NodeId, child_id: NodeId, before: Option<NodeId>) {
234 if let Some(parent) = self.nodes.get_mut(parent_id) {
235 if let Some(before_id) = before {
236 if let Some(pos) = parent.children.iter().position(|&id| id == before_id) {
237 parent.children.insert(pos, child_id);
238 } else {
239 parent.children.push_back(child_id);
240 }
241 } else {
242 parent.children.push_back(child_id);
243 }
244 }
245
246 if let Some(child) = self.nodes.get_mut(child_id) {
247 child.parent = Some(parent_id);
248 }
249 }
250
251 pub fn remove_child(&mut self, parent_id: NodeId, child_id: NodeId) {
253 if let Some(parent) = self.nodes.get_mut(parent_id) {
254 parent.children = parent
255 .children
256 .iter()
257 .filter(|&&id| id != child_id)
258 .copied()
259 .collect();
260 }
261
262 if let Some(child) = self.nodes.get_mut(child_id) {
263 child.parent = None;
264 }
265 }
266
267 pub fn update_nodes(
269 &mut self,
270 node_ids: &indexmap::IndexSet<NodeId>,
271 state: &serde_json::Value,
272 ) {
273 for &node_id in node_ids {
274 if let Some(node) = self.nodes.get_mut(node_id) {
275 node.update_props(state);
276 }
277 }
278 }
279
280 pub fn len(&self) -> usize {
282 self.nodes.len()
283 }
284
285 pub fn is_empty(&self) -> bool {
287 self.nodes.is_empty()
288 }
289
290 pub fn iter(&self) -> impl Iterator<Item = (NodeId, &InstanceNode)> {
292 self.nodes.iter()
293 }
294}
295
296impl Default for InstanceTree {
297 fn default() -> Self {
298 Self::new()
299 }
300}
301
302#[cfg(test)]
303mod tests {
304
305 use crate::reconcile::resolve::evaluate_binding;
306 use serde_json::json;
307
308 #[test]
309 fn test_evaluate_binding() {
310 use crate::reactive::Binding;
311
312 let state = json!({
313 "user": {
314 "name": "Alice",
315 "age": 30
316 }
317 });
318
319 let name_binding = Binding::state(vec!["user".to_string(), "name".to_string()]);
320 let age_binding = Binding::state(vec!["user".to_string(), "age".to_string()]);
321 let email_binding = Binding::state(vec!["user".to_string(), "email".to_string()]);
322
323 assert_eq!(
324 evaluate_binding(&name_binding, &state),
325 Some(json!("Alice"))
326 );
327 assert_eq!(evaluate_binding(&age_binding, &state), Some(json!(30)));
328 assert_eq!(evaluate_binding(&email_binding, &state), None);
329 }
330}