diff options
| author | tv <tv@krebsco.de> | 2026-10-31 13:28:55 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-31 13:28:55 +0100 |
| commit | a3d27a7e20f0279d34bb683782947658c48d8300 (patch) | |
| tree | c7b2e2e23e4fcfd70be75be087119ab3ea21f136 /src/document | |
| parent | 7ef7e393fa811eb7dd73d025394d21cadc3a2e3a (diff) | |
one function for changed paths
Diffstat (limited to 'src/document')
| -rw-r--r-- | src/document/store.rs | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/src/document/store.rs b/src/document/store.rs index eeebda8..dff0cfb 100644 --- a/src/document/store.rs +++ b/src/document/store.rs @@ -16,6 +16,67 @@ pub(crate) struct ChangeSet { pub(crate) paths: Vec<Vec<String>>, } +/// How `changed` names a change inside a list. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum InLists { + /// By the item's index: `servers/0/name` (the change publisher). + Index, + /// By the list: `servers` (remakes replay a list whole). + Whole, +} + +/// A store path changes touched, and whether concurrent writes left a conflict there. +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct Changed { + pub(crate) path: Vec<String>, + pub(crate) conflict: bool, +} + +/// The store paths the changes from `before` to `after` touched, as the document +/// reports them (a path may come more than once). A map entry by its key, a counter +/// incremented in a map by its key, and list and text edits by the containing object; +/// inside a list as `lists` says. +pub(crate) fn changed( + doc: &mut AutoCommit, + before: &[automerge::ChangeHash], + after: &[automerge::ChangeHash], + lists: InLists, +) -> Vec<Changed> { + doc.diff(before, after) + .iter() + .map(|patch| Changed { + path: patch_path(patch, lists), + conflict: matches!( + patch.action, + automerge::PatchAction::PutMap { conflict: true, .. } + ), + }) + .collect() +} + +fn patch_path(patch: &automerge::Patch, lists: InLists) -> Vec<String> { + use automerge::PatchAction; + let mut path = Vec::new(); + for (_, prop) in &patch.path { + match (prop, lists) { + (Prop::Map(key), _) => path.push(key.clone()), + (Prop::Seq(index), InLists::Index) => path.push(index.to_string()), + (Prop::Seq(_), InLists::Whole) => return path, + } + } + match &patch.action { + PatchAction::PutMap { key, .. } + | PatchAction::DeleteMap { key, .. } + | PatchAction::Increment { + prop: Prop::Map(key), + .. + } => path.push(key.clone()), + // List and text edits: the containing object. + _ => {} + } + path +} + /// Whether one path is within the other (a change at either touches both). pub(crate) fn paths_related(a: &[String], b: &[String]) -> bool { a.starts_with(b) || b.starts_with(a) |
