1use std::collections::{HashMap, HashSet};
7
8use super::{Ids, ImageFiles, ImageId, Node, Scene};
9use crate::fonts::{FontFiles, FontId};
10use crate::tree::{NodeId, Order, OrderKey};
11
12#[derive(Debug, Clone, PartialEq)]
14pub enum Edit {
15 Change(Node),
17 Insert {
20 parent: Option<NodeId>,
21 after: Option<NodeId>,
22 node: Node,
23 },
24 Remove(NodeId),
26 Move {
28 id: NodeId,
29 parent: NodeId,
30 after: Option<NodeId>,
31 },
32}
33
34#[derive(Debug, Clone, PartialEq, Default)]
38pub struct Edits {
39 pub list: Vec<Edit>,
40 pub images: ImageFiles,
41 pub fonts: FontFiles,
42 pub themed: bool,
44}
45
46impl Edits {
47 pub fn between(old: &Scene, new: &Scene) -> Edits {
52 Edits::onto(old, diff(old, new), &new.images, &new.fonts, new.themed)
53 }
54
55 pub fn onto(
58 scene: &Scene,
59 list: Vec<Edit>,
60 images: &ImageFiles,
61 fonts: &FontFiles,
62 themed: bool,
63 ) -> Edits {
64 Edits {
65 list,
66 images: images
67 .iter()
68 .filter(|(id, _)| !scene.images.contains_key(id))
69 .map(|(id, f)| (*id, f.clone()))
70 .collect(),
71 fonts: fonts
72 .iter()
73 .filter(|(id, _)| !scene.fonts.contains_key(id))
74 .map(|(id, f)| (*id, f.clone()))
75 .collect(),
76 themed,
77 }
78 }
79
80 pub fn whole(scene: &Scene) -> Edits {
82 Edits {
83 list: vec![Edit::Insert {
84 parent: None,
85 after: None,
86 node: scene.root.clone(),
87 }],
88 images: scene.images.clone(),
89 fonts: scene.fonts.clone(),
90 themed: scene.themed,
91 }
92 }
93}
94
95fn diff(old: &Scene, new: &Scene) -> Vec<Edit> {
102 if old.root.id != new.root.id {
103 return vec![Edit::Insert {
104 parent: None,
105 after: None,
106 node: new.root.clone(),
107 }];
108 }
109 subtree(old, &[], &new.root)
110}
111
112pub fn subtree(old: &Scene, at: &[OrderKey], new: &Node) -> Vec<Edit> {
116 let within = |id: &NodeId| old.ids.get(id).is_some_and(|o| o.starts_with(at));
117 let mut out = Vec::new();
118 fn kept_below(n: &Node, within: &dyn Fn(&NodeId) -> bool, out: &mut HashSet<NodeId>) -> bool {
120 let mut any = false;
121 for c in &n.children {
122 any |= kept_below(c, within, out) | within(&c.id);
123 }
124 if any {
125 out.insert(n.id.clone());
126 }
127 any
128 }
129 let mut holds = HashSet::new();
130 kept_below(new, &within, &mut holds);
131 let Some(was) = old.at(at) else {
132 return out;
133 };
134 if !was.same_own(new) {
135 out.push(Edit::Change(new.own()));
136 }
137 let mut todo = vec![new];
138 while let Some(p) = todo.pop() {
139 let old_parent = old
142 .ids
143 .get(&p.id)
144 .filter(|o| o.starts_with(at))
145 .and_then(|o| old.at(o));
146 let rank: HashMap<&NodeId, usize> = old_parent
147 .map(|op| {
148 op.children
149 .iter()
150 .enumerate()
151 .map(|(i, c)| (&c.id, i))
152 .collect()
153 })
154 .unwrap_or_default();
155 let ranks: Vec<Option<usize>> = p
156 .children
157 .iter()
158 .map(|c| rank.get(&c.id).copied())
159 .collect();
160 let stay = longest_run(&ranks);
161 let mut prev: Option<&NodeId> = None;
162 for (i, c) in p.children.iter().enumerate() {
163 match old.node(&c.id).filter(|_| within(&c.id)) {
164 Some(was) => {
165 if !stay[i] {
166 out.push(Edit::Move {
167 id: c.id.clone(),
168 parent: p.id.clone(),
169 after: prev.cloned(),
170 });
171 }
172 if !was.same_own(c) {
173 out.push(Edit::Change(c.own()));
174 }
175 todo.push(c);
176 }
177 None => {
178 let node = if holds.contains(&c.id) {
179 todo.push(c);
180 c.own()
181 } else {
182 c.clone()
183 };
184 out.push(Edit::Insert {
185 parent: Some(p.id.clone()),
186 after: prev.cloned(),
187 node,
188 });
189 }
190 }
191 prev = Some(&c.id);
192 }
193 }
194 let kept: HashSet<&NodeId> = {
195 fn ids<'a>(n: &'a Node, out: &mut HashSet<&'a NodeId>) {
196 out.insert(&n.id);
197 for c in &n.children {
198 ids(c, out);
199 }
200 }
201 let mut out = HashSet::new();
202 ids(new, &mut out);
203 out
204 };
205 fn gone(n: &Node, kept: &HashSet<&NodeId>, out: &mut Vec<Edit>) {
206 for c in &n.children {
207 if kept.contains(&c.id) {
208 gone(c, kept, out);
209 } else {
210 out.push(Edit::Remove(c.id.clone()));
211 }
212 }
213 }
214 gone(was, &kept, &mut out);
215 out
216}
217
218fn longest_run(ranks: &[Option<usize>]) -> Vec<bool> {
221 let mut tails: Vec<usize> = Vec::new();
224 let mut before: Vec<Option<usize>> = vec![None; ranks.len()];
225 for (i, r) in ranks.iter().enumerate() {
226 let Some(r) = r else { continue };
227 let at = tails.partition_point(|&t| ranks[t].expect("ranked") < *r);
228 before[i] = at.checked_sub(1).map(|a| tails[a]);
229 if at == tails.len() {
230 tails.push(i);
231 } else {
232 tails[at] = i;
233 }
234 }
235 let mut stay = vec![false; ranks.len()];
236 let mut at = tails.last().copied();
237 while let Some(i) = at {
238 stay[i] = true;
239 at = before[i];
240 }
241 stay
242}
243
244#[derive(Debug, Default, Clone, PartialEq)]
249pub struct Applied {
250 pub removed: Vec<NodeId>,
251 pub placed: Vec<NodeId>,
252 pub changed: Vec<(NodeId, Node)>,
253}
254
255enum Step {
257 Own(Order, Node),
259 Take(Order),
261 Put(Order, OrderKey, Node),
263 Back(Order, Order, OrderKey),
265 Root(Node),
267}
268
269pub fn apply(scene: &mut Scene, uses: &mut Uses, edits: &Edits) -> Result<Applied, String> {
274 applied(scene, uses, edits).map(|(applied, _)| applied)
275}
276
277pub fn applied(
281 scene: &mut Scene,
282 uses: &mut Uses,
283 edits: &Edits,
284) -> Result<(Applied, Undo), String> {
285 let (images, fonts) = (&edits.images, &edits.fonts);
286 let mut undo = Vec::new();
287 let mut applied = Applied::default();
288 let done =
289 run(scene, uses, &edits.list, &mut undo, &mut applied).and_then(|()| {
290 if let Some(missing) = uses.images.iter().find(|(id, c)| {
292 **c > 0 && !scene.images.contains_key(id) && !images.contains_key(id)
293 }) {
294 return Err(format!(
295 "the stream never sent the image file {:?}",
296 missing.0
297 ));
298 }
299 if let Some(missing) = uses
300 .fonts
301 .iter()
302 .find(|(id, c)| **c > 0 && !scene.fonts.contains_key(id) && !fonts.contains_key(id))
303 {
304 return Err(format!(
305 "the stream never sent the font file {:?}",
306 missing.0
307 ));
308 }
309 Ok(())
310 });
311 if let Err(e) = done {
312 for u in undo.into_iter().rev() {
313 revert(scene, uses, u);
314 }
315 uses.settle();
316 return Err(e);
317 }
318 scene
319 .images
320 .extend(images.iter().map(|(id, f)| (*id, f.clone())));
321 scene
322 .fonts
323 .extend(fonts.iter().map(|(id, f)| (*id, f.clone())));
324 uses.settle();
325 let mut back = Undo {
326 steps: undo,
327 images: ImageFiles::new(),
328 fonts: FontFiles::new(),
329 themed: scene.themed,
330 };
331 scene.images.retain(|id, f| {
332 let kept = uses.images.contains_key(id);
333 if !kept {
334 back.images.insert(*id, f.clone());
335 }
336 kept
337 });
338 scene.fonts.retain(|id, f| {
339 let kept = uses.fonts.contains_key(id);
340 if !kept {
341 back.fonts.insert(*id, f.clone());
342 }
343 kept
344 });
345 scene.themed = edits.themed;
346 Ok((applied, back))
347}
348
349pub struct Undo {
353 steps: Vec<Step>,
354 images: ImageFiles,
355 fonts: FontFiles,
356 themed: bool,
357}
358
359impl Undo {
360 pub fn undo(self, scene: &mut Scene, uses: &mut Uses) {
363 for step in self.steps.into_iter().rev() {
364 revert(scene, uses, step);
365 }
366 uses.settle();
367 scene.images.extend(self.images);
368 scene.fonts.extend(self.fonts);
369 scene.images.retain(|id, _| uses.images.contains_key(id));
370 scene.fonts.retain(|id, _| uses.fonts.contains_key(id));
371 scene.themed = self.themed;
372 }
373}
374
375pub trait Holder {
379 fn scene(&self) -> &Scene;
381
382 fn apply(&mut self, edits: &Edits) -> Result<Applied, String>;
385}
386
387#[cfg(test)]
390pub(crate) struct Bare {
391 pub scene: Scene,
392 pub uses: Uses,
393 pub applies: usize,
395}
396
397#[cfg(test)]
398impl Bare {
399 pub fn new(scene: Scene) -> Bare {
400 Bare {
401 uses: Uses::of(&scene.root),
402 scene,
403 applies: 0,
404 }
405 }
406}
407
408#[cfg(test)]
409impl Holder for Bare {
410 fn scene(&self) -> &Scene {
411 &self.scene
412 }
413
414 fn apply(&mut self, edits: &Edits) -> Result<Applied, String> {
415 self.applies += 1;
416 apply(&mut self.scene, &mut self.uses, edits)
417 }
418}
419
420fn run(
421 scene: &mut Scene,
422 uses: &mut Uses,
423 ops: &[Edit],
424 undo: &mut Vec<Step>,
425 applied: &mut Applied,
426) -> Result<(), String> {
427 for o in ops {
428 match o {
429 Edit::Change(new) => {
430 let order = order_of(scene, &new.id)?;
431 let new = new.clone();
432 let place = scene.at_mut(&order).expect("indexed");
433 let mut own = std::mem::replace(place, new);
434 std::mem::swap(&mut place.children, &mut own.children);
435 uses.take_own(&own);
436 uses.add_own(place);
437 applied.changed.push((own.id.clone(), own.clone()));
438 undo.push(Step::Own(order, own));
439 }
440 Edit::Insert {
441 parent,
442 after,
443 node,
444 } => {
445 let node = node.clone();
446 let Some(parent) = parent.as_ref() else {
447 if Ids::of(&node).len() != count(&node) {
449 return Err(format!("{} holds a node twice", node.id));
450 }
451 let old = std::mem::replace(&mut scene.root, node);
452 uses.take(&old);
453 uses.add(&scene.root);
454 scene.ids = Ids::of(&scene.root);
455 applied.removed.push(old.id.clone());
456 applied.placed.push(scene.root.id.clone());
457 undo.push(Step::Root(old));
458 continue;
459 };
460 let parent = order_of(scene, parent)?;
461 let after = after_key(scene, &parent, after.as_ref())?;
462 check_unique(scene, &node, None)?;
463 uses.add(&node);
464 let id = node.id.clone();
465 let order = place(scene, &parent, after.as_ref(), node);
466 applied.placed.push(id);
467 undo.push(Step::Take(order));
468 }
469 Edit::Remove(id) => {
470 let order = order_of(scene, id)?;
471 if order.is_empty() {
472 return Err("the root can't be removed".into());
473 }
474 let (parent, key) = (
475 order[..order.len() - 1].to_vec(),
476 order[order.len() - 1].clone(),
477 );
478 let node = take(scene, &order);
479 uses.take(&node);
480 applied.removed.push(id.clone());
481 undo.push(Step::Put(parent, key, node));
482 }
483 Edit::Move { id, parent, after } => {
484 let from = order_of(scene, id)?;
485 if from.is_empty() {
486 return Err("the root can't be moved".into());
487 }
488 let parent = order_of(scene, parent)?;
489 if parent.starts_with(&from) {
490 return Err(format!("{id} can't move under itself"));
491 }
492 let key = from[from.len() - 1].clone();
493 let old_parent = from[..from.len() - 1].to_vec();
494 let after = after_key(scene, &parent, after.as_ref())?;
495 if after.as_ref() == Some(&key) && parent == old_parent {
496 return Err(format!("{id} can't move after itself"));
497 }
498 let node = take(scene, &from);
499 let to = place(scene, &parent, after.as_ref(), node);
500 applied.removed.push(id.clone());
501 applied.placed.push(id.clone());
502 undo.push(Step::Back(to, old_parent, key));
503 }
504 }
505 }
506 Ok(())
507}
508
509fn count(n: &Node) -> usize {
510 1 + n.children.iter().map(count).sum::<usize>()
511}
512
513fn order_of(scene: &Scene, id: &NodeId) -> Result<Order, String> {
514 scene
515 .ids
516 .get(id)
517 .cloned()
518 .ok_or_else(|| format!("no node {id}"))
519}
520
521fn after_key(
523 scene: &Scene,
524 parent: &Order,
525 after: Option<&NodeId>,
526) -> Result<Option<OrderKey>, String> {
527 let Some(id) = after else { return Ok(None) };
528 let o = order_of(scene, id)?;
529 if o.len() != parent.len() + 1 || !o.starts_with(parent) {
530 return Err(format!("{id} isn't a child of the node it is placed under"));
531 }
532 Ok(o.last().cloned())
533}
534
535fn check_unique(scene: &Scene, node: &Node, but: Option<&NodeId>) -> Result<(), String> {
537 if Some(&node.id) != but && scene.ids.contains(&node.id) {
538 return Err(format!("{} is in the scene already", node.id));
539 }
540 let mut seen = HashSet::new();
541 fn walk<'a>(n: &'a Node, scene: &Scene, seen: &mut HashSet<&'a NodeId>) -> Result<(), String> {
542 if !seen.insert(&n.id) {
543 return Err(format!("{} is in the subtree twice", n.id));
544 }
545 for c in &n.children {
546 if scene.ids.contains(&c.id) {
547 return Err(format!("{} is in the scene already", c.id));
548 }
549 walk(c, scene, seen)?;
550 }
551 Ok(())
552 }
553 walk(node, scene, &mut seen)
554}
555
556fn place(scene: &mut Scene, parent: &Order, after: Option<&OrderKey>, node: Node) -> Order {
559 let p = scene.at_mut(parent).expect("indexed");
560 let key = p.children.insert_after(after, node);
561 let mut order = parent.clone();
562 order.push(key.clone());
563 index(scene, &order);
564 order
565}
566
567fn index(scene: &mut Scene, order: &Order) {
569 let mut at = &scene.root;
570 for k in order {
571 at = at.children.get(k).expect("placed");
572 }
573 scene.ids.add(at, order.clone());
574}
575
576fn take(scene: &mut Scene, order: &Order) -> Node {
578 let (parent, key) = (&order[..order.len() - 1], &order[order.len() - 1]);
579 let node = scene
580 .at_mut(parent)
581 .expect("indexed")
582 .children
583 .remove(key)
584 .expect("indexed");
585 scene.ids.remove(&node);
586 node
587}
588
589fn revert(scene: &mut Scene, uses: &mut Uses, u: Step) {
590 match u {
591 Step::Own(order, mut own) => {
592 let place = scene.at_mut(&order).expect("done");
593 std::mem::swap(&mut place.children, &mut own.children);
594 let new = std::mem::replace(place, own);
595 uses.take_own(&new);
596 uses.add_own(scene.at(&order).expect("done"));
597 }
598 Step::Take(order) => {
599 let node = take(scene, &order);
600 uses.take(&node);
601 }
602 Step::Put(parent, key, node) => {
603 uses.add(&node);
604 let p = scene.at_mut(&parent).expect("done");
605 p.children.put(key.clone(), node);
606 let mut order = parent;
607 order.push(key);
608 index(scene, &order);
609 }
610 Step::Back(now, parent, key) => {
611 let node = take(scene, &now);
612 let p = scene.at_mut(&parent).expect("done");
613 p.children.put(key.clone(), node);
614 let mut order = parent;
615 order.push(key);
616 index(scene, &order);
617 }
618 Step::Root(old) => {
619 let new = std::mem::replace(&mut scene.root, old);
620 uses.take(&new);
621 uses.add(&scene.root);
622 scene.ids = Ids::of(&scene.root);
623 }
624 }
625}
626
627#[derive(Debug, Default, Clone, PartialEq)]
631pub struct Uses {
632 images: std::collections::HashMap<ImageId, usize>,
633 fonts: std::collections::HashMap<FontId, usize>,
634}
635
636impl Uses {
637 pub fn of(root: &Node) -> Uses {
639 let mut uses = Uses::default();
640 uses.add(root);
641 uses
642 }
643
644 fn add(&mut self, n: &Node) {
645 self.add_own(n);
646 for c in &n.children {
647 self.add(c);
648 }
649 }
650
651 fn add_own(&mut self, n: &Node) {
652 if let Some(i) = &n.image {
653 *self.images.entry(i.id).or_default() += 1;
654 }
655 if let Some(font) = n.text.as_ref().and_then(|t| t.font) {
656 *self.fonts.entry(font).or_default() += 1;
657 }
658 }
659
660 fn take(&mut self, n: &Node) {
661 self.take_own(n);
662 for c in &n.children {
663 self.take(c);
664 }
665 }
666
667 fn take_own(&mut self, n: &Node) {
668 let less = |count: Option<&mut usize>| {
669 if let Some(c) = count {
670 *c -= 1;
671 }
672 };
673 if let Some(i) = &n.image {
674 less(self.images.get_mut(&i.id));
675 }
676 if let Some(font) = n.text.as_ref().and_then(|t| t.font) {
677 less(self.fonts.get_mut(&font));
678 }
679 }
680
681 fn settle(&mut self) {
683 self.images.retain(|_, c| *c > 0);
684 self.fonts.retain(|_, c| *c > 0);
685 }
686}
687
688#[cfg(test)]
689mod tests;