1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//! The nodes one document added, changed and removed against another, its base (the `loft
//! status` Feature). A node is matched by its key, so a node that moves stays the same node; it
//! changed when its own content view differs, the hashes of its children left out, so a
//! change to a node is not a change to each of its ancestors.
use crate::document::Document;
use crate::hash::own_views;
use crate::ids::NodeId;
/// The keyed nodes a document added, changed and removed against its base: the added and the
/// changed in the document's order, the removed in the base's.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct NodeChanges {
pub added: Vec<NodeId>,
pub changed: Vec<NodeId>,
pub removed: Vec<NodeId>,
}
impl NodeChanges {
/// Whether the document holds every node of its base unchanged and no other.
#[must_use]
pub fn is_empty(&self) -> bool {
self.added.is_empty() && self.changed.is_empty() && self.removed.is_empty()
}
}
/// The nodes `document` added, changed and removed against `base`.
#[must_use]
pub fn node_changes(base: &Document, document: &Document) -> NodeChanges {
let before = own_views(base);
let after = own_views(document);
let mut changes = NodeChanges::default();
for id in in_order(document) {
match before.get(&id) {
None => changes.added.push(id),
Some(view) if after.get(&id) != Some(view) => changes.changed.push(id),
Some(_) => {}
}
}
changes.removed = in_order(base)
.into_iter()
.filter(|id| !after.contains_key(id))
.collect();
changes
}
/// The keyed nodes of a document, parents before children.
fn in_order(document: &Document) -> Vec<NodeId> {
let mut ids = Vec::new();
document.walk(&mut |node| ids.extend(node.id()));
ids
}