1use crate::{
3 node::attribute::group_attributes_per_name, Attribute, Element, Node,
4 Patch, TreePath,
5};
6use alloc::vec;
7use alloc::vec::Vec;
8use core::fmt::Debug;
9use core::{cmp, mem};
10
11pub fn diff_with_key<'a, Ns, Tag, Leaf, Att, Val>(
51 old_node: &'a Node<Ns, Tag, Leaf, Att, Val>,
52 new_node: &'a Node<Ns, Tag, Leaf, Att, Val>,
53 key: &Att,
54) -> Vec<Patch<'a, Ns, Tag, Leaf, Att, Val>>
55where
56 Ns: PartialEq + Clone + Debug,
57 Tag: PartialEq + Debug,
58 Leaf: PartialEq + Clone + Debug,
59 Att: PartialEq + Clone + Debug,
60 Val: PartialEq + Clone + Debug,
61{
62 diff_recursive(
63 old_node,
64 new_node,
65 &TreePath::root(),
66 key,
67 &|_old, _new| false,
68 &|_old, _new| false,
69 )
70}
71
72pub fn diff_with_functions<'a, Ns, Tag, Leaf, Att, Val, Skip, Rep>(
84 old_node: &'a Node<Ns, Tag, Leaf, Att, Val>,
85 new_node: &'a Node<Ns, Tag, Leaf, Att, Val>,
86 key: &Att,
87 skip: &Skip,
88 rep: &Rep,
89) -> Vec<Patch<'a, Ns, Tag, Leaf, Att, Val>>
90where
91 Ns: PartialEq + Clone + Debug,
92 Tag: PartialEq + Debug,
93 Leaf: PartialEq + Clone + Debug,
94 Att: PartialEq + Clone + Debug,
95 Val: PartialEq + Clone + Debug,
96
97 Skip: Fn(
98 &'a Node<Ns, Tag, Leaf, Att, Val>,
99 &'a Node<Ns, Tag, Leaf, Att, Val>,
100 ) -> bool,
101 Rep: Fn(
102 &'a Node<Ns, Tag, Leaf, Att, Val>,
103 &'a Node<Ns, Tag, Leaf, Att, Val>,
104 ) -> bool,
105{
106 diff_recursive(old_node, new_node, &TreePath::root(), key, skip, rep)
107}
108
109fn is_any_keyed<Ns, Tag, Leaf, Att, Val>(
110 nodes: &[Node<Ns, Tag, Leaf, Att, Val>],
111 key: &Att,
112) -> bool
113where
114 Ns: PartialEq + Clone + Debug,
115 Tag: PartialEq + Debug,
116 Leaf: PartialEq + Clone + Debug,
117 Att: PartialEq + Clone + Debug,
118 Val: PartialEq + Clone + Debug,
119{
120 nodes.iter().any(|child| is_keyed_node(child, key))
121}
122
123fn is_keyed_node<Ns, Tag, Leaf, Att, Val>(
125 node: &Node<Ns, Tag, Leaf, Att, Val>,
126 key: &Att,
127) -> bool
128where
129 Ns: PartialEq + Clone + Debug,
130 Tag: PartialEq + Debug,
131 Leaf: PartialEq + Clone + Debug,
132 Att: PartialEq + Clone + Debug,
133 Val: PartialEq + Clone + Debug,
134{
135 if let Some(attributes) = node.attributes() {
136 attributes.iter().any(|att| att.name == *key)
137 } else {
138 false
139 }
140}
141
142fn should_replace<'a, 'b, Ns, Tag, Leaf, Att, Val, Rep>(
143 old_node: &'a Node<Ns, Tag, Leaf, Att, Val>,
144 new_node: &'a Node<Ns, Tag, Leaf, Att, Val>,
145 key: &Att,
146 rep: &Rep,
147) -> bool
148where
149 Ns: PartialEq + Clone + Debug,
150 Tag: PartialEq + Debug,
151 Leaf: PartialEq + Clone + Debug,
152 Att: PartialEq + Clone + Debug,
153 Val: PartialEq + Clone + Debug,
154 Rep: Fn(
155 &'a Node<Ns, Tag, Leaf, Att, Val>,
156 &'a Node<Ns, Tag, Leaf, Att, Val>,
157 ) -> bool,
158{
159 if mem::discriminant(old_node) != mem::discriminant(new_node) {
161 return true;
162 }
163
164 if rep(old_node, new_node) {
166 return true;
167 }
168
169 if let (Some(old_key), Some(new_key)) =
171 (old_node.attribute_value(key), new_node.attribute_value(key))
172 {
173 if old_key != new_key {
174 return true;
175 }
176 }
177 if let (Node::Element(old_element), Node::Element(new_element)) =
179 (old_node, new_node)
180 {
181 if old_element.tag != new_element.tag {
183 return true;
184 }
185 }
186 false
187}
188
189pub fn diff_recursive<'a, 'b, Ns, Tag, Leaf, Att, Val, Skip, Rep>(
191 old_node: &'a Node<Ns, Tag, Leaf, Att, Val>,
192 new_node: &'a Node<Ns, Tag, Leaf, Att, Val>,
193 path: &TreePath,
194 key: &Att,
195 skip: &Skip,
196 rep: &Rep,
197) -> Vec<Patch<'a, Ns, Tag, Leaf, Att, Val>>
198where
199 Ns: PartialEq + Clone + Debug,
200 Leaf: PartialEq + Clone + Debug,
201 Tag: PartialEq + Debug,
202 Att: PartialEq + Clone + Debug,
203 Val: PartialEq + Clone + Debug,
204 Skip: Fn(
205 &'a Node<Ns, Tag, Leaf, Att, Val>,
206 &'a Node<Ns, Tag, Leaf, Att, Val>,
207 ) -> bool,
208 Rep: Fn(
209 &'a Node<Ns, Tag, Leaf, Att, Val>,
210 &'a Node<Ns, Tag, Leaf, Att, Val>,
211 ) -> bool,
212{
213 if skip(old_node, new_node) {
215 return vec![];
216 }
217
218 if should_replace(old_node, new_node, key, rep) {
220 return vec![Patch::replace_node(
221 old_node.tag(),
222 path.clone(),
223 vec![new_node],
224 )];
225 }
226
227 if old_node == new_node {
229 return vec![];
230 }
231
232 let mut patches = vec![];
233
234 match (old_node, new_node) {
238 (Node::Leaf(old_leaf), Node::Leaf(new_leaf)) => {
239 if old_leaf != new_leaf {
240 let ct = Patch::replace_node(
241 old_node.tag(),
242 path.clone(),
243 vec![new_node],
244 );
245 patches.push(ct);
246 }
247 }
248 (Node::Element(old_element), Node::Element(new_element)) => {
250 let patch =
251 diff_element(old_element, new_element, key, path, skip, rep);
252 patches.extend(patch);
253 }
254 (Node::Fragment(old_nodes), Node::Fragment(new_nodes)) => {
255 let patch = diff_nodes(
258 None,
259 old_nodes,
260 new_nodes,
261 key,
262 &path.backtrack(),
263 skip,
264 rep,
265 );
266 patches.extend(patch);
267 }
268 (Node::NodeList(_old_elements), Node::NodeList(_new_elements)) => {
269 panic!(
270 "Node list must have already unrolled when creating an element"
271 );
272 }
273 _ => {
274 unreachable!("Unequal variant discriminants should already have been handled");
275 }
276 };
277
278 patches
279}
280
281fn diff_element<'a, Ns, Tag, Leaf, Att, Val, Skip, Rep>(
282 old_element: &'a Element<Ns, Tag, Leaf, Att, Val>,
283 new_element: &'a Element<Ns, Tag, Leaf, Att, Val>,
284 key: &Att,
285 path: &TreePath,
286 skip: &Skip,
287 rep: &Rep,
288) -> Vec<Patch<'a, Ns, Tag, Leaf, Att, Val>>
289where
290 Ns: PartialEq + Clone + Debug,
291 Tag: PartialEq + Debug,
292 Leaf: PartialEq + Clone + Debug,
293 Att: PartialEq + Clone + Debug,
294 Val: PartialEq + Clone + Debug,
295 Skip: Fn(
296 &'a Node<Ns, Tag, Leaf, Att, Val>,
297 &'a Node<Ns, Tag, Leaf, Att, Val>,
298 ) -> bool,
299 Rep: Fn(
300 &'a Node<Ns, Tag, Leaf, Att, Val>,
301 &'a Node<Ns, Tag, Leaf, Att, Val>,
302 ) -> bool,
303{
304 let mut patches = create_attribute_patches(old_element, new_element, path);
305
306 let more_patches = diff_nodes(
307 Some(old_element.tag()),
308 &old_element.children,
309 &new_element.children,
310 key,
311 path,
312 skip,
313 rep,
314 );
315
316 patches.extend(more_patches);
317 patches
318}
319
320fn diff_nodes<'a, Ns, Tag, Leaf, Att, Val, Skip, Rep>(
321 old_tag: Option<&'a Tag>,
322 old_children: &'a [Node<Ns, Tag, Leaf, Att, Val>],
323 new_children: &'a [Node<Ns, Tag, Leaf, Att, Val>],
324 key: &Att,
325 path: &TreePath,
326 skip: &Skip,
327 rep: &Rep,
328) -> Vec<Patch<'a, Ns, Tag, Leaf, Att, Val>>
329where
330 Ns: PartialEq + Clone + Debug,
331 Tag: PartialEq + Debug,
332 Leaf: PartialEq + Clone + Debug,
333 Att: PartialEq + Clone + Debug,
334 Val: PartialEq + Clone + Debug,
335 Skip: Fn(
336 &'a Node<Ns, Tag, Leaf, Att, Val>,
337 &'a Node<Ns, Tag, Leaf, Att, Val>,
338 ) -> bool,
339 Rep: Fn(
340 &'a Node<Ns, Tag, Leaf, Att, Val>,
341 &'a Node<Ns, Tag, Leaf, Att, Val>,
342 ) -> bool,
343{
344 let diff_as_keyed =
345 is_any_keyed(old_children, key) || is_any_keyed(new_children, key);
346
347 if diff_as_keyed {
348 let keyed_patches = crate::diff_lis::diff_keyed_nodes(
349 old_tag,
350 old_children,
351 new_children,
352 key,
353 path,
354 skip,
355 rep,
356 );
357 keyed_patches
358 } else {
359 let non_keyed_patches = diff_non_keyed_nodes(
360 old_tag,
361 old_children,
362 new_children,
363 key,
364 path,
365 skip,
366 rep,
367 );
368 non_keyed_patches
369 }
370}
371
372fn diff_non_keyed_nodes<'a, Ns, Tag, Leaf, Att, Val, Skip, Rep>(
383 old_element_tag: Option<&'a Tag>,
384 old_children: &'a [Node<Ns, Tag, Leaf, Att, Val>],
385 new_children: &'a [Node<Ns, Tag, Leaf, Att, Val>],
386 key: &Att,
387 path: &TreePath,
388 skip: &Skip,
389 rep: &Rep,
390) -> Vec<Patch<'a, Ns, Tag, Leaf, Att, Val>>
391where
392 Ns: PartialEq + Clone + Debug,
393 Tag: PartialEq + Debug,
394 Leaf: PartialEq + Clone + Debug,
395 Att: PartialEq + Clone + Debug,
396 Val: PartialEq + Clone + Debug,
397 Skip: Fn(
398 &'a Node<Ns, Tag, Leaf, Att, Val>,
399 &'a Node<Ns, Tag, Leaf, Att, Val>,
400 ) -> bool,
401 Rep: Fn(
402 &'a Node<Ns, Tag, Leaf, Att, Val>,
403 &'a Node<Ns, Tag, Leaf, Att, Val>,
404 ) -> bool,
405{
406 let mut patches = vec![];
407 let old_child_count = old_children.len();
408 let new_child_count = new_children.len();
409
410 let min_count = cmp::min(old_child_count, new_child_count);
411 for index in 0..min_count {
412 let child_path = path.traverse(index);
414
415 let old_child =
416 &old_children.get(index).expect("No old_node child node");
417 let new_child = &new_children.get(index).expect("No new child node");
418
419 let more_patches =
420 diff_recursive(old_child, new_child, &child_path, key, skip, rep);
421 patches.extend(more_patches);
422 }
423
424 if new_child_count > old_child_count {
427 patches.push(Patch::append_children(
428 old_element_tag,
429 path.clone(),
430 new_children.iter().skip(old_child_count).collect(),
431 ));
432 }
433
434 if new_child_count < old_child_count {
435 let remove_node_patches = old_children
436 .iter()
437 .skip(new_child_count)
438 .enumerate()
439 .map(|(i, old_child)| {
440 Patch::remove_node(
441 old_child.tag(),
442 path.traverse(new_child_count + i),
443 )
444 })
445 .collect::<Vec<_>>();
446
447 patches.extend(remove_node_patches);
448 }
449
450 patches
451}
452
453fn create_attribute_patches<'a, Ns, Tag, Leaf, Att, Val>(
458 old_element: &'a Element<Ns, Tag, Leaf, Att, Val>,
459 new_element: &'a Element<Ns, Tag, Leaf, Att, Val>,
460 path: &TreePath,
461) -> Vec<Patch<'a, Ns, Tag, Leaf, Att, Val>>
462where
463 Ns: PartialEq + Clone + Debug,
464 Leaf: PartialEq + Clone + Debug,
465 Tag: PartialEq + Debug,
466 Att: PartialEq + Clone + Debug,
467 Val: PartialEq + Clone + Debug,
468{
469 let new_attributes = new_element.attributes();
470 let old_attributes = old_element.attributes();
471
472 if old_attributes == new_attributes {
474 return vec![];
475 }
476 let mut patches = vec![];
477
478 let mut add_attributes: Vec<&Attribute<Ns, Att, Val>> = vec![];
479 let mut remove_attributes: Vec<&Attribute<Ns, Att, Val>> = vec![];
480
481 let new_attributes_grouped = group_attributes_per_name(new_attributes);
482 let old_attributes_grouped = group_attributes_per_name(old_attributes);
483
484 for (new_attr_name, new_attrs) in new_attributes_grouped.iter() {
488 let old_attr_values = old_attributes_grouped
489 .iter()
490 .find(|(att_name, _)| att_name == new_attr_name)
491 .map(|(_, attrs)| {
492 attrs.iter().map(|attr| &attr.value).collect::<Vec<_>>()
493 });
494
495 let new_attr_values = new_attributes_grouped
496 .iter()
497 .find(|(att_name, _)| att_name == new_attr_name)
498 .map(|(_, attrs)| {
499 attrs.iter().map(|attr| &attr.value).collect::<Vec<_>>()
500 });
501
502 if let Some(old_attr_values) = old_attr_values {
503 let new_attr_values =
504 new_attr_values.expect("must have new attr values");
505 if old_attr_values != new_attr_values {
506 add_attributes.extend(new_attrs);
507 }
508 } else {
509 add_attributes.extend(new_attrs);
510 }
511 }
512
513 for (old_attr_name, old_attrs) in old_attributes_grouped.iter() {
516 if let Some(_pre_attr) = new_attributes_grouped
517 .iter()
518 .find(|(new_attr_name, _)| new_attr_name == old_attr_name)
519 {
520 } else {
522 remove_attributes.extend(old_attrs);
523 }
524 }
525
526 if !add_attributes.is_empty() {
527 patches.push(Patch::add_attributes(
528 &old_element.tag,
529 path.clone(),
530 add_attributes,
531 ));
532 }
533 if !remove_attributes.is_empty() {
534 patches.push(Patch::remove_attributes(
535 &old_element.tag,
536 path.clone(),
537 remove_attributes,
538 ));
539 }
540 patches
541}