Iteration using a Zipper
Zippers can facilitate several different iteration strategies to systematically explore a trie.
ZipperIteration
The ZipperIteration trait extends ZipperMoving to provides methods for traversal of the trie structure.
Path-Byte Based Iteration
to_next_stepmoves the zipper to the next existing position in the trie structure, regardless of whether it contains a value. Calling this method repeatedly will cycle through through all existing positions in the trie, visiting each position once before visiting any position twice. If the focus is not at a leaf, this method descends. If it is at a leaf, it ascends repeatedly until finding a sibling, then moves to that sibling.
Value Based Iteration
to_next_valadvances the zipper to the next position containing a value, using depth-first traversal. Calling this method repeatedly will visit each position containing a value once, before visiting any position twice.
K-Path Iteration
The k_path methods allow iterating over children at depth k relative to the focus (or starting focus). This enables efficiently visiting all paths at a specific distances from a common root, which is useful for certain algorithmic patterns. For example, if your trie contains a number of 4-byte data types (e.g. record IDs, etc.), you can visit the subtrie below each one using a k_path iteration.
descend_first_k_pathdescendskbytes from the current focus, following the first child at each branch until reaching the target depth.to_next_k_pathmoves to the next position at the same depth level, useful for systematically exploring all paths of a given length.
Example: Iterating Fixed-Length Records
#![allow(unused)] fn main() { extern crate pathmap; use pathmap::{PathMap, zipper::*}; // Create a map with various 4-byte keys let mut map = PathMap::new(); map.insert(b"abcd:subtrie1", ()); map.insert(b"abce:subtrie2", ()); map.insert(b"abxy:subtrie3", ()); map.insert(b"wxyz:subtrie4", ()); map.insert(b"ab:", ()); // shorter than 4 bytes let mut zipper = map.read_zipper(); // Find and iterate all 4-byte paths if zipper.descend_first_k_path(4) { println!("Visited 4-byte path: {:?}", std::str::from_utf8(zipper.path()).unwrap()); // Continue to next 4-byte paths while zipper.to_next_k_path(4) { println!("Visited 4-byte path: {:?}", std::str::from_utf8(zipper.path()).unwrap()); } } // Output: // Visited 4-byte path: "abcd" // Visited 4-byte path: "abce" // Visited 4-byte path: "abxy" // Visited 4-byte path: "wxyz" // Note: "ab:" is skipped (too short), longer paths also skipped }
ZipperReadOnlyIteration
The ZipperReadOnlyIteration trait combines ZipperReadOnlyValues with ZipperIteration to provide iteration over values, exposing the same pattern as the std Rust Iterator trait.
to_next_get_valcombines the functionality ofto_next_valwithval, returningSome(&'a V)if positioned at a value, orNoneif iteration is complete.
ZipperReadOnlyConditionalIteration
The ZipperReadOnlyConditionalIteration provides the same functionality as ZipperReadOnlyIteration but for zipper types that require a witness type. See ZipperReadOnlyConditionalValues for more discussion on the use of witness types.
to_next_get_val_with_witnessbehaves likeZipperReadOnlyIteration::to_next_get_val, but requires awitnessto guarantee the lifetime of the returned references.