diff --git a/src/write_zipper.rs b/src/write_zipper.rs index b38eed05..93f96422 100644 --- a/src/write_zipper.rs +++ b/src/write_zipper.rs @@ -1343,7 +1343,10 @@ impl <'a, 'path, V: Clone + Send + Sync + Unpin, A: Allocator + 'a> WriteZipperC /// Internal method to re-borrow a WriteZipperCore without the `'path` lifetime fn as_static_path_zipper(&mut self) -> &mut WriteZipperCore<'a, 'static, V, A> { self.prepare_buffers(); - debug_assert!(!self.key.origin_path.is_slice() || self.key.origin_path.len() == 0); + debug_assert!( + !self.key.origin_path.is_slice() || self.key.origin_path.len() == 0, + "a prepared zipper must not retain a borrowed origin path" + ); unsafe{ &mut *(self as *mut WriteZipperCore).cast() } } @@ -2784,6 +2787,8 @@ impl<'k> KeyFields<'k> { self.prefix_buf.reserve(path_len.saturating_sub(self.prefix_buf.len())); if was_unallocated { self.prefix_buf.extend(unsafe{ self.origin_path.as_slice_unchecked() }); + //The path now lives in `prefix_buf`; release the borrowed slice. + self.origin_path.make_len(); } } if self.prefix_idx.capacity() < stack_depth { diff --git a/src/zipper_head.rs b/src/zipper_head.rs index 4353d3f3..796832a6 100644 --- a/src/zipper_head.rs +++ b/src/zipper_head.rs @@ -1523,6 +1523,29 @@ mod tests { assert_eq!(paths, vec![b"ax".to_vec(), b"bx".to_vec(), b"c".to_vec(), b"dx".to_vec()]); } + /// A `ZipperHead` from a write zipper made with a borrowed path, and the zipper used afterwards + #[test] + fn zipper_head_from_write_zipper_at_borrowed_path() { + let mut map = PathMap::::new(); + map.set_val_at(&[1u8, 2, 3], 7); + { + let path = [1u8, 2]; + let mut wz = map.write_zipper_at_path(&path); + { + let zh = wz.zipper_head(); + let mut child = zh.write_zipper_at_exclusive_path(&[4u8]).unwrap(); + child.set_val(1); + } + assert_eq!(wz.origin_path(), &[1u8, 2]); + wz.descend_to(&[5u8]); + wz.set_val(2); + assert_eq!(wz.origin_path(), &[1u8, 2, 5]); + } + assert_eq!(map.val_at(&[1u8, 2, 4]), Some(&1)); + assert_eq!(map.val_at(&[1u8, 2, 5]), Some(&2)); + assert_eq!(map.val_at(&[1u8, 2, 3]), Some(&7)); + } + /// An exclusive zipper at the head's own root, requested more than once, from a head whose /// root sits partway into a node #[test]