Value Access
Several traits provide access to values stored in the trie; the difference between them is the duration for which the value reference must be borrowed.
ZipperValuesis avilable on most zipper types, and provides short-lived access to values.ZipperReadOnlyValuesis only available on zippers that cannot modify the trie, and privides access to the same values but with a lifetime that allows the zipper to be moved while the borrow is still active.ZipperReadOnlyConditionalValuesmakes lifetime guarantees somewhere in the middle. It allows safe access and some amount of zipper movement, while ensuring it's impossible to modify or delete a value while it is actively borrowed.
ZipperValues
The ZipperValues trait provides most zippers with the ability to access values of type V at the focus position.
Basic Value Access
The val method returns an Option<&V> - Some containing a reference to the value if one exists at the focus, or None if the path exists but has no associated value.
The returned reference has the same lifetime as the method call, which means you many modify the zipper (e.g. move its focus) while the borrow is active. For longer-lived references, use ZipperReadOnlyValues and ZipperReadOnlyConditionalValues.
ZipperReadOnlyValues
The ZipperReadOnlyValues trait provides the same value access as ZipperValues but with a lifetime parameter that is tied to the source of the value, irrespective of the zipper. The zipper may be modified or even dropped, and the borrow remains valid.
This trait is implemented on read-only zipper types where the underlying data structure's lifetime can be guaranteed, and will never be implemented alongside ZipperWriting on the same type.
ZipperReadOnlyConditionalValues
The ZipperReadOnlyConditionalValues trait provides an intermediate approach between ZipperValues and ZipperReadOnlyValues. It uses a witness object to ensure the underlying values remain intact, while still allowing zipper modification.
Witness-Based Access
The trait introduces a witness method that returns a WitnessT type, which acts as a proof that the underlying data remains valid. The get_val_with_witness method then provides a reference with the witness's lifetime rather than relying on a borrow from the zipper.
This design allows the zipper to be moved while ensuring that any borrowed values remain valid as long as the witness remains active.
Example Usage
#![allow(unused)] fn main() { extern crate pathmap; use pathmap::{PathMap, zipper::*}; // Create a PathMap and populate it let mut map = PathMap::new(); map.insert(b"hello", "world"); map.insert(b"hello/nested", "value"); // Convert to a read-only zipper let mut zipper = map.into_read_zipper(b""); // Move to a position with a value zipper.descend_to(b"hello"); assert!(zipper.is_val()); // Create a witness to enable extended lifetime access let witness = zipper.witness(); // Get a reference using the witness let value_ref = zipper.get_val_with_witness(&witness).unwrap(); // The zipper can now be moved while the value reference remains valid zipper.descend_to(b"/nested"); assert!(zipper.is_val()); // The original value reference is still valid because the witness is alive assert_eq!(*value_ref, "world"); // Get another value using the same witness let nested_ref = zipper.get_val_with_witness(&witness).unwrap(); assert_eq!(*nested_ref, "value"); // Both references remain valid until the witness is dropped, even after the // zipper is dropped drop(zipper); assert_eq!(*value_ref, "world"); assert_eq!(*nested_ref, "value"); }