1use super::resolve::resolve_props;
2use crate::ir::{Element, IRNode, NodeId, 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>,
53
54 pub parent: Option<NodeId>,
56
57 pub children: im::Vector<NodeId>,
59}
60
61impl InstanceNode {
62 pub fn new(id: NodeId, element: &Element, state: &serde_json::Value) -> Self {
63 let props = resolve_props(&element.props, state);
64
65 Self {
66 id,
67 element_type: element.element_type.clone(),
68 props,
69 raw_props: element.props.clone(),
70 element_template: None,
71 ir_node_template: None,
72 control_flow: None,
73 key: element.key.clone(),
74 parent: None,
75 children: im::Vector::new(),
76 }
77 }
78
79 pub fn new_control_flow(
81 id: NodeId,
82 element_type: &str,
83 props: IndexMap<String, serde_json::Value>,
84 raw_props: Props,
85 control_flow: ControlFlowKind,
86 ir_node_template: IRNode,
87 ) -> Self {
88 Self {
89 id,
90 element_type: element_type.to_string(),
91 props,
92 raw_props,
93 element_template: None,
94 ir_node_template: Some(Arc::new(ir_node_template)),
95 control_flow: Some(control_flow),
96 key: None,
97 parent: None,
98 children: im::Vector::new(),
99 }
100 }
101
102 pub fn update_props(&mut self, state: &serde_json::Value) {
104 self.props = resolve_props(&self.raw_props, state);
105 }
106
107 pub fn is_foreach(&self) -> bool {
109 matches!(self.control_flow, Some(ControlFlowKind::ForEach { .. }))
110 }
111
112 pub fn is_conditional(&self) -> bool {
114 matches!(self.control_flow, Some(ControlFlowKind::Conditional))
115 }
116}
117
118pub struct InstanceTree {
120 nodes: SlotMap<NodeId, InstanceNode>,
122
123 root: Option<NodeId>,
125}
126
127impl InstanceTree {
128 pub fn new() -> Self {
129 Self {
130 nodes: SlotMap::with_key(),
131 root: None,
132 }
133 }
134
135 pub fn clear(&mut self) {
137 self.nodes.clear();
138 self.root = None;
139 }
140
141 pub fn create_node(&mut self, element: &Element, state: &serde_json::Value) -> NodeId {
143 self.nodes
144 .insert_with_key(|id| InstanceNode::new(id, element, state))
145 }
146
147 pub fn create_control_flow_node(
149 &mut self,
150 element_type: &str,
151 props: IndexMap<String, serde_json::Value>,
152 raw_props: Props,
153 control_flow: ControlFlowKind,
154 ir_node_template: IRNode,
155 ) -> NodeId {
156 self.nodes.insert_with_key(|id| {
157 InstanceNode::new_control_flow(
158 id,
159 element_type,
160 props,
161 raw_props,
162 control_flow,
163 ir_node_template,
164 )
165 })
166 }
167
168 pub fn get(&self, id: NodeId) -> Option<&InstanceNode> {
170 self.nodes.get(id)
171 }
172
173 pub fn get_mut(&mut self, id: NodeId) -> Option<&mut InstanceNode> {
175 self.nodes.get_mut(id)
176 }
177
178 pub fn remove(&mut self, id: NodeId) -> Option<InstanceNode> {
180 if let Some(node) = self.nodes.get(id) {
181 let children = node.children.clone();
182 for child_id in children {
184 self.remove(child_id);
185 }
186 }
187 self.nodes.remove(id)
188 }
189
190 pub fn set_root(&mut self, id: NodeId) {
192 self.root = Some(id);
193 }
194
195 pub fn root(&self) -> Option<NodeId> {
197 self.root
198 }
199
200 pub fn add_child(&mut self, parent_id: NodeId, child_id: NodeId, before: Option<NodeId>) {
202 if let Some(parent) = self.nodes.get_mut(parent_id) {
203 if let Some(before_id) = before {
204 if let Some(pos) = parent.children.iter().position(|&id| id == before_id) {
205 parent.children.insert(pos, child_id);
206 } else {
207 parent.children.push_back(child_id);
208 }
209 } else {
210 parent.children.push_back(child_id);
211 }
212 }
213
214 if let Some(child) = self.nodes.get_mut(child_id) {
215 child.parent = Some(parent_id);
216 }
217 }
218
219 pub fn remove_child(&mut self, parent_id: NodeId, child_id: NodeId) {
221 if let Some(parent) = self.nodes.get_mut(parent_id) {
222 parent.children = parent
223 .children
224 .iter()
225 .filter(|&&id| id != child_id)
226 .copied()
227 .collect();
228 }
229
230 if let Some(child) = self.nodes.get_mut(child_id) {
231 child.parent = None;
232 }
233 }
234
235 pub fn update_nodes(
237 &mut self,
238 node_ids: &indexmap::IndexSet<NodeId>,
239 state: &serde_json::Value,
240 ) {
241 for &node_id in node_ids {
242 if let Some(node) = self.nodes.get_mut(node_id) {
243 node.update_props(state);
244 }
245 }
246 }
247
248 pub fn iter(&self) -> impl Iterator<Item = (NodeId, &InstanceNode)> {
250 self.nodes.iter()
251 }
252}
253
254impl Default for InstanceTree {
255 fn default() -> Self {
256 Self::new()
257 }
258}
259
260#[cfg(test)]
261mod tests {
262
263 use crate::reconcile::resolve::evaluate_binding;
264 use serde_json::json;
265
266 #[test]
267 fn test_evaluate_binding() {
268 use crate::reactive::Binding;
269
270 let state = json!({
271 "user": {
272 "name": "Alice",
273 "age": 30
274 }
275 });
276
277 let name_binding = Binding::state(vec!["user".to_string(), "name".to_string()]);
278 let age_binding = Binding::state(vec!["user".to_string(), "age".to_string()]);
279 let email_binding = Binding::state(vec!["user".to_string(), "email".to_string()]);
280
281 assert_eq!(
282 evaluate_binding(&name_binding, &state),
283 Some(json!("Alice"))
284 );
285 assert_eq!(evaluate_binding(&age_binding, &state), Some(json!(30)));
286 assert_eq!(evaluate_binding(&email_binding, &state), None);
287 }
288}