From 9dcb0ca5d924caee97ed4288b3ad68ee05e935e3 Mon Sep 17 00:00:00 2001 From: Igor Malovitsa Date: Thu, 17 Sep 2026 05:36:09 +0000 Subject: [PATCH] Allow empty child nodes when joining dangling slots --- src/dense_byte_node.rs | 5 +++-- src/write_zipper.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/dense_byte_node.rs b/src/dense_byte_node.rs index ab6bf2db..f8b570c5 100644 --- a/src/dense_byte_node.rs +++ b/src/dense_byte_node.rs @@ -2079,8 +2079,9 @@ impl, Other AlgebraicResult::None => { //Both nodes hold a dangling path (no value, no onward node) at this byte, e.g. after // `remove_branches(prune = false)`; it stays dangling in the join and is an identity for both - debug_assert!(!lv.has_rec() && !lv.has_val()); - debug_assert!(!rv.has_rec() && !rv.has_val()); + // An empty onward node counts as dangling too + debug_assert!(!lv.has_val() && lv.rec().map_or(true, |n| n.as_tagged().node_is_empty())); + debug_assert!(!rv.has_val() && rv.rec().map_or(true, |n| n.as_tagged().node_is_empty())); unsafe { new_v.get_unchecked_mut(c).write(Cf::new(None, None)) }; }, AlgebraicResult::Identity(mask) => { diff --git a/src/write_zipper.rs b/src/write_zipper.rs index 141128f9..7a97438f 100644 --- a/src/write_zipper.rs +++ b/src/write_zipper.rs @@ -6494,6 +6494,20 @@ mod tests { assert_eq!(keys(&m), ["cax", "cbx", "cdx", "d"]); } + /// Joining child slots whose onward nodes are empty, as left by dropped head writers + #[test] + fn join_k_path_into_empty_child_nodes() { + let mut map = PathMap::::new(); + map.set_val_at(&[0, 0], 1); + { + let zh = map.zipper_head(); + let _w0 = zh.write_zipper_at_exclusive_path(&[0, 2]).unwrap(); + let _w1 = zh.write_zipper_at_exclusive_path(&[1, 2]).unwrap(); + } + map.write_zipper().join_k_path_into(1, false); + assert_eq!(map.get_val_at(&[0]), Some(&1)); + assert_eq!(map.val_count(), 1); + } /// `graft_child_maps` and `graft_masked_branches` below a root path too long for one node key #[test] fn graft_child_maps_long_root() {