1use std::str::FromStr;
4
5use dioxus_core::{
6 AttributeValue,
7 ElementId,
8 Template,
9 TemplateNode,
10 WriteMutations,
11};
12use rustc_hash::{
13 FxHashMap,
14 FxHashSet,
15};
16use shipyard::Component;
17
18use crate::{
19 node::{
20 ElementNode,
21 FromAnyValue,
22 NodeType,
23 OwnedAttributeValue,
24 },
25 prelude::*,
26 real_dom::NodeTypeMut,
27 tags::TagName,
28 tree::TreeMut,
29 NodeId,
30};
31
32#[derive(Component)]
33struct ElementIdComponent(ElementId);
34
35pub struct DioxusState {
37 templates: FxHashMap<Template, Vec<NodeId>>,
38 pub stack: Vec<NodeId>,
39 node_id_mapping: Vec<Option<NodeId>>,
40}
41
42impl DioxusState {
43 pub fn create<V: FromAnyValue + Send + Sync>(rdom: &mut RealDom<V>) -> Self {
45 let root_id = rdom.root_id();
46 let mut root = rdom.get_mut(root_id).unwrap();
47 root.insert(ElementIdComponent(ElementId(0)));
48 Self {
49 templates: FxHashMap::default(),
50 stack: vec![root_id],
51 node_id_mapping: vec![Some(root_id)],
52 }
53 }
54
55 pub fn element_to_node_id(&self, element_id: ElementId) -> NodeId {
57 self.try_element_to_node_id(element_id).unwrap()
58 }
59
60 pub fn try_element_to_node_id(&self, element_id: ElementId) -> Option<NodeId> {
62 self.node_id_mapping.get(element_id.0).copied().flatten()
63 }
64
65 pub fn create_mutation_writer<'a, V: FromAnyValue + Send + Sync>(
67 &'a mut self,
68 rdom: &'a mut RealDom<V>,
69 ) -> DioxusNativeCoreMutationWriter<'a, V> {
70 DioxusNativeCoreMutationWriter { rdom, state: self }
71 }
72
73 fn set_element_id<V: FromAnyValue + Send + Sync>(
74 &mut self,
75 mut node: NodeMut<V>,
76 element_id: ElementId,
77 ) {
78 let node_id = node.id();
79 node.insert(ElementIdComponent(element_id));
80 if self.node_id_mapping.len() <= element_id.0 {
81 self.node_id_mapping.resize(element_id.0 + 1, None);
82 } else if let Some(mut node) =
83 self.node_id_mapping[element_id.0].and_then(|id| node.real_dom_mut().get_mut(id))
84 {
85 node.remove();
86 }
87
88 self.node_id_mapping[element_id.0] = Some(node_id);
89 }
90
91 fn load_child<V: FromAnyValue + Send + Sync>(&self, rdom: &RealDom<V>, path: &[u8]) -> NodeId {
92 let mut current = rdom.get(*self.stack.last().unwrap()).unwrap();
93 for i in path {
94 let new_id = current.child_ids()[*i as usize];
95 current = rdom.get(new_id).unwrap();
96 }
97 current.id()
98 }
99}
100
101pub struct DioxusNativeCoreMutationWriter<'a, V: FromAnyValue + Send + Sync = ()> {
103 pub rdom: &'a mut RealDom<V>,
105
106 pub state: &'a mut DioxusState,
108}
109
110impl<V: FromAnyValue + Send + Sync> WriteMutations for DioxusNativeCoreMutationWriter<'_, V> {
111 fn append_children(&mut self, id: ElementId, m: usize) {
123 let children = self.state.stack.split_off(self.state.stack.len() - m);
124 let parent_id = self.state.element_to_node_id(id);
125 let mut parent = self.rdom.get_mut(parent_id).unwrap();
126 for child in children {
127 parent.add_child(child);
128 }
129 }
130
131 fn assign_node_id(&mut self, path: &'static [u8], id: ElementId) {
132 let node_id = self.state.load_child(self.rdom, path);
133 self.state
134 .set_element_id(self.rdom.get_mut(node_id).unwrap(), id);
135 }
136
137 fn create_placeholder(&mut self, id: ElementId) {
138 let node = NodeType::Placeholder;
139 let node = self.rdom.create_node(node);
140 let node_id = node.id();
141 self.state.set_element_id(node, id);
142 self.state.stack.push(node_id);
143 }
144
145 fn create_text_node(&mut self, value: &str, id: ElementId) {
146 let node_data = NodeType::Text(value.to_string());
147 let node = self.rdom.create_node(node_data);
148 let node_id = node.id();
149 self.state.set_element_id(node, id);
150 self.state.stack.push(node_id);
151 }
152
153 fn load_template(&mut self, template: Template, index: usize, id: ElementId) {
154 let template_entry = self.state.templates.entry(template).or_insert_with(|| {
155 let template_root_ids: Vec<NodeId> = template
156 .roots
157 .iter()
158 .map(|root| create_template_node(self.rdom, root))
159 .collect();
160
161 template_root_ids
162 });
163
164 let template_node_id = template_entry[index];
165 let clone = self.rdom.deep_clone_node(template_node_id);
166 let clone_id = clone.id();
167 self.state.set_element_id(clone, id);
168 self.state.stack.push(clone_id);
169 }
170
171 fn replace_node_with(&mut self, id: ElementId, m: usize) {
172 let new_nodes = self.state.stack.split_off(self.state.stack.len() - m);
173 let old_node_id = self.state.element_to_node_id(id);
174 for new in new_nodes {
175 let mut node = self.rdom.get_mut(new).unwrap();
176 node.insert_before(old_node_id);
177 }
178 self.rdom.get_mut(old_node_id).unwrap().remove();
179 }
180
181 fn replace_placeholder_with_nodes(&mut self, path: &'static [u8], m: usize) {
182 let new_nodes = self.state.stack.split_off(self.state.stack.len() - m);
183 let old_node_id = self.state.load_child(self.rdom, path);
184 for new in new_nodes {
185 let mut node = self.rdom.get_mut(new).unwrap();
186 node.insert_before(old_node_id);
187 }
188 self.rdom.get_mut(old_node_id).unwrap().remove();
189 }
190
191 fn insert_nodes_after(&mut self, id: ElementId, m: usize) {
192 let new_nodes = self.state.stack.split_off(self.state.stack.len() - m);
193 let old_node_id = self.state.element_to_node_id(id);
194 for new in new_nodes.into_iter().rev() {
195 let mut node = self.rdom.get_mut(new).unwrap();
196 node.insert_after(old_node_id);
197 }
198 }
199
200 fn insert_nodes_before(&mut self, id: ElementId, m: usize) {
201 let new_nodes = self.state.stack.split_off(self.state.stack.len() - m);
202 let old_node_id = self.state.element_to_node_id(id);
203 for new in new_nodes {
204 self.rdom.tree_mut().insert_before(old_node_id, new);
205 }
206 }
207
208 fn set_attribute(
209 &mut self,
210 name: &'static str,
211 _ns: Option<&'static str>,
212 value: &AttributeValue,
213 id: ElementId,
214 ) {
215 let node_id = self.state.element_to_node_id(id);
216 let mut node = self.rdom.get_mut(node_id).unwrap();
217 let mut node_type_mut = node.node_type_mut();
218 if let NodeTypeMut::Element(element) = &mut node_type_mut {
219 let attribute = AttributeName::from_str(name).expect("Unexpected");
220 if let AttributeValue::None = &value {
221 element.remove_attribute(&attribute);
222 } else {
223 element.set_attribute(attribute, OwnedAttributeValue::from(value));
224 }
225 }
226 }
227
228 fn set_node_text(&mut self, value: &str, id: ElementId) {
229 let node_id = self.state.element_to_node_id(id);
230 let mut node = self.rdom.get_mut(node_id).unwrap();
231 let node_type_mut = node.node_type_mut();
232 if let NodeTypeMut::Text(mut text) = node_type_mut {
233 *text.text_mut() = value.to_string();
234 }
235 }
236
237 fn create_event_listener(&mut self, name: &'static str, id: ElementId) {
238 let node_id = self.state.element_to_node_id(id);
239 let mut node = self.rdom.get_mut(node_id).unwrap();
240 node.add_event_listener(EventName::from_str(name).expect("Unexpected."));
241 }
242
243 fn remove_event_listener(&mut self, name: &'static str, id: ElementId) {
244 let node_id = self.state.element_to_node_id(id);
245 let mut node = self.rdom.get_mut(node_id).unwrap();
246 node.remove_event_listener(&EventName::from_str(name).expect("Unexpected."));
247 }
248
249 fn remove_node(&mut self, id: ElementId) {
250 let node_id = self.state.element_to_node_id(id);
251 self.rdom.get_mut(node_id).unwrap().remove();
252 }
253
254 fn push_root(&mut self, id: ElementId) {
255 let node_id = self.state.element_to_node_id(id);
256 self.state.stack.push(node_id);
257 }
258}
259
260fn create_template_node<V: FromAnyValue + Send + Sync>(
261 rdom: &mut RealDom<V>,
262 node: &TemplateNode,
263) -> NodeId {
264 match node {
265 TemplateNode::Element {
266 tag,
267 attrs,
268 children,
269 ..
270 } => {
271 let node = NodeType::Element(ElementNode {
272 tag: TagName::from_str(tag).expect("Unexpected."),
273 attributes: attrs
274 .iter()
275 .filter_map(|attr| match attr {
276 dioxus_core::TemplateAttribute::Static { name, value, .. } => Some((
277 AttributeName::from_str(name).expect("Unexpected."),
278 OwnedAttributeValue::Text(value.to_string()),
279 )),
280 dioxus_core::TemplateAttribute::Dynamic { .. } => None,
281 })
282 .collect(),
283 listeners: FxHashSet::default(),
284 });
285 let node_id = rdom.create_node(node).id();
286 for child in *children {
287 let child_id = create_template_node(rdom, child);
288 rdom.get_mut(node_id).unwrap().add_child(child_id);
289 }
290 node_id
291 }
292 TemplateNode::Text { text } => rdom.create_node(NodeType::Text(text.to_string())).id(),
293 TemplateNode::Dynamic { .. } => rdom.create_node(NodeType::Placeholder).id(),
294 }
295}
296
297pub trait NodeImmutableDioxusExt<V: FromAnyValue + Send + Sync>: NodeImmutable<V> {
299 fn mounted_id(&self) -> Option<ElementId> {
302 let id = self.get::<ElementIdComponent>();
303 id.map(|id| id.0)
304 }
305}
306
307impl<T: NodeImmutable<V>, V: FromAnyValue + Send + Sync> NodeImmutableDioxusExt<V> for T {}