1use std::collections::{HashMap, HashSet};
7
8use super::{
9 Uses, decode, encode, encode_own, file, files, font_file, font_files, node_id, unnode_id,
10};
11use crate::proto::{self, op::Op as Kind};
12use crate::resolve::{Node, Scene};
13use crate::tree::{NodeId, Order, OrderKey};
14
15pub fn patch(old: &Scene, new: &Scene) -> proto::Patch {
22 proto::Patch {
23 ops: encode_edits(&edits(old, new)),
24 images: new
25 .images
26 .values()
27 .filter(|f| !old.images.contains_key(&f.id))
28 .map(|f| file(f))
29 .collect(),
30 fonts: new
31 .fonts
32 .values()
33 .filter(|f| !old.fonts.contains_key(&f.id))
34 .map(|f| font_file(f))
35 .collect(),
36 themed: new.themed,
37 }
38}
39
40fn op(kind: Kind) -> proto::Op {
41 proto::Op { op: Some(kind) }
42}
43
44#[derive(Debug, Clone, PartialEq)]
48pub enum Edit {
49 Change(Node),
51 Insert {
54 parent: Option<NodeId>,
55 after: Option<NodeId>,
56 node: Node,
57 },
58 Remove(NodeId),
60 Move {
62 id: NodeId,
63 parent: NodeId,
64 after: Option<NodeId>,
65 },
66}
67
68pub fn encode_edits(edits: &[Edit]) -> Vec<proto::Op> {
70 edits
71 .iter()
72 .map(|e| {
73 op(match e {
74 Edit::Change(n) => Kind::Change(encode_own(n)),
75 Edit::Insert {
76 parent,
77 after,
78 node,
79 } => Kind::Insert(proto::Insert {
80 parent: parent.as_ref().map(node_id),
81 after: after.as_ref().map(node_id),
82 node: Some(encode(node)),
83 }),
84 Edit::Remove(id) => Kind::Remove(node_id(id)),
85 Edit::Move { id, parent, after } => Kind::Move(proto::Move {
86 id: Some(node_id(id)),
87 parent: Some(node_id(parent)),
88 after: after.as_ref().map(node_id),
89 }),
90 })
91 })
92 .collect()
93}
94
95fn decode_edits(ops: &[proto::Op]) -> Result<Vec<Edit>, String> {
97 ops.iter()
98 .map(|o| {
99 Ok(match o.op.as_ref().ok_or("an empty operation")? {
100 Kind::Change(n) => Edit::Change(decode(n)?),
101 Kind::Insert(i) => Edit::Insert {
102 parent: i.parent.as_ref().map(|p| unnode_id(Some(p))).transpose()?,
103 after: i.after.as_ref().map(|a| unnode_id(Some(a))).transpose()?,
104 node: decode(i.node.as_ref().ok_or("an insert with no node")?)?,
105 },
106 Kind::Remove(id) => Edit::Remove(unnode_id(Some(id))?),
107 Kind::Move(m) => Edit::Move {
108 id: unnode_id(m.id.as_ref())?,
109 parent: unnode_id(m.parent.as_ref())?,
110 after: m.after.as_ref().map(|a| unnode_id(Some(a))).transpose()?,
111 },
112 })
113 })
114 .collect()
115}
116
117pub fn edits(old: &Scene, new: &Scene) -> Vec<Edit> {
124 if old.root.id != new.root.id {
125 return vec![Edit::Insert {
126 parent: None,
127 after: None,
128 node: new.root.clone(),
129 }];
130 }
131 subtree(old, &[], &new.root)
132}
133
134pub fn subtree(old: &Scene, at: &[OrderKey], new: &Node) -> Vec<Edit> {
138 let within = |id: &NodeId| old.ids.get(id).is_some_and(|o| o.starts_with(at));
139 let mut out = Vec::new();
140 fn kept_below(n: &Node, within: &dyn Fn(&NodeId) -> bool, out: &mut HashSet<NodeId>) -> bool {
142 let mut any = false;
143 for c in &n.children {
144 any |= kept_below(c, within, out) | within(&c.id);
145 }
146 if any {
147 out.insert(n.id.clone());
148 }
149 any
150 }
151 let mut holds = HashSet::new();
152 kept_below(new, &within, &mut holds);
153 let Some(was) = old.at(at) else {
154 return out;
155 };
156 if !was.same_own(new) {
157 out.push(Edit::Change(new.own()));
158 }
159 let mut todo = vec![new];
160 while let Some(p) = todo.pop() {
161 let old_parent = old
164 .ids
165 .get(&p.id)
166 .filter(|o| o.starts_with(at))
167 .and_then(|o| old.at(o));
168 let rank: HashMap<&NodeId, usize> = old_parent
169 .map(|op| {
170 op.children
171 .iter()
172 .enumerate()
173 .map(|(i, c)| (&c.id, i))
174 .collect()
175 })
176 .unwrap_or_default();
177 let ranks: Vec<Option<usize>> = p
178 .children
179 .iter()
180 .map(|c| rank.get(&c.id).copied())
181 .collect();
182 let stay = longest_run(&ranks);
183 let mut prev: Option<&NodeId> = None;
184 for (i, c) in p.children.iter().enumerate() {
185 match old.node(&c.id).filter(|_| within(&c.id)) {
186 Some(was) => {
187 if !stay[i] {
188 out.push(Edit::Move {
189 id: c.id.clone(),
190 parent: p.id.clone(),
191 after: prev.cloned(),
192 });
193 }
194 if !was.same_own(c) {
195 out.push(Edit::Change(c.own()));
196 }
197 todo.push(c);
198 }
199 None => {
200 let node = if holds.contains(&c.id) {
201 todo.push(c);
202 c.own()
203 } else {
204 c.clone()
205 };
206 out.push(Edit::Insert {
207 parent: Some(p.id.clone()),
208 after: prev.cloned(),
209 node,
210 });
211 }
212 }
213 prev = Some(&c.id);
214 }
215 }
216 let kept: HashSet<&NodeId> = {
217 fn ids<'a>(n: &'a Node, out: &mut HashSet<&'a NodeId>) {
218 out.insert(&n.id);
219 for c in &n.children {
220 ids(c, out);
221 }
222 }
223 let mut out = HashSet::new();
224 ids(new, &mut out);
225 out
226 };
227 fn gone(n: &Node, kept: &HashSet<&NodeId>, out: &mut Vec<Edit>) {
228 for c in &n.children {
229 if kept.contains(&c.id) {
230 gone(c, kept, out);
231 } else {
232 out.push(Edit::Remove(c.id.clone()));
233 }
234 }
235 }
236 gone(was, &kept, &mut out);
237 out
238}
239
240fn longest_run(ranks: &[Option<usize>]) -> Vec<bool> {
243 let mut tails: Vec<usize> = Vec::new();
246 let mut before: Vec<Option<usize>> = vec![None; ranks.len()];
247 for (i, r) in ranks.iter().enumerate() {
248 let Some(r) = r else { continue };
249 let at = tails.partition_point(|&t| ranks[t].expect("ranked") < *r);
250 before[i] = at.checked_sub(1).map(|a| tails[a]);
251 if at == tails.len() {
252 tails.push(i);
253 } else {
254 tails[at] = i;
255 }
256 }
257 let mut stay = vec![false; ranks.len()];
258 let mut at = tails.last().copied();
259 while let Some(i) = at {
260 stay[i] = true;
261 at = before[i];
262 }
263 stay
264}
265
266#[derive(Debug, Default, Clone, PartialEq)]
271pub struct Applied {
272 pub removed: Vec<NodeId>,
273 pub placed: Vec<NodeId>,
274 pub changed: Vec<(NodeId, Node)>,
275}
276
277enum Undo {
279 Own(Order, Node),
281 Take(Order),
283 Put(Order, OrderKey, Node),
285 Back(Order, Order, OrderKey),
287 Root(Node),
289}
290
291pub fn apply(scene: &mut Scene, uses: &mut Uses, patch: &proto::Patch) -> Result<Applied, String> {
296 let images = files(&patch.images, &scene.images)?;
297 let fonts = font_files(&patch.fonts, &scene.fonts)?;
298 let edits = decode_edits(&patch.ops)?;
299 apply_edits(scene, uses, edits, images, fonts, patch.themed)
300}
301
302pub fn bring(scene: &mut Scene, uses: &mut Uses, to: &Scene) -> Result<Applied, String> {
307 let edits = edits(scene, to);
308 let images = to.images.clone();
309 let fonts = to.fonts.clone();
310 apply_edits(scene, uses, edits, images, fonts, to.themed)
311}
312
313pub fn apply_edits(
317 scene: &mut Scene,
318 uses: &mut Uses,
319 ops: Vec<Edit>,
320 images: crate::resolve::ImageFiles,
321 fonts: crate::fonts::FontFiles,
322 themed: bool,
323) -> Result<Applied, String> {
324 let mut undo = Vec::new();
325 let mut applied = Applied::default();
326 let done =
327 run(scene, uses, ops, &mut undo, &mut applied).and_then(|()| {
328 if let Some(missing) = uses.images.iter().find(|(id, c)| {
330 **c > 0 && !scene.images.contains_key(id) && !images.contains_key(id)
331 }) {
332 return Err(format!(
333 "the stream never sent the image file {:?}",
334 missing.0
335 ));
336 }
337 if let Some(missing) = uses
338 .fonts
339 .iter()
340 .find(|(id, c)| **c > 0 && !scene.fonts.contains_key(id) && !fonts.contains_key(id))
341 {
342 return Err(format!(
343 "the stream never sent the font file {:?}",
344 missing.0
345 ));
346 }
347 Ok(())
348 });
349 if let Err(e) = done {
350 for u in undo.into_iter().rev() {
351 revert(scene, uses, u);
352 }
353 uses.settle();
354 return Err(e);
355 }
356 scene.images.extend(images);
357 scene.fonts.extend(fonts);
358 uses.settle();
359 scene.images.retain(|id, _| uses.images.contains_key(id));
360 scene.fonts.retain(|id, _| uses.fonts.contains_key(id));
361 scene.themed = themed;
362 Ok(applied)
363}
364
365fn run(
366 scene: &mut Scene,
367 uses: &mut Uses,
368 ops: Vec<Edit>,
369 undo: &mut Vec<Undo>,
370 applied: &mut Applied,
371) -> Result<(), String> {
372 for o in ops {
373 match o {
374 Edit::Change(new) => {
375 let order = order_of(scene, &new.id)?;
376 let place = scene.at_mut(&order).expect("indexed");
377 let mut own = std::mem::replace(place, new);
378 std::mem::swap(&mut place.children, &mut own.children);
379 uses.take_own(&own);
380 uses.add_own(place);
381 applied.changed.push((own.id.clone(), own.clone()));
382 undo.push(Undo::Own(order, own));
383 }
384 Edit::Insert {
385 parent,
386 after,
387 node,
388 } => {
389 let Some(parent) = parent.as_ref() else {
390 if crate::tree::Ids::of(&node).len() != count(&node) {
392 return Err(format!("{} holds a node twice", node.id));
393 }
394 let old = std::mem::replace(&mut scene.root, node);
395 uses.take(&old);
396 uses.add(&scene.root);
397 scene.ids = crate::tree::Ids::of(&scene.root);
398 applied.removed.push(old.id.clone());
399 applied.placed.push(scene.root.id.clone());
400 undo.push(Undo::Root(old));
401 continue;
402 };
403 let parent = order_of(scene, parent)?;
404 let after = after_key(scene, &parent, after.as_ref())?;
405 check_unique(scene, &node, None)?;
406 uses.add(&node);
407 let id = node.id.clone();
408 let order = place(scene, &parent, after.as_ref(), node);
409 applied.placed.push(id);
410 undo.push(Undo::Take(order));
411 }
412 Edit::Remove(id) => {
413 let order = order_of(scene, &id)?;
414 if order.is_empty() {
415 return Err("the root can't be removed".into());
416 }
417 let (parent, key) = (
418 order[..order.len() - 1].to_vec(),
419 order[order.len() - 1].clone(),
420 );
421 let node = take(scene, &order);
422 uses.take(&node);
423 applied.removed.push(id);
424 undo.push(Undo::Put(parent, key, node));
425 }
426 Edit::Move { id, parent, after } => {
427 let from = order_of(scene, &id)?;
428 if from.is_empty() {
429 return Err("the root can't be moved".into());
430 }
431 let parent = order_of(scene, &parent)?;
432 if parent.starts_with(&from) {
433 return Err(format!("{id} can't move under itself"));
434 }
435 let key = from[from.len() - 1].clone();
436 let old_parent = from[..from.len() - 1].to_vec();
437 let after = after_key(scene, &parent, after.as_ref())?;
438 if after.as_ref() == Some(&key) && parent == old_parent {
439 return Err(format!("{id} can't move after itself"));
440 }
441 let node = take(scene, &from);
442 let to = place(scene, &parent, after.as_ref(), node);
443 applied.removed.push(id.clone());
444 applied.placed.push(id);
445 undo.push(Undo::Back(to, old_parent, key));
446 }
447 }
448 }
449 Ok(())
450}
451
452fn count(n: &Node) -> usize {
453 1 + n.children.iter().map(count).sum::<usize>()
454}
455
456fn order_of(scene: &Scene, id: &NodeId) -> Result<Order, String> {
457 scene
458 .ids
459 .get(id)
460 .cloned()
461 .ok_or_else(|| format!("no node {id}"))
462}
463
464fn after_key(
466 scene: &Scene,
467 parent: &Order,
468 after: Option<&NodeId>,
469) -> Result<Option<OrderKey>, String> {
470 let Some(id) = after else { return Ok(None) };
471 let o = order_of(scene, id)?;
472 if o.len() != parent.len() + 1 || !o.starts_with(parent) {
473 return Err(format!("{id} isn't a child of the node it is placed under"));
474 }
475 Ok(o.last().cloned())
476}
477
478fn check_unique(scene: &Scene, node: &Node, but: Option<&NodeId>) -> Result<(), String> {
480 if Some(&node.id) != but && scene.ids.contains(&node.id) {
481 return Err(format!("{} is in the scene already", node.id));
482 }
483 let mut seen = HashSet::new();
484 fn walk<'a>(n: &'a Node, scene: &Scene, seen: &mut HashSet<&'a NodeId>) -> Result<(), String> {
485 if !seen.insert(&n.id) {
486 return Err(format!("{} is in the subtree twice", n.id));
487 }
488 for c in &n.children {
489 if scene.ids.contains(&c.id) {
490 return Err(format!("{} is in the scene already", c.id));
491 }
492 walk(c, scene, seen)?;
493 }
494 Ok(())
495 }
496 walk(node, scene, &mut seen)
497}
498
499fn place(scene: &mut Scene, parent: &Order, after: Option<&OrderKey>, node: Node) -> Order {
502 let p = scene.at_mut(parent).expect("indexed");
503 let key = p.children.insert_after(after, node);
504 let mut order = parent.clone();
505 order.push(key.clone());
506 index(scene, &order);
507 order
508}
509
510fn index(scene: &mut Scene, order: &Order) {
512 let mut at = &scene.root;
513 for k in order {
514 at = at.children.get(k).expect("placed");
515 }
516 scene.ids.add(at, order.clone());
517}
518
519fn take(scene: &mut Scene, order: &Order) -> Node {
521 let (parent, key) = (&order[..order.len() - 1], &order[order.len() - 1]);
522 let node = scene
523 .at_mut(parent)
524 .expect("indexed")
525 .children
526 .remove(key)
527 .expect("indexed");
528 scene.ids.remove(&node);
529 node
530}
531
532fn revert(scene: &mut Scene, uses: &mut Uses, u: Undo) {
533 match u {
534 Undo::Own(order, mut own) => {
535 let place = scene.at_mut(&order).expect("done");
536 std::mem::swap(&mut place.children, &mut own.children);
537 let new = std::mem::replace(place, own);
538 uses.take_own(&new);
539 uses.add_own(scene.at(&order).expect("done"));
540 }
541 Undo::Take(order) => {
542 let node = take(scene, &order);
543 uses.take(&node);
544 }
545 Undo::Put(parent, key, node) => {
546 uses.add(&node);
547 let p = scene.at_mut(&parent).expect("done");
548 p.children.put(key.clone(), node);
549 let mut order = parent;
550 order.push(key);
551 index(scene, &order);
552 }
553 Undo::Back(now, parent, key) => {
554 let node = take(scene, &now);
555 let p = scene.at_mut(&parent).expect("done");
556 p.children.put(key.clone(), node);
557 let mut order = parent;
558 order.push(key);
559 index(scene, &order);
560 }
561 Undo::Root(old) => {
562 let new = std::mem::replace(&mut scene.root, old);
563 uses.take(&new);
564 uses.add(&scene.root);
565 scene.ids = crate::tree::Ids::of(&scene.root);
566 }
567 }
568}
569
570#[cfg(test)]
571mod tests;