aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-31 03:50:43 +0100
committertv <tv@krebsco.de>2026-10-31 03:50:43 +0100
commit4015c292ed83702c518cdb6dc9158bf11abf250a (patch)
tree36ea5c530394e16dded83d9cebbbeb0e2f5eb359
parent43230f03f7b7bd3ed3b4d45c04529ab3527a5ceb (diff)
unify path walkers
-rw-r--r--src/document/store.rs39
1 files changed, 7 insertions, 32 deletions
diff --git a/src/document/store.rs b/src/document/store.rs
index a55f95d..9134795 100644
--- a/src/document/store.rs
+++ b/src/document/store.rs
@@ -355,7 +355,7 @@ pub(crate) fn read_shallow(
}
/// The resolved value at `path` (the empty path is the root map), through maps and
-/// lists (`step`). `resolve_at` goes through maps only.
+/// lists (`step`).
fn resolve_through(doc: &AutoCommit, path: &[String]) -> Result<Option<Resolved>, StoreError> {
let mut current = Resolved::Maps(vec![automerge::ROOT]);
for segment in path {
@@ -558,35 +558,6 @@ pub(crate) fn insert_path(
Ok(())
}
-/// The merged maps at `path`, creating missing maps on the way.
-fn ensure_maps(doc: &mut AutoCommit, path: &[String]) -> Result<Vec<ObjId>, StoreError> {
- let mut maps = vec![automerge::ROOT];
- for segment in path {
- maps = match resolve(doc, &maps, segment, None)? {
- Some(Resolved::Maps(next)) => next,
- Some(Resolved::Other(..)) => return Err(StoreError::Conflict),
- // A concurrent creation elsewhere is merged on read.
- None => vec![doc.put_object(&maps[0], segment.as_str(), ObjType::Map)?],
- };
- }
- Ok(maps)
-}
-
-/// The resolved value at `path` (the empty path is the root map).
-fn resolve_at(doc: &AutoCommit, path: &[String]) -> Result<Option<Resolved>, StoreError> {
- let mut current = Resolved::Maps(vec![automerge::ROOT]);
- for segment in path {
- let Resolved::Maps(maps) = &current else {
- return Ok(None);
- };
- match resolve(doc, maps, segment, None)? {
- Some(next) => current = next,
- None => return Ok(None),
- }
- }
- Ok(Some(current))
-}
-
/// Makes `dst` hold at `path` what `src`'s merged view holds there: a type-preserving
/// copy (see `materialize_into`) if it exists, a delete otherwise. Replaces the whole
/// subtree at `path`; the path must not be empty.
@@ -607,14 +578,18 @@ pub(crate) fn copy_path_to(
) -> Result<(), StoreError> {
let (leaf, parents) = to.split_last().ok_or(StoreError::NotFound)?;
- let Some(resolved) = resolve_at(src, from)? else {
+ let Some(resolved) = resolve_through(src, from)? else {
return match delete_path(dst, to, false) {
Ok(()) | Err(StoreError::NotFound) => Ok(()),
Err(error) => Err(error),
};
};
- let maps = ensure_maps(dst, parents)?;
+ // Into a map: what is copied are map entries (delta replay names nothing inside a
+ // list: a list is copied whole).
+ let Parent::Maps(maps) = parent_for_write(dst, parents)? else {
+ return Err(StoreError::Conflict);
+ };
delete_in_all(dst, &maps, leaf)?;
let mut trace = from.to_vec();
copy_resolved(