Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/dense_byte_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,11 @@ impl<V: Clone + Send + Sync, A: Allocator, Cf: CoFree<V=V, A=A>> ByteNode<Cf, A>
if self.mask.test_bit(k) {
let cf = unsafe { self.values.get_unchecked_mut(ix) };
match cf.rec_mut() {
Some(existing_node) => {
existing_node.join_into(node)
Some(existing_node) => match existing_node.join_into(node) {
//Only two empty nodes join to nothing: the path stays dangling and nothing changes.
// `None` would tell the caller this whole node is empty
AlgebraicStatus::None => AlgebraicStatus::Identity,
status => status,
},
None => {
cf.set_rec(node);
Expand Down
29 changes: 29 additions & 0 deletions src/trie_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,35 @@ mod tests {
assert_eq!(map.val_at(b"foo/bar"), Some(&300));
assert_eq!(map.val_at(b"missing"), None);
}

/// Joining a byte node with a list node whose only contents are dangling paths the byte node
/// also has. Each list slot joins to nothing, which must not make the whole join empty
#[test]
fn map_join_with_dangling_only_list_node() {
let mut a = PathMap::<()>::new();
a.create_path([0u8]);
a.create_path([1u8]);
a.set_val_at([2u8], ());
let mut b = PathMap::<()>::new();
b.create_path([0u8]);
b.create_path([1u8]);
assert!(a.join(&b).contains([2u8]));
}

/// `b` is a clone of `a` plus one value, so the two share nodes. A join may not lose that
/// value in either operand order. Found by the algebraic fuzzer's `join-commutative` law.
#[test]
fn map_join_keeps_value_across_shared_structure() {
let mut a = PathMap::<u64>::new();
for p in [&[0u8, 0, 0, 0, 0][..], &[1, 0, 1], &[1, 0, 3]] {
a.create_path(p);
}
let mut b = a.clone();
b.set_val_at([1u8, 0, 0, 0], 1);

assert_eq!(a.join(&b).val_at([1u8, 0, 0, 0]), Some(&1));
assert_eq!(b.join(&a).val_at([1u8, 0, 0, 0]), Some(&1));
}
}

//GOAT, Consider refactor of zipper traits. `WriteZipper` -> `PathWriter`. Zipper is split into the zipper
Expand Down