1use std::collections::{BTreeSet, HashMap, HashSet};
14use std::sync::Arc;
15
16use super::{Caller, Instance, Record, Resolver, resolved};
17use crate::Problem;
18use crate::parse::{self, Child, Element, TextPart};
19use crate::scene::{self, Applied, Edit, Edits, Files, Holder, Layout, Node, Scene};
20use crate::tree::NodeId;
21
22#[derive(Debug, Clone)]
27pub struct Resolution {
28 path: String,
29 record: Record,
30 files: Vec<String>,
32 pending: BTreeSet<String>,
35 pub(crate) wholes: usize,
38 pub(crate) elements: usize,
42}
43
44#[derive(Debug)]
46pub enum Outcome {
47 Same,
49 Changed(Edits, Applied),
52 Problems(Vec<Problem>),
55}
56
57impl Resolution {
58 pub fn new(files: &dyn Files, path: &str) -> Result<(Resolution, Scene), Vec<Problem>> {
61 let (scene, record, read) = resolved(files, path)?;
62 let resolution = Resolution {
63 path: path.to_string(),
64 record,
65 files: read,
66 pending: BTreeSet::new(),
67 wholes: 0,
68 elements: 0,
69 };
70 Ok((resolution, scene))
71 }
72
73 pub fn files(&self) -> &[String] {
76 &self.files
77 }
78
79 pub fn wholes(&self) -> usize {
83 self.wholes
84 }
85
86 pub fn update(
94 &mut self,
95 held: &mut dyn Holder,
96 files: &dyn Files,
97 changed: &[String],
98 ) -> Outcome {
99 self.pending.extend(changed.iter().cloned());
100 match self.again(held, files) {
101 Ok(outcome) => {
102 self.pending.clear();
103 outcome
104 }
105 Err(()) => match resolved(files, &self.path) {
106 Err(problems) => Outcome::Problems(problems),
107 Ok((scene, record, read)) => {
110 self.pending.clear();
111 self.whole(held, scene, record, read)
112 }
113 },
114 }
115 }
116
117 fn whole(
120 &mut self,
121 held: &mut dyn Holder,
122 scene: Scene,
123 record: Record,
124 read: Vec<String>,
125 ) -> Outcome {
126 self.wholes += 1;
127 self.record = record;
128 self.files = read;
129 let was_themed = held.scene().themed;
130 let edits = Edits::between(held.scene(), &scene);
131 if edits.list.is_empty() && was_themed == edits.themed {
132 return Outcome::Same;
133 }
134 match held.apply(&edits) {
135 Ok(applied) => Outcome::Changed(edits, applied),
136 Err(_) => {
140 let edits = Edits::whole(&scene);
141 match held.apply(&edits) {
142 Ok(applied) => Outcome::Changed(edits, applied),
143 Err(e) => Outcome::Problems(vec![Problem {
144 file: self.path.clone(),
145 pos: parse::Pos { line: 1, col: 1 },
146 message: format!("the design engine failed on this design: {e}"),
147 }]),
148 }
149 }
150 }
151 }
152
153 fn again(&mut self, held: &mut dyn Holder, files: &dyn Files) -> Result<Outcome, ()> {
156 let pending: Vec<String> = self.pending.iter().cloned().collect();
157 let scene = held.scene();
158 let mut w = Work {
159 r: Resolver::new(files),
160 files,
161 res: self,
162 scene,
163 edits: Vec::new(),
164 forget: Vec::new(),
165 forget_instances: Vec::new(),
166 covered: HashSet::new(),
167 covered_instances: Vec::new(),
168 own: HashMap::new(),
169 parses: HashMap::new(),
170 indexes: HashMap::new(),
171 failed: false,
172 whole: false,
173 };
174 for key in &pending {
175 if w.res.record.parses.contains_key(key) {
176 w.file(key);
177 }
178 }
179 for key in &pending {
180 let readers: Vec<Vec<u32>> = w
181 .res
182 .record
183 .readers
184 .get(key)
185 .map(|r| r.iter().cloned().collect())
186 .unwrap_or_default();
187 for id in readers {
188 w.reader(key, &id);
189 }
190 }
191 let Work {
192 r,
193 edits,
194 forget,
195 forget_instances,
196 parses,
197 failed,
198 whole,
199 ..
200 } = w;
201 self.elements = r.elements;
202 if failed || !r.problems.is_empty() {
203 return Err(());
204 }
205 if whole {
206 let (scene, record, read) = resolved(files, &self.path).map_err(|_| ())?;
207 return Ok(self.whole(held, scene, record, read));
208 }
209 let record = &mut self.record;
213 for prefix in &forget_instances {
214 record.forget_instances(prefix);
215 }
216 for id in &forget {
217 record.forget(&id.0);
218 record.themed.remove(id);
219 }
220 record.merge(r.record);
221 record.parses.extend(parses);
222 let themed = !record.themed.is_empty();
223 if edits.is_empty() && themed == scene.themed {
224 return Ok(Outcome::Same);
225 }
226 let edits = Edits::onto(scene, edits, &r.images, &r.fonts, themed);
227 let applied = held.apply(&edits).map_err(|_| ())?;
229 for file in r.read {
230 if !self.files.contains(&file) {
231 self.files.push(file);
232 }
233 }
234 Ok(Outcome::Changed(edits, applied))
236 }
237}
238
239impl Record {
240 fn forget_instances(&mut self, prefix: &[u32]) {
243 let gone: Vec<Vec<u32>> = self
244 .instances
245 .range(prefix.to_vec()..)
246 .take_while(|(k, _)| k.starts_with(prefix))
247 .map(|(k, _)| k.clone())
248 .collect();
249 for k in gone {
250 if let Some(i) = self.instances.remove(&k)
251 && let Some(set) = self.by_file.get_mut(&i.file)
252 {
253 set.remove(&k);
254 }
255 }
256 let read: Vec<Vec<u32>> = self
257 .reads
258 .range(prefix.to_vec()..)
259 .take_while(|(k, _)| k.starts_with(prefix))
260 .map(|(k, _)| k.clone())
261 .collect();
262 for k in read {
263 self.forget(&k);
264 }
265 let themed: Vec<NodeId> = self
266 .themed
267 .range(NodeId(prefix.to_vec())..)
268 .take_while(|k| k.0.starts_with(prefix))
269 .cloned()
270 .collect();
271 for k in themed {
272 self.themed.remove(&k);
273 }
274 }
275
276 fn merge(&mut self, other: Record) {
278 self.instances.extend(other.instances);
279 for (file, set) in other.by_file {
280 self.by_file.entry(file).or_default().extend(set);
281 }
282 for (key, set) in other.readers {
283 self.readers.entry(key).or_default().extend(set);
284 }
285 for (id, set) in other.reads {
286 self.reads.entry(id).or_default().extend(set);
287 }
288 self.themed.extend(other.themed);
289 self.parses.extend(other.parses);
290 }
291}
292
293struct Work<'a, 'r> {
296 r: Resolver<'a>,
297 files: &'a dyn Files,
298 res: &'r Resolution,
299 scene: &'r Scene,
301 edits: Vec<Edit>,
302 forget: Vec<NodeId>,
304 forget_instances: Vec<Vec<u32>>,
306 covered: HashSet<NodeId>,
309 covered_instances: Vec<Vec<u32>>,
310 own: HashMap<NodeId, Node>,
312 parses: HashMap<String, Arc<parse::File>>,
314 indexes: HashMap<String, HashMap<u32, Vec<usize>>>,
316 failed: bool,
318 whole: bool,
320}
321
322enum Act<'p> {
325 Own(&'p Element, bool),
327 Whole(&'p Element, &'p Element),
329 Insert {
330 parent: &'p Element,
331 after: Option<&'p Element>,
332 el: &'p Element,
333 },
334 Remove(&'p Element),
335 Move {
336 parent: &'p Element,
337 after: Option<&'p Element>,
338 el: &'p Element,
339 },
340}
341
342impl Work<'_, '_> {
343 fn file(&mut self, path: &str) {
346 let old = self.res.record.parses[path].clone();
347 let Some(source) = self.files.read(path) else {
348 self.failed = true;
349 return;
350 };
351 let new = match self.files.parse(path, &source) {
352 Ok(new) => new,
353 Err(_) => {
354 self.failed = true;
355 return;
356 }
357 };
358 self.parses.insert(path.to_string(), new.clone());
359 self.indexes.remove(path);
360 let mut scope = parse::File {
362 imports: new.imports.clone(),
363 root: Element {
364 id: new.root.id,
365 name: new.root.name.clone(),
366 attrs: new.root.attrs.clone(),
367 children: Vec::new(),
368 pos: new.root.pos,
369 },
370 next_id: new.next_id,
371 };
372 self.r.instance = Vec::new();
373 self.r.current = None;
374 let saved = std::mem::take(&mut self.r.record);
376 self.r.bind_own(path, &mut scope.root);
377 let scoped = self.r.scope(path, &scope);
378 self.r.record = saved;
379 let Some((imports, _)) = scoped else {
380 self.failed = true;
381 return;
382 };
383 let old_imports = import_map(path, &old);
384 let props = |f: &parse::File| f.root.attrs.iter().find(|a| a.name == "props").cloned();
385 let props_same = match (props(&old), props(&new)) {
386 (Some(a), Some(b)) => crate::ids::same_value(&a.value, &b.value),
387 (None, None) => true,
388 _ => false,
389 };
390 let instances: Vec<Vec<u32>> = self
391 .res
392 .record
393 .by_file
394 .get(path)
395 .map(|s| s.iter().cloned().collect())
396 .unwrap_or_default();
397 if new.root.id != old.root.id || new.root.name != old.root.name || !props_same {
398 for i in instances {
400 self.whole_instance(&i);
401 }
402 return;
403 }
404 let retargeted: HashSet<&str> = imports
406 .keys()
407 .chain(old_imports.keys())
408 .filter(|n| imports.get(*n) != old_imports.get(*n))
409 .map(String::as_str)
410 .collect();
411 let is_instance = |el: &Element| imports.contains_key(&el.name);
412 let was_instance = |el: &Element| old_imports.contains_key(&el.name);
413 let mut acts = Vec::new();
414 let mut dup = false;
415 walk(
416 &old.root,
417 &new.root,
418 true,
419 &|el| is_instance(el),
420 &|el| was_instance(el),
421 &retargeted,
422 &mut acts,
423 &mut dup,
424 );
425 if dup {
426 self.failed = true;
427 return;
428 }
429 for i in instances {
430 if self.is_covered_instance(&i) {
431 continue;
432 }
433 let Some(inst) = self.res.record.instances.get(&i).cloned() else {
434 continue;
435 };
436 for act in &acts {
437 self.act(&i, &inst, path, act);
438 }
439 }
440 }
441
442 fn act(&mut self, i: &[u32], inst: &Instance, path: &str, act: &Act) {
444 match *act {
445 Act::Own(el, root) => {
446 let id = if root {
447 inst.root.clone()
448 } else {
449 node_id(i, el)
450 };
451 self.own_again(i, inst, path, el, &id, root);
452 }
453 Act::Whole(el, old) => {
454 let was = self.node_of(i, inst, old, true);
455 self.whole_again(i, inst, path, el, &was);
456 }
457 Act::Insert { parent, after, el } => {
458 let parent_id = self.node_of(i, inst, parent, false);
459 let after = after.map(|a| self.node_of(i, inst, a, false));
460 if self.covered.contains(&parent_id) {
461 return;
462 }
463 let layout = self.layout(&parent_id);
464 let Some(node) = self.subtree(i, inst, path, el, &parent_id, layout) else {
465 return;
466 };
467 self.edits.push(Edit::Insert {
468 parent: Some(parent_id),
469 after,
470 node,
471 });
472 }
473 Act::Remove(old) => {
474 let id = self.node_of(i, inst, old, true);
475 if self.covered.contains(&id) {
476 return;
477 }
478 self.drop_subtree(&id);
479 self.edits.push(Edit::Remove(id));
480 }
481 Act::Move { parent, after, el } => {
482 let id = self.node_of(i, inst, el, false);
483 let parent = self.node_of(i, inst, parent, false);
484 let after = after.map(|a| self.node_of(i, inst, a, false));
485 self.edits.push(Edit::Move { id, parent, after });
486 }
487 }
488 }
489
490 fn node_of(&self, i: &[u32], inst: &Instance, el: &Element, old: bool) -> NodeId {
494 if el.id == root_id(inst) {
495 return inst.root.clone();
496 }
497 let mut key = i.to_vec();
498 key.push(el.id);
499 let made = if old {
501 self.res.record.instances.get(&key)
502 } else {
503 self.r
504 .record
505 .instances
506 .get(&key)
507 .or_else(|| self.res.record.instances.get(&key))
508 };
509 match made {
510 Some(child) => child.root.clone(),
511 None => NodeId(key),
512 }
513 }
514
515 fn layout(&self, parent: &NodeId) -> Option<Layout> {
517 self.own
518 .get(parent)
519 .or_else(|| self.scene.node(parent))
520 .map(|n| n.layout)
521 }
522
523 fn reader(&mut self, key: &str, id: &[u32]) {
525 if self.is_covered_instance(id) {
526 return;
527 }
528 if let Some(inst) = self.res.record.instances.get(id).cloned() {
529 if key.ends_with(super::THEMES_FILE) {
530 self.whole_instance(id);
532 } else {
533 let Some(file) = self.parse_of(&inst.file) else {
535 self.failed = true;
536 return;
537 };
538 self.r.instance = id.to_vec();
539 let mut scope = (*file).clone();
540 scope.root.children.clear();
541 let saved = std::mem::take(&mut self.r.record);
542 if self.r.scope(&inst.file, &scope).is_none() {
543 self.failed = true;
544 }
545 self.r.record = saved;
546 }
547 return;
548 }
549 let node = NodeId(id.to_vec());
550 if self.covered.contains(&node) || self.own.contains_key(&node) {
551 return;
552 }
553 let (prefix, el_id) = id.split_at(id.len() - 1);
554 let Some(inst) = self.res.record.instances.get(prefix).cloned() else {
555 return;
556 };
557 let Some(file) = self.parse_of(&inst.file) else {
558 self.failed = true;
559 return;
560 };
561 let Some(el) = self.element(&inst.file, &file, el_id[0]) else {
562 return;
563 };
564 let root = node == inst.root;
565 self.own_again(prefix, &inst, &inst.file.clone(), &el, &node, root);
566 }
567
568 fn parse_of(&self, path: &str) -> Option<Arc<parse::File>> {
570 self.parses
571 .get(path)
572 .or_else(|| self.res.record.parses.get(path))
573 .cloned()
574 }
575
576 fn element(&mut self, path: &str, file: &parse::File, id: u32) -> Option<Element> {
578 let index = self
579 .indexes
580 .entry(path.to_string())
581 .or_insert_with(|| index(&file.root));
582 let at = index.get(&id)?;
583 let mut el = &file.root;
584 for &i in at {
585 match &el.children[i] {
586 Child::Element(e) => el = e,
587 Child::Text(..) => return None,
588 }
589 }
590 Some(shallow(el))
591 }
592
593 fn whole_instance(&mut self, i: &[u32]) {
596 if self.is_covered_instance(i) {
597 return;
598 }
599 let Some((caller, el_id)) = i.split_last().map(|(l, p)| (p, *l)) else {
600 self.whole = true;
601 return;
602 };
603 let (Some(inst), Some(at)) = (
604 self.res.record.instances.get(caller).cloned(),
605 self.res.record.instances.get(i).cloned(),
606 ) else {
607 self.whole = true;
608 return;
609 };
610 let Some(file) = self.parse_of(&inst.file) else {
611 self.failed = true;
612 return;
613 };
614 let Some(el) = self.element_whole(&inst.file, &file, el_id) else {
615 return;
617 };
618 self.whole_again(caller, &inst, &inst.file.clone(), &el, &at.root);
619 }
620
621 fn element_whole(&mut self, path: &str, file: &parse::File, id: u32) -> Option<Element> {
623 let index = self
624 .indexes
625 .entry(path.to_string())
626 .or_insert_with(|| index(&file.root));
627 let at = index.get(&id)?;
628 let mut el = &file.root;
629 for &i in at {
630 match &el.children[i] {
631 Child::Element(e) => el = e,
632 Child::Text(..) => return None,
633 }
634 }
635 Some(el.clone())
636 }
637
638 fn is_covered_instance(&self, i: &[u32]) -> bool {
639 self.covered_instances.iter().any(|p| i.starts_with(p))
640 }
641
642 fn enter(&mut self, i: &[u32], depth: usize) {
645 self.r.instance = i.to_vec();
646 self.r.stack = (0..=i.len())
647 .filter_map(|k| self.res.record.instances.get(&i[..k]))
648 .map(|inst| inst.file.clone())
649 .collect();
650 self.r.depth = depth;
651 self.r.current = None;
652 }
653
654 fn depth_of(&self, id: &NodeId) -> usize {
656 let order = self.scene.ids.get(id).map_or(0, |o| o.len());
657 order + id.0.len() - 1
658 }
659
660 fn own_again(
663 &mut self,
664 i: &[u32],
665 inst: &Instance,
666 path: &str,
667 el: &Element,
668 id: &NodeId,
669 root: bool,
670 ) {
671 if self.covered.contains(id) || self.own.contains_key(id) {
672 return;
673 }
674 let Some(was) = self.scene.node(id) else {
675 return;
676 };
677 let parent = if root {
678 inst.parent
679 } else {
680 let order = &self.scene.ids.get(id).expect("indexed")[..];
681 let parent = self.scene.at(&order[..order.len() - 1]);
682 parent
683 .and_then(|p| self.own.get(&p.id).or(Some(p)))
684 .map(|p| p.layout)
685 };
686 let depth = self.depth_of(id);
687 self.enter(i, depth);
688 let mut el = shallow(el);
689 self.r.bind_own(path, &mut el);
690 self.r.own_only = true;
691 let node = self
692 .r
693 .element(path, &el, &inst.props, &inst.imports, root, parent);
694 self.r.own_only = false;
695 let Some(mut node) = node else {
696 self.failed = true;
697 return;
698 };
699 if root && let Some(caller) = &inst.caller {
700 overrides(&mut self.r, caller, &mut node, inst.parent);
701 }
702 self.forget.push(id.clone());
703 if !node.same_own(was) {
704 self.edits.push(Edit::Change(node.own()));
705 }
706 self.own.insert(id.clone(), node);
707 }
708
709 fn whole_again(&mut self, i: &[u32], inst: &Instance, path: &str, el: &Element, was: &NodeId) {
712 if self.covered.contains(was) {
713 return;
714 }
715 let Some(order) = self.scene.ids.get(was).cloned() else {
716 return;
717 };
718 let parent_order = &order[..order.len().saturating_sub(1)];
719 let Some(parent) = (!order.is_empty())
720 .then(|| self.scene.at(parent_order))
721 .flatten()
722 else {
723 self.whole = true;
725 return;
726 };
727 let parent_id = parent.id.clone();
728 let after = parent
729 .children
730 .key_before(order.last().expect("not the root"))
731 .and_then(|k| parent.children.get(k))
732 .map(|n| n.id.clone());
733 let layout = self.layout(&parent_id);
734 let Some(node) = self.subtree(i, inst, path, el, &parent_id, layout) else {
735 return;
736 };
737 self.drop_subtree(was);
738 if node.id == *was {
739 self.edits.extend(scene::subtree(self.scene, &order, &node));
740 } else {
741 self.edits.push(Edit::Remove(was.clone()));
742 self.edits.push(Edit::Insert {
743 parent: Some(parent_id),
744 after,
745 node,
746 });
747 }
748 }
749
750 fn subtree(
753 &mut self,
754 i: &[u32],
755 inst: &Instance,
756 path: &str,
757 el: &Element,
758 parent: &NodeId,
759 layout: Option<Layout>,
760 ) -> Option<Node> {
761 let depth = self.depth_of(parent) + 1;
762 self.enter(i, depth);
763 let mut el = el.clone();
764 self.r.bind_element(path, &mut el);
765 let node = self
766 .r
767 .element(path, &el, &inst.props, &inst.imports, false, layout);
768 if node.is_none() {
769 self.failed = true;
770 }
771 node
772 }
773
774 fn drop_subtree(&mut self, id: &NodeId) {
777 let Some(node) = self.scene.node(id) else {
778 return;
779 };
780 let mut todo = vec![node];
781 while let Some(n) = todo.pop() {
782 self.covered.insert(n.id.clone());
783 self.forget.push(n.id.clone());
784 let (prefix, _) = n.id.0.split_at(n.id.0.len() - 1);
785 let instance_root = !prefix.is_empty()
786 && self
787 .res
788 .record
789 .instances
790 .get(prefix)
791 .is_some_and(|inst| inst.root == n.id)
792 && n.id != *id;
793 if instance_root || (n.id == *id && self.is_root_of_instance(&n.id)) {
794 self.forget_instances.push(prefix.to_vec());
795 self.covered_instances.push(prefix.to_vec());
796 for c in &n.children {
798 todo.push(c);
799 }
800 continue;
801 }
802 for c in &n.children {
803 todo.push(c);
804 }
805 }
806 }
807
808 fn is_root_of_instance(&self, id: &NodeId) -> bool {
809 let (prefix, _) = id.0.split_at(id.0.len() - 1);
810 !prefix.is_empty()
811 && self
812 .res
813 .record
814 .instances
815 .get(prefix)
816 .is_some_and(|inst| inst.root == *id)
817 }
818}
819
820fn overrides(r: &mut Resolver, caller: &Caller, root: &mut Node, parent: Option<Layout>) {
822 r.current = Some(root.id.clone());
823 for (attr, by) in &caller.overrides {
824 r.common(&caller.file, by, root, attr, attr.value.clone());
825 r.fill_needs_layout(&caller.file, attr, &attr.value, parent);
826 r.place_needs_no_layout(&caller.file, attr, parent);
827 }
828}
829
830fn root_id(inst: &Instance) -> u32 {
832 *inst.root.0.last().expect("an id")
833}
834
835fn node_id(i: &[u32], el: &Element) -> NodeId {
836 let mut id = i.to_vec();
837 id.push(el.id);
838 NodeId(id)
839}
840
841fn import_map(path: &str, file: &parse::File) -> HashMap<String, String> {
843 file.imports
844 .iter()
845 .filter_map(|i| Some((i.name.clone(), super::join(path, &i.path)?)))
846 .collect()
847}
848
849fn shallow(el: &Element) -> Element {
852 Element {
853 id: el.id,
854 name: el.name.clone(),
855 attrs: el.attrs.clone(),
856 children: el
857 .children
858 .iter()
859 .filter(|c| matches!(c, Child::Text(..)))
860 .cloned()
861 .collect(),
862 pos: el.pos,
863 }
864}
865
866fn index(root: &Element) -> HashMap<u32, Vec<usize>> {
868 let mut out = HashMap::new();
869 let mut todo = vec![(root, Vec::new())];
870 while let Some((el, at)) = todo.pop() {
871 for (i, c) in el.children.iter().enumerate() {
872 if let Child::Element(e) = c {
873 let mut here = at.clone();
874 here.push(i);
875 todo.push((e, here));
876 }
877 }
878 out.insert(el.id, at);
879 }
880 out
881}
882
883fn same_text(a: &Element, b: &Element) -> bool {
885 let texts = |e: &Element| {
886 e.children
887 .iter()
888 .filter_map(|c| match c {
889 Child::Text(parts, _) => Some(
890 parts
891 .iter()
892 .map(|p| match p {
893 TextPart::Literal(s) => (0, s.clone()),
894 TextPart::Prop(s) => (1, s.clone()),
895 TextPart::Theme(s, _) => (2, s.clone()),
896 })
897 .collect::<Vec<_>>(),
898 ),
899 Child::Element(_) => None,
900 })
901 .collect::<Vec<_>>()
902 };
903 texts(a) == texts(b)
904}
905
906fn moved_origin(a: &Element, b: &Element) -> bool {
909 let at = |e: &Element| {
910 e.attrs
911 .iter()
912 .filter(|x| x.name == "shadow" || x.name == "src")
913 .map(|x| (x.pos.line, x.pos.col))
914 .collect::<Vec<_>>()
915 };
916 at(a) != at(b)
917}
918
919fn children(el: &Element) -> Vec<&Element> {
920 el.children
921 .iter()
922 .filter_map(|c| match c {
923 Child::Element(e) => Some(e),
924 Child::Text(..) => None,
925 })
926 .collect()
927}
928
929#[allow(clippy::too_many_arguments)]
934fn walk<'p>(
935 old: &'p Element,
936 new: &'p Element,
937 root: bool,
938 is_instance: &dyn Fn(&Element) -> bool,
939 was_instance: &dyn Fn(&Element) -> bool,
940 retargeted: &HashSet<&str>,
941 out: &mut Vec<Act<'p>>,
942 dup: &mut bool,
943) {
944 let own_same = crate::ids::same_own(old, new) && same_text(old, new);
945 let instance = is_instance(new) || was_instance(old);
946 if !root
947 && (old.name != new.name
948 || is_instance(new) != was_instance(old)
949 || (instance && (!own_same || retargeted.contains(new.name.as_str()))))
950 {
951 out.push(Act::Whole(new, old));
952 return;
953 }
954 if !own_same || moved_origin(old, new) {
955 out.push(Act::Own(new, root));
956 }
957 let layout = |e: &Element| e.attrs.iter().find(|a| a.name == "layout").cloned();
958 let relayout = match (layout(old), layout(new)) {
959 (Some(a), Some(b)) => !crate::ids::same_value(&a.value, &b.value),
960 (None, None) => false,
961 _ => true,
962 };
963 let olds = children(old);
964 let news = children(new);
965 let mut keys = HashSet::new();
967 for c in &news {
968 if let Some(k) = crate::ids::key(c)
969 && !keys.insert(k)
970 {
971 *dup = true;
972 }
973 }
974 let rank: HashMap<u32, usize> = olds.iter().enumerate().map(|(i, e)| (e.id, i)).collect();
975 let ranks: Vec<Option<usize>> = news.iter().map(|e| rank.get(&e.id).copied()).collect();
976 let stay = longest_run(&ranks);
977 let by_id: HashMap<u32, &Element> = olds.iter().map(|e| (e.id, *e)).collect();
978 let mut prev: Option<&Element> = None;
979 for (n, c) in news.iter().enumerate() {
980 match by_id.get(&c.id) {
981 Some(o) => {
982 if !stay[n] {
983 out.push(Act::Move {
984 parent: new,
985 after: prev,
986 el: c,
987 });
988 }
989 walk(o, c, false, is_instance, was_instance, retargeted, out, dup);
990 if relayout {
992 if is_instance(c) {
993 out.push(Act::Whole(c, o));
994 } else {
995 out.push(Act::Own(c, false));
996 }
997 }
998 }
999 None => out.push(Act::Insert {
1000 parent: new,
1001 after: prev,
1002 el: c,
1003 }),
1004 }
1005 prev = Some(c);
1006 }
1007 let kept: HashSet<u32> = news.iter().map(|e| e.id).collect();
1008 for o in olds {
1009 if !kept.contains(&o.id) {
1010 out.push(Act::Remove(o));
1011 }
1012 }
1013}
1014
1015fn longest_run(ranks: &[Option<usize>]) -> Vec<bool> {
1018 let mut tails: Vec<usize> = Vec::new();
1019 let mut before: Vec<Option<usize>> = vec![None; ranks.len()];
1020 for (i, r) in ranks.iter().enumerate() {
1021 let Some(r) = r else { continue };
1022 let at = tails.partition_point(|&t| ranks[t].expect("ranked") < *r);
1023 before[i] = at.checked_sub(1).map(|a| tails[a]);
1024 if at == tails.len() {
1025 tails.push(i);
1026 } else {
1027 tails[at] = i;
1028 }
1029 }
1030 let mut stay = vec![false; ranks.len()];
1031 let mut at = tails.last().copied();
1032 while let Some(i) = at {
1033 stay[i] = true;
1034 at = before[i];
1035 }
1036 stay
1037}
1038
1039#[cfg(test)]
1040mod tests;