pathmap/
product_zipper.rs

1
2use crate::alloc::{Allocator, GlobalAlloc};
3use crate::utils::ByteMask;
4use crate::trie_node::*;
5use crate::zipper::*;
6use zipper_priv::*;
7
8/// A [Zipper] type that moves through a Cartesian product trie created by extending each path in a primary
9/// trie with the root of the next secondardary trie, doing it recursively for all provided tries
10pub struct ProductZipper<'factor_z, 'trie, V: Clone + Send + Sync, A: Allocator = GlobalAlloc> {
11    z: read_zipper_core::ReadZipperCore<'trie, 'static, V, A>,
12    /// All of the seconday factors beyond the primary factor
13    secondaries: Vec<TrieRef<'trie, V, A>>,
14    /// The indices in the zipper's path that correspond to the start-point of each secondary factor,
15    /// which is conceptually the same as the end-point of each indexed factor
16    factor_paths: Vec<usize>,
17    /// We need to hang onto the zippers for the life of this object, so their trackers stay alive
18    source_zippers: Vec<Box<dyn zipper_priv::ZipperReadOnlyPriv<'trie, V, A> + 'factor_z>>
19}
20
21impl<V: Clone + Send + Sync + Unpin, A: Allocator> core::fmt::Debug for ProductZipper<'_, '_, V, A> {
22    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
23        let path = crate::utils::debug::render_debug_path(self.path(), crate::utils::debug::PathRenderMode::TryAscii).unwrap();
24        f.debug_struct("ProductZipper")
25            .field("path", &path)
26            .field("is_val", &self.is_val())
27            .field("child_cnt", &self.child_count())
28            .field("child_mask", &self.child_mask())
29            .field("factor_cnt", &self.factor_count())
30            .field("focus_factor", &self.focus_factor())
31            .finish()
32    }
33}
34
35impl<'factor_z, 'trie, V: Clone + Send + Sync + Unpin, A: Allocator> ProductZipper<'factor_z, 'trie, V, A> {
36    /// Creates a new `ProductZipper` from the provided zippers
37    ///
38    /// WARNING: passing `other_zippers` that are not at node roots may lead to a panic.  This is
39    /// an implementation issue, but would be very difficult to fix and may not be worth fixing.
40    pub fn new<PrimaryZ, OtherZ, ZipperList>(mut primary_z: PrimaryZ, other_zippers: ZipperList) -> Self
41        where
42        PrimaryZ: ZipperMoving + ZipperReadOnlySubtries<'trie, V, A> + 'factor_z,
43        OtherZ: ZipperReadOnlySubtries<'trie, V, A> + 'factor_z,
44        ZipperList: IntoIterator<Item=OtherZ>,
45    {
46        let other_z_iter = other_zippers.into_iter();
47        let (mut secondaries, mut source_zippers) = match other_z_iter.size_hint() {
48            (_, Some(hint)) => (Vec::with_capacity(hint), Vec::with_capacity(hint+1)),
49            (_, None) => (Vec::new(), Vec::new())
50        };
51
52        //Get the core out of the primary zipper
53        //This unwrap won't fail because all the types that implement `ZipperMoving` have cores
54        let core_z = primary_z.take_core().unwrap();
55        source_zippers.push(Box::new(primary_z) as Box<dyn zipper_priv::ZipperReadOnlyPriv<V, A>>);
56
57        //Get TrieRefs for the remaining zippers
58        for other_z in other_z_iter {
59            let trie_ref: TrieRef<'trie, V, A> = other_z.trie_ref_at_path("").into();
60            secondaries.push(trie_ref);
61            source_zippers.push(Box::new(other_z));
62        }
63
64        Self{z: core_z, factor_paths: Vec::with_capacity(secondaries.len()), secondaries, source_zippers}
65    }
66    /// Creates a new `ProductZipper` from a single zipper, with the expectation that more zippers
67    /// will be added using [new_factors](Self::new_factors)
68    pub fn new_with_primary<PrimaryZ>(mut primary_z: PrimaryZ) -> Self
69        where PrimaryZ: ZipperMoving + ZipperReadOnlySubtries<'trie, V, A> + 'factor_z,
70    {
71        let mut source_zippers = Vec::new();
72
73        //Get the core out of the primary zipper
74        //This unwrap won't fail because all the types that implement `ZipperMoving` have cores
75        let core_z = primary_z.take_core().unwrap();
76        source_zippers.push(Box::new(primary_z) as Box<dyn zipper_priv::ZipperReadOnlyPriv<V, A>>);
77
78        Self{z: core_z, factor_paths: Vec::new(), secondaries: vec![], source_zippers}
79    }
80    /// Appends additional factors to a `ProductZipper`.  This is useful when dealing with
81    /// factor zippers of different types
82    ///
83    /// WARNING: the same warning as above applies about passing other zippers that aren't at node roots
84    pub fn new_factors<OtherZ, ZipperList>(&mut self, other_zippers: ZipperList)
85        where
86        OtherZ: ZipperReadOnlySubtries<'trie, V, A> + 'factor_z,
87        ZipperList: IntoIterator<Item=OtherZ>,
88    {
89        let other_z_iter = other_zippers.into_iter();
90        for other_z in other_z_iter {
91            let trie_ref: TrieRef<'trie, V, A> = other_z.trie_ref_at_path("").into();
92            self.secondaries.push(trie_ref);
93            self.source_zippers.push(Box::new(other_z));
94        }
95    }
96    /// Reserves a path buffer of at least `len` bytes.  Will never shrink the path buffer
97    /// NOTE, this doesn't offer any value over the standard `reserve_buffers` method which is now implemented
98    /// on many zipper types
99    #[deprecated]
100    pub fn reserve_path_buffer(&mut self, reserve_len: usize) {
101        const AVG_BYTES_PER_NODE: usize = 8;
102        self.reserve_buffers(reserve_len, (reserve_len / AVG_BYTES_PER_NODE) + 1);
103    }
104    #[inline]
105    fn has_next_factor(&mut self) -> bool {
106        self.factor_paths.len() < self.secondaries.len()
107    }
108    fn enroll_next_factor(&mut self) {
109        //If there is a `_secondary_root_val`, it lands at the same path as the value where the
110        // paths are joined.  And the value from the earlier zipper takes precedence
111        let (secondary_root, partial_path, _secondary_root_val) = self.secondaries[self.factor_paths.len()].borrow_raw_parts();
112
113        //SAFETY: We won't drop the `secondaries` vec until we're done with the stack of node references
114        let secondary_root: TaggedNodeRef<'trie, V, A> = unsafe{ core::mem::transmute(secondary_root) };
115
116        //TODO! Dealing with hidden root path in a secondary factor is very nasty.  I'm going to punt
117        // on handling this until we move this feature out of the experimental stage.
118        //See "WARNING" in ProductZipper creation methods
119        assert_eq!(partial_path.len(), 0);
120
121        self.z.deregularize();
122        self.z.push_node(secondary_root);
123        self.factor_paths.push(self.path().len());
124    }
125    /// Internal method to descend across the boundary between two factor zippers if the focus is on a value
126    ///
127    /// The ProductZipper's internal representation can be a bit tricky.  See the documentation on
128    /// `product_zipper_test4` for more discussion.
129    #[inline]
130    fn ensure_descend_next_factor(&mut self) {
131        if self.factor_paths.len() < self.secondaries.len() && self.z.child_count() == 0 {
132
133            //We don't want to push the same factor on the stack twice
134            if let Some(factor_path_len) = self.factor_paths.last() {
135                if *factor_path_len == self.path().len() {
136                    return
137                }
138            }
139
140            self.enroll_next_factor();
141        }
142    }
143    /// Internal method to make sure `self.factor_paths` is correct after an ascend method
144    #[inline]
145    fn fix_after_ascend(&mut self) {
146        while let Some(factor_path_start) = self.factor_paths.last() {
147            if self.z.path().len() < *factor_path_start {
148                self.factor_paths.pop();
149            } else {
150                break
151            }
152        }
153    }
154}
155
156impl<'trie, V: Clone + Send + Sync + Unpin + 'trie, A: Allocator + 'trie> ZipperMoving for ProductZipper<'_, 'trie, V, A> {
157    fn at_root(&self) -> bool {
158        self.path().len() == 0
159    }
160    fn reset(&mut self) {
161        self.factor_paths.clear();
162        self.z.reset()
163    }
164    #[inline]
165    fn path(&self) -> &[u8] {
166        self.z.path()
167    }
168    fn val_count(&self) -> usize {
169        assert!(self.focus_factor() == self.factor_count() - 1);
170        self.z.val_count()
171    }
172    fn descend_to_existing<K: AsRef<[u8]>>(&mut self, k: K) -> usize {
173        let k = k.as_ref();
174        let mut descended = 0;
175
176        while descended < k.len() {
177            let this_step = self.z.descend_to_existing(&k[descended..]);
178            if this_step == 0 {
179                break
180            }
181            descended += this_step;
182
183            if self.has_next_factor() {
184                if self.z.child_count() == 0 && self.factor_paths.last().map(|l| *l).unwrap_or(0) < self.path().len() {
185                    self.enroll_next_factor();
186                }
187            } else {
188                break
189            }
190        }
191        descended
192    }
193    fn descend_to<K: AsRef<[u8]>>(&mut self, k: K) {
194        let k = k.as_ref();
195        let descended = self.descend_to_existing(k);
196        if descended != k.len() {
197            self.z.descend_to(&k[descended..]);
198        }
199    }
200    fn descend_to_check<K: AsRef<[u8]>>(&mut self, k: K) -> bool {
201        let k = k.as_ref();
202        let descended = self.descend_to_existing(k);
203        if descended != k.len() {
204            self.z.descend_to(&k[descended..]);
205            return false
206        }
207        true
208    }
209    #[inline]
210    fn descend_to_byte(&mut self, k: u8) {
211        self.z.descend_to_byte(k);
212        if self.z.child_count() == 0 {
213            if self.has_next_factor() {
214                if self.z.path_exists() {
215                    debug_assert!(self.factor_paths.last().map(|l| *l).unwrap_or(0) < self.path().len());
216                    self.enroll_next_factor();
217                    if self.z.node_key().len() > 0 {
218                        self.z.regularize();
219                    }
220                }
221            }
222        }
223    }
224    #[inline]
225    fn descend_to_existing_byte(&mut self, k: u8) -> bool {
226        let descended = self.z.descend_to_existing_byte(k);
227        if descended && self.z.child_count() == 0 {
228            if self.has_next_factor() {
229                debug_assert!(self.factor_paths.last().map(|l| *l).unwrap_or(0) < self.path().len());
230                self.enroll_next_factor();
231                if self.z.node_key().len() > 0 {
232                    self.z.regularize();
233                }
234            }
235        }
236        descended
237    }
238    fn descend_indexed_byte(&mut self, child_idx: usize) -> bool {
239        let result = self.z.descend_indexed_byte(child_idx);
240        self.ensure_descend_next_factor();
241        result
242    }
243    fn descend_first_byte(&mut self) -> bool {
244        let result = self.z.descend_first_byte();
245        self.ensure_descend_next_factor();
246        result
247    }
248    fn descend_until(&mut self) -> bool {
249        let mut moved = false;
250        while self.z.child_count() == 1 {
251            moved |= self.z.descend_until();
252            self.ensure_descend_next_factor();
253            if self.z.is_val() {
254                break;
255            }
256        }
257        moved
258    }
259    fn to_next_sibling_byte(&mut self) -> bool {
260        if self.factor_paths.last().cloned().unwrap_or(0) == self.path().len() {
261            self.factor_paths.pop();
262        }
263        let moved = self.z.to_next_sibling_byte();
264        self.ensure_descend_next_factor();
265        moved
266    }
267    fn to_prev_sibling_byte(&mut self) -> bool {
268        if self.factor_paths.last().cloned().unwrap_or(0) == self.path().len() {
269            self.factor_paths.pop();
270        }
271        let moved = self.z.to_prev_sibling_byte();
272        self.ensure_descend_next_factor();
273        moved
274    }
275    fn ascend(&mut self, steps: usize) -> bool {
276        let ascended = self.z.ascend(steps);
277        self.fix_after_ascend();
278        ascended
279    }
280    fn ascend_byte(&mut self) -> bool {
281        let ascended = self.z.ascend_byte();
282        self.fix_after_ascend();
283        ascended
284    }
285    fn ascend_until(&mut self) -> bool {
286        let ascended = self.z.ascend_until();
287        self.fix_after_ascend();
288        ascended
289    }
290    fn ascend_until_branch(&mut self) -> bool {
291        let ascended = self.z.ascend_until_branch();
292        self.fix_after_ascend();
293        ascended
294    }
295}
296
297impl<'trie, V: Clone + Send + Sync + Unpin + 'trie, A: Allocator + 'trie> ZipperIteration for ProductZipper<'_, 'trie, V, A> { } //Use the default impl for all methods
298
299impl<'trie, V: Clone + Send + Sync + Unpin + 'trie, A: Allocator + 'trie> ZipperValues<V> for ProductZipper<'_, 'trie, V, A> {
300    fn val(&self) -> Option<&V> {
301        unsafe{ self.z.get_val() }
302    }
303}
304
305/// A [`witness`](ZipperReadOnlyConditionalValues::witness) type used by [`ProductZipper`]
306pub struct ProductZipperWitness<V: Clone + Send + Sync, A: Allocator>((ReadZipperWitness<V, A>, Vec<TrieRefOwned<V, A>>));
307
308impl<'factor_z, 'trie, V: Clone + Send + Sync + Unpin + 'trie, A: Allocator + 'trie> ZipperReadOnlyConditionalValues<'trie, V> for ProductZipper<'factor_z, 'trie, V, A> {
309    type WitnessT = ProductZipperWitness<V, A>;
310    fn witness<'w>(&self) -> Self::WitnessT {
311        let primary_witness = self.z.witness();
312        let secondary_witnesses = self.secondaries.iter().filter_map(|trie_ref| {
313            match trie_ref {
314                TrieRef::Owned(trie_ref) => Some(trie_ref.clone()),
315                TrieRef::Borrowed(_) => None
316            }
317        }).collect();
318        ProductZipperWitness((primary_witness, secondary_witnesses))
319    }
320    fn get_val_with_witness<'w>(&self, _witness: &'w Self::WitnessT) -> Option<&'w V> where 'trie: 'w {
321        //SAFETY: We know the witnesses are keeping the nodes we're borrowing from alive
322        unsafe{ self.z.get_val() }
323    }
324}
325
326impl<'trie, V: Clone + Send + Sync + Unpin + 'trie, A: Allocator + 'trie> Zipper for ProductZipper<'_, 'trie, V, A> {
327    #[inline]
328    fn path_exists(&self) -> bool {
329        self.z.path_exists()
330    }
331    fn is_val(&self) -> bool {
332        self.z.is_val()
333    }
334    fn child_count(&self) -> usize {
335        self.z.child_count()
336    }
337    fn child_mask(&self) -> ByteMask {
338        self.z.child_mask()
339    }
340}
341
342impl<V: Clone + Send + Sync + Unpin, A: Allocator> ZipperConcrete for ProductZipper<'_, '_, V, A> {
343    fn shared_node_id(&self) -> Option<u64> { self.z.shared_node_id() }
344    fn is_shared(&self) -> bool { self.z.is_shared() }
345}
346
347impl<V: Clone + Send + Sync + Unpin, A: Allocator> zipper_priv::ZipperPriv for ProductZipper<'_, '_, V, A> {
348    type V = V;
349    type A = A;
350    fn get_focus(&self) -> AbstractNodeRef<'_, Self::V, Self::A> { self.z.get_focus() }
351    fn try_borrow_focus(&self) -> Option<&TrieNodeODRc<Self::V, Self::A>> { self.z.try_borrow_focus() }
352}
353
354impl<'trie, V: Clone + Send + Sync + Unpin + 'trie, A: Allocator + 'trie> ZipperPathBuffer for ProductZipper<'_, 'trie, V, A> {
355    unsafe fn origin_path_assert_len(&self, len: usize) -> &[u8] { unsafe{ self.z.origin_path_assert_len(len) } }
356    fn prepare_buffers(&mut self) { self.z.prepare_buffers() }
357    fn reserve_buffers(&mut self, path_len: usize, stack_depth: usize) { self.z.reserve_buffers(path_len, stack_depth) }
358}
359
360impl<'trie, V: Clone + Send + Sync + Unpin + 'trie, A: Allocator + 'trie> ZipperAbsolutePath for ProductZipper<'_, 'trie, V, A> {
361    fn origin_path(&self) -> &[u8] { self.z.origin_path() }
362    fn root_prefix_path(&self) -> &[u8] { self.z.root_prefix_path() }
363}
364
365/// A [Zipper] type that moves through a Cartesian product trie created by extending each path in a primary
366/// trie with the root of the next secondardary trie, doing it recursively for all provided tries
367///
368/// Compared to [ProductZipper], this is a generic virtual zipper that works without
369/// inspecting the inner workings of primary and secondary zippers.  `ProductZipperG` is more general,
370/// while `ProductZipper` is faster in situations where it can be used.
371///
372/// NOTE: In the future, this generic type will be renamed to `ProductZipper`, and the existing
373/// [ProductZipper] will be renamed something else or removed entirely.
374pub struct ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
375    where
376        V: Clone + Send + Sync,
377{
378    factor_paths: Vec<usize>,
379    primary: PrimaryZ,
380    secondary: Vec<SecondaryZ>,
381    _marker: core::marker::PhantomData<&'trie V>
382}
383
384impl<'trie, PrimaryZ, SecondaryZ, V> ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
385    where
386        V: Clone + Send + Sync,
387        PrimaryZ: ZipperMoving,
388        SecondaryZ: ZipperMoving,
389{
390    /// Creates a new `ProductZipper` from the provided zippers
391    pub fn new<ZipperList>(primary: PrimaryZ, other_zippers: ZipperList) -> Self
392        where
393            ZipperList: IntoIterator<Item=SecondaryZ>,
394            PrimaryZ: ZipperValues<V>,
395            SecondaryZ: ZipperValues<V>,
396    {
397        Self {
398            factor_paths: Vec::new(),
399            primary,
400            secondary: other_zippers.into_iter().collect(),
401            _marker: core::marker::PhantomData,
402        }
403    }
404
405    /// Actual focus factor calculation.
406    /// Returns a valid index into `self.factor_paths`, truncating to parents if requested.
407    fn factor_idx(&self, truncate_up: bool) -> Option<usize> {
408        let len = self.path().len();
409        let mut factor = self.factor_paths.len().checked_sub(1)?;
410        while truncate_up && self.factor_paths[factor] == len {
411            factor = factor.checked_sub(1)?;
412        }
413        Some(factor)
414    }
415
416    /// Returns `true` if the last active factor zipper is positioned at the end of a valid path
417    /// (i.e. a stitch point to the next zipper)
418    fn is_path_end(&self) -> bool {
419        if let Some(idx) = self.factor_idx(false) {
420            self.secondary[idx].child_count() == 0 && self.secondary[idx].path_exists()
421        } else {
422            self.primary.child_count() == 0 && self.primary.path_exists()
423        }
424    }
425
426    /// Remove top factors if they are at root
427    fn exit_factors(&mut self) -> bool {
428        let len = self.path().len();
429        let mut exited = false;
430        while self.factor_paths.last() == Some(&len) {
431            self.factor_paths.pop();
432            exited = true;
433        }
434        exited
435    }
436
437    /// Enter factors at current location if we're on the end of the factor's path
438    fn enter_factors(&mut self) -> bool {
439        let len = self.path().len();
440        // enter the next factor if we can
441        let mut entered = false;
442        if self.factor_paths.len() < self.secondary.len() && self.is_path_end() {
443            self.factor_paths.push(len);
444            entered = true;
445        }
446        entered
447    }
448
449    /// A combination between `ascend_until` and `ascend_until_branch`.
450    /// if `allow_stop_on_val` is `true`, behaves as `ascend_until`
451    fn ascend_cond(&mut self, allow_stop_on_val: bool) -> bool {
452        let mut plen = self.path().len();
453        loop {
454            while self.factor_paths.last() == Some(&plen) {
455                self.factor_paths.pop();
456            }
457            if let Some(idx) = self.factor_idx(false) {
458                let zipper = &mut self.secondary[idx];
459                let before = zipper.path().len();
460                let rv = if allow_stop_on_val {
461                    zipper.ascend_until()
462                } else {
463                    zipper.ascend_until_branch()
464                };
465                let delta = before - zipper.path().len();
466                plen -= delta;
467                self.primary.ascend(delta);
468                if rv && (self.child_count() != 1 || (allow_stop_on_val && self.is_val())) {
469                    return true;
470                }
471            } else {
472                return if allow_stop_on_val {
473                    self.primary.ascend_until()
474                } else {
475                    self.primary.ascend_until_branch()
476                };
477            }
478        }
479    }
480
481    /// a combination between `to_next_sibling` and `to_prev_sibling`
482    fn to_sibling_byte(&mut self, next: bool) -> bool {
483        let Some(&byte) = self.path().last() else {
484            return false;
485        };
486        assert!(self.ascend(1), "must ascend");
487        let child_mask = self.child_mask();
488        let Some(sibling_byte) = (if next {
489            child_mask.next_bit(byte)
490        } else {
491            child_mask.prev_bit(byte)
492        }) else {
493            self.descend_to_byte(byte);
494            return false;
495        };
496        self.descend_to_byte(sibling_byte);
497        true
498    }
499}
500
501impl<'trie, PrimaryZ, SecondaryZ, V> ZipperAbsolutePath
502    for ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
503    where
504        V: Clone + Send + Sync,
505        PrimaryZ: ZipperAbsolutePath,
506        SecondaryZ: ZipperMoving,
507{
508    fn origin_path(&self) -> &[u8] { self.primary.origin_path() }
509    fn root_prefix_path(&self) -> &[u8] { self.primary.root_prefix_path() }
510}
511
512impl<'trie, PrimaryZ, SecondaryZ, V> ZipperConcrete
513    for ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
514    where
515        V: Clone + Send + Sync,
516        PrimaryZ: ZipperMoving + ZipperConcrete,
517        SecondaryZ: ZipperMoving + ZipperConcrete,
518{
519    fn shared_node_id(&self) -> Option<u64> {
520        if let Some(idx) = self.factor_idx(true) {
521            self.secondary[idx].shared_node_id()
522        } else {
523            self.primary.shared_node_id()
524        }
525    }
526    fn is_shared(&self) -> bool {
527        if let Some(idx) = self.factor_idx(true) {
528            self.secondary[idx].is_shared()
529        } else {
530            self.primary.is_shared()
531        }
532    }
533}
534
535impl<'trie, PrimaryZ, SecondaryZ, V> ZipperPathBuffer
536    for ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
537    where
538        V: Clone + Send + Sync,
539        PrimaryZ: ZipperMoving + ZipperPathBuffer,
540        SecondaryZ: ZipperMoving + ZipperPathBuffer,
541{
542    unsafe fn origin_path_assert_len(&self, len: usize) -> &[u8] { unsafe{ self.primary.origin_path_assert_len(len) } }
543    fn prepare_buffers(&mut self) { self.primary.prepare_buffers() }
544    fn reserve_buffers(&mut self, path_len: usize, stack_depth: usize) { self.primary.reserve_buffers(path_len, stack_depth) }
545}
546
547impl<'trie, PrimaryZ, SecondaryZ, V> ZipperValues<V>
548    for ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
549    where
550        V: Clone + Send + Sync,
551        PrimaryZ: ZipperMoving + ZipperValues<V>,
552        SecondaryZ: ZipperMoving + ZipperValues<V>,
553{
554    fn val(&self) -> Option<&V> {
555        if let Some(idx) = self.factor_idx(true) {
556            self.secondary[idx].val()
557        } else {
558            self.primary.val()
559        }
560    }
561}
562
563impl<'trie, PrimaryZ, SecondaryZ, V> ZipperReadOnlyValues<'trie, V>
564    for ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
565    where
566        V: Clone + Send + Sync,
567        PrimaryZ: ZipperMoving + ZipperReadOnlyValues<'trie, V>,
568        SecondaryZ: ZipperMoving + ZipperReadOnlyValues<'trie, V>,
569{
570    fn get_val(&self) -> Option<&'trie V> {
571        if let Some(idx) = self.factor_idx(true) {
572            self.secondary[idx].get_val()
573        } else {
574            self.primary.get_val()
575        }
576    }
577}
578
579impl<'trie, PrimaryZ, SecondaryZ, V> ZipperReadOnlyConditionalValues<'trie, V>
580    for ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
581    where
582        V: Clone + Send + Sync,
583        PrimaryZ: ZipperMoving + ZipperReadOnlyConditionalValues<'trie, V>,
584        SecondaryZ: ZipperMoving + ZipperReadOnlyConditionalValues<'trie, V>,
585{
586    type WitnessT = (PrimaryZ::WitnessT, Vec<SecondaryZ::WitnessT>);
587    fn witness<'w>(&self) -> Self::WitnessT {
588        let primary_witness = self.primary.witness();
589        let secondary_witnesses = self.secondary.iter().map(|secondary| secondary.witness()).collect();
590        (primary_witness, secondary_witnesses)
591    }
592    fn get_val_with_witness<'w>(&self, witness: &'w Self::WitnessT) -> Option<&'w V> where 'trie: 'w {
593        if let Some(idx) = self.factor_idx(true) {
594            self.secondary[idx].get_val_with_witness(&witness.1[idx])
595        } else {
596            self.primary.get_val_with_witness(&witness.0)
597        }
598    }
599}
600
601impl<'trie, PrimaryZ, SecondaryZ, V> Zipper for ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
602    where
603        V: Clone + Send + Sync,
604        PrimaryZ: ZipperMoving + Zipper,
605        SecondaryZ: ZipperMoving + Zipper,
606{
607    fn path_exists(&self) -> bool {
608        if let Some(idx) = self.factor_idx(true) {
609            self.secondary[idx].path_exists()
610        } else {
611            self.primary.path_exists()
612        }
613    }
614    fn is_val(&self) -> bool {
615        if let Some(idx) = self.factor_idx(true) {
616            self.secondary[idx].is_val()
617        } else {
618            self.primary.is_val()
619        }
620    }
621    fn child_count(&self) -> usize {
622        if let Some(idx) = self.factor_idx(false) {
623            self.secondary[idx].child_count()
624        } else {
625            self.primary.child_count()
626        }
627    }
628    fn child_mask(&self) -> ByteMask {
629        if let Some(idx) = self.factor_idx(false) {
630            self.secondary[idx].child_mask()
631        } else {
632            self.primary.child_mask()
633        }
634    }
635}
636
637impl<'trie, PrimaryZ, SecondaryZ, V> ZipperMoving for ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
638    where
639        V: Clone + Send + Sync,
640        PrimaryZ: ZipperMoving,
641        SecondaryZ: ZipperMoving,
642{
643    fn at_root(&self) -> bool {
644        self.path().is_empty()
645    }
646    fn reset(&mut self) {
647        self.factor_paths.clear();
648        for secondary in &mut self.secondary {
649            secondary.reset();
650        }
651        self.primary.reset();
652    }
653    #[inline]
654    fn path(&self) -> &[u8] {
655        self.primary.path()
656    }
657    fn val_count(&self) -> usize {
658        unimplemented!("method will probably get removed")
659    }
660    fn descend_to_existing<K: AsRef<[u8]>>(&mut self, path: K) -> usize {
661        let mut path = path.as_ref();
662        let mut descended = 0;
663        'descend: while !path.is_empty() {
664            self.enter_factors();
665            let good;
666            if let Some(idx) = self.factor_idx(false) {
667                good = self.secondary[idx].descend_to_existing(path);
668                self.primary.descend_to(&path[..good]);
669            } else {
670                good = self.primary.descend_to_existing(path);
671            };
672            if good == 0 {
673                break 'descend;
674            }
675            descended += good;
676            path = &path[good..];
677        }
678        self.enter_factors();
679        descended
680    }
681    fn descend_to<K: AsRef<[u8]>>(&mut self, path: K) {
682        let path = path.as_ref();
683        let good = self.descend_to_existing(path);
684        if good == path.len() {
685            return
686        }
687        let rest = &path[good..];
688        if let Some(idx) = self.factor_idx(false) {
689            self.secondary[idx].descend_to(rest);
690        }
691
692        self.primary.descend_to(rest);
693    }
694    #[inline]
695    fn descend_to_byte(&mut self, k: u8) {
696        self.descend_to([k])
697    }
698    fn descend_indexed_byte(&mut self, child_idx: usize) -> bool {
699        let mask = self.child_mask();
700        let Some(byte) = mask.indexed_bit::<true>(child_idx) else {
701            return false;
702        };
703        self.descend_to_byte(byte);
704        true
705    }
706    #[inline]
707    fn descend_first_byte(&mut self) -> bool {
708        self.descend_indexed_byte(0)
709    }
710    fn descend_until(&mut self) -> bool {
711        let mut moved = false;
712        self.enter_factors();
713        while self.child_count() == 1 {
714            moved |= if let Some(idx) = self.factor_idx(false) {
715                let zipper = &mut self.secondary[idx];
716                let before = zipper.path().len();
717                let rv = zipper.descend_until();
718                let path = zipper.path();
719                if path.len() > before {
720                    self.primary.descend_to(&path[before..]);
721                }
722                rv
723            } else {
724                self.primary.descend_until()
725            };
726            self.enter_factors();
727            if self.is_val() {
728                break
729            }
730        }
731        moved
732    }
733    #[inline]
734    fn to_next_sibling_byte(&mut self) -> bool {
735        self.to_sibling_byte(true)
736    }
737    #[inline]
738    fn to_prev_sibling_byte(&mut self) -> bool {
739        self.to_sibling_byte(false)
740    }
741    fn ascend(&mut self, mut steps: usize) -> bool {
742        while steps > 0 {
743            self.exit_factors();
744            if let Some(idx) = self.factor_idx(false) {
745                let len = self.path().len() - self.factor_paths[idx];
746                let delta = len.min(steps);
747                self.secondary[idx].ascend(delta);
748                self.primary.ascend(delta);
749                steps -= delta;
750            } else {
751                return self.primary.ascend(steps);
752            }
753        }
754        true
755    }
756    #[inline]
757    fn ascend_byte(&mut self) -> bool {
758        self.ascend(1)
759    }
760    #[inline]
761    fn ascend_until(&mut self) -> bool {
762        self.ascend_cond(true)
763    }
764    #[inline]
765    fn ascend_until_branch(&mut self) -> bool {
766        self.ascend_cond(false)
767    }
768}
769
770impl<'trie, PrimaryZ, SecondaryZ, V> ZipperIteration
771for ProductZipperG<'trie, PrimaryZ, SecondaryZ, V>
772    where
773        V: Clone + Send + Sync,
774        PrimaryZ: ZipperIteration,
775        SecondaryZ: ZipperIteration,
776{ } //Use the default impl for all methods
777
778impl_zipper_debug!(
779    impl<V: Clone + Send + Sync + Unpin, PrimaryZ, SecondaryZ> core::fmt::Debug for ProductZipperG<'_, PrimaryZ, SecondaryZ, V>
780        where PrimaryZ: ZipperAbsolutePath, SecondaryZ: ZipperAbsolutePath
781);
782
783/// Implemented on both [ProductZipper] types to provide abstraction across them
784pub trait ZipperProduct : ZipperMoving + Zipper + ZipperAbsolutePath + ZipperIteration {
785    /// Returns the number of factors composing the `ProductZipper`
786    ///
787    /// The minimum returned value will be 1 because the primary factor is counted.
788    fn factor_count(&self) -> usize;
789
790    /// Returns the index of the factor containing the `ProductZipper` focus
791    ///
792    /// Returns `0` if the focus is in the primary factor.  The returned value will always be
793    /// `zipper.focus_factor() < zipper.factor_count()`.
794    fn focus_factor(&self) -> usize;
795
796    /// Returns a slice of the path indices that represent the end-points of the portion of the path from each
797    /// factor
798    ///
799    /// The returned slice will have a length of [`focus_factor`](ZipperProduct::focus_factor), so the factor
800    /// containing the current focus has will not be included.
801    ///
802    /// Indices will be offsets into the buffer returned by [path](ZipperMoving::path).  To get an offset into
803    /// [origin_path](ZipperAbsolutePath::origin_path), add the length of the prefix path from
804    /// [root_prefix_path](ZipperAbsolutePath::root_prefix_path).
805    fn path_indices(&self) -> &[usize];
806}
807
808impl<'trie, V: Clone + Send + Sync + Unpin, A: Allocator> ZipperProduct for ProductZipper<'_, 'trie, V, A> {
809    fn factor_count(&self) -> usize {
810        self.secondaries.len() + 1
811    }
812    fn focus_factor(&self) -> usize {
813        match self.factor_paths.last() {
814            Some(factor_path_len) => {
815                let factor_idx = self.factor_paths.len();
816                if *factor_path_len < self.path().len() {
817                    factor_idx
818                } else {
819                    factor_idx - 1
820                }
821            },
822            None => 0
823        }
824    }
825    fn path_indices(&self) -> &[usize] {
826        &self.factor_paths
827    }
828}
829
830impl <'trie, PZ, SZ, V: crate::TrieValue> ZipperProduct for ProductZipperG<'trie, PZ, SZ, V> where
831    PZ : ZipperMoving + Zipper + ZipperAbsolutePath + ZipperIteration,
832    SZ : ZipperMoving + Zipper + ZipperAbsolutePath + ZipperIteration {
833    fn focus_factor(&self) -> usize {
834        self.factor_idx(true).map_or(0, |x| x + 1)
835    }
836    fn factor_count(&self) -> usize {
837        self.secondary.len() + 1
838    }
839    fn path_indices(&self) -> &[usize] {
840        &self.factor_paths
841    }
842}
843
844/// A simple wrapper that lifts a Zipper into a single-factor product zipper
845pub struct OneFactor<Z> {
846    z: Z
847}
848
849impl <Z : ZipperMoving + Zipper + ZipperAbsolutePath + ZipperIteration> OneFactor<Z> {
850    pub fn new(z: Z) -> Self {
851        OneFactor{ z }
852    }
853}
854
855impl <Z : ZipperMoving + Zipper + ZipperAbsolutePath + ZipperIteration> ZipperProduct for OneFactor<Z> {
856    fn focus_factor(&self) -> usize {
857        0
858    }
859    fn factor_count(&self) -> usize {
860        1
861    }
862    fn path_indices(&self) -> &[usize] {
863        &[]
864    }
865}
866
867// TODO GOAT I feel like we should move this lens to zipper.rs and use it to replace more boilerplate there
868macro_rules! lens {
869    (ZipperIteration $e:ident) => {
870        fn to_next_val(&mut self) -> bool { self.$e.to_next_val() }
871        fn descend_first_k_path(&mut self, k: usize) -> bool { self.$e.descend_first_k_path(k) }
872        fn to_next_k_path(&mut self, k: usize) -> bool { self.$e.to_next_k_path(k) }
873    };
874    (ZipperAbsolutePath $e:ident) => {
875        fn origin_path(&self) -> &[u8] { self.$e.origin_path() }
876        fn root_prefix_path(&self) -> &[u8] { self.$e.root_prefix_path() }
877    };
878    (Zipper $e:ident) => {
879        #[inline] fn path_exists(&self) -> bool { self.$e.path_exists() }
880        fn is_val(&self) -> bool { self.$e.is_val() }
881        fn child_count(&self) -> usize { self.$e.child_count() }
882        fn child_mask(&self) -> ByteMask { self.$e.child_mask() }
883    };
884    (ZipperMoving $e:ident) => {
885        fn at_root(&self) -> bool { self.$e.at_root() }
886        fn reset(&mut self) { self.$e.reset() }
887        #[inline] fn path(&self) -> &[u8] { self.$e.path() }
888        fn val_count(&self) -> usize { self.$e.val_count() }
889        fn descend_to<K: AsRef<[u8]>>(&mut self, k: K) { self.$e.descend_to(k) }
890        fn descend_to_check<K: AsRef<[u8]>>(&mut self, k: K) -> bool { self.$e.descend_to_check(k) }
891        fn descend_to_existing<K: AsRef<[u8]>>(&mut self, k: K) -> usize { self.$e.descend_to_existing(k) }
892        fn descend_to_val<K: AsRef<[u8]>>(&mut self, k: K) -> usize { self.$e.descend_to_val(k) }
893        fn descend_to_byte(&mut self, k: u8) { self.$e.descend_to_byte(k) }
894        fn descend_to_existing_byte(&mut self, k: u8) -> bool { self.$e.descend_to_existing_byte(k) }
895        fn descend_indexed_byte(&mut self, child_idx: usize) -> bool { self.$e.descend_indexed_byte(child_idx) }
896        fn descend_first_byte(&mut self) -> bool { self.$e.descend_first_byte() }
897        fn descend_until(&mut self) -> bool { self.$e.descend_until() }
898        fn to_next_sibling_byte(&mut self) -> bool { self.$e.to_next_sibling_byte() }
899        fn to_prev_sibling_byte(&mut self) -> bool { self.$e.to_prev_sibling_byte() }
900        fn ascend(&mut self, steps: usize) -> bool { self.$e.ascend(steps) }
901        fn ascend_byte(&mut self) -> bool { self.$e.ascend_byte() }
902        fn ascend_until(&mut self) -> bool { self.$e.ascend_until() }
903        fn ascend_until_branch(&mut self) -> bool { self.$e.ascend_until_branch() }
904        fn to_next_step(&mut self) -> bool { self.$e.to_next_step() }
905    };
906}
907
908impl<V : Clone + Send + Sync + Unpin, Z : ZipperForking<V>> ZipperForking<V> for OneFactor<Z> {
909    type ReadZipperT<'a> = Z::ReadZipperT<'a> where Z: 'a;
910    fn fork_read_zipper<'a>(&'a self) -> Self::ReadZipperT<'a> {
911        self.z.fork_read_zipper()
912    }
913}
914
915impl <Z : Zipper> Zipper for OneFactor<Z> { lens!(Zipper z); }
916impl <Z : ZipperAbsolutePath> ZipperAbsolutePath for OneFactor<Z> { lens!(ZipperAbsolutePath z); }
917impl <Z : ZipperMoving> ZipperMoving for OneFactor<Z> { lens!(ZipperMoving z); }
918impl <Z : ZipperIteration> ZipperIteration for OneFactor<Z> { lens!(ZipperIteration z); }
919
920#[cfg(test)]
921mod tests {
922    use fast_slice_utils::find_prefix_overlap;
923    use crate::utils::ByteMask;
924    use crate::zipper::*;
925    use crate::PathMap;
926    use crate::morphisms::Catamorphism;
927
928    macro_rules! impl_product_zipper_tests {
929        ($mod:ident, $ProductZipper:ident, $convert:ident) => {
930            impl_product_zipper_tests!($mod, $ProductZipper, $convert, read_zipper);
931        };
932        ($mod:ident, $ProductZipper:ident, $convert:ident, $read_zipper_u64:ident) => {
933            // --- START OF MACRO GENERATED MOD ---
934            pub mod $mod {
935                use super::*;
936    /// Tests a very simple two-level product zipper
937    #[test]
938    fn product_zipper_test1() {
939        let keys = [b"AAa", b"AAb", b"AAc"];
940        let keys2 = [b"DDd", b"EEe", b"FFf"];
941        let map = PathMap::from_iter(keys.into_iter().enumerate().map(|(i, v)| (v, i as u64)));
942        let map2 = PathMap::from_iter(keys2.into_iter().enumerate().map(|(i, v)| (v, (i + 1000) as u64)));
943        $convert!(*map);
944        $convert!(*map2);
945
946        let rz = map.$read_zipper_u64();
947        let mut pz = $ProductZipper::new(rz, [map2.$read_zipper_u64()]);
948
949        //Descend within the first factor
950        pz.descend_to(b"AA");
951        assert!(pz.path_exists());
952        assert_eq!(pz.path(), b"AA");
953        assert_eq!(pz.val(), None);
954        assert_eq!(pz.child_count(), 3);
955        pz.descend_to(b"a");
956        assert!(pz.path_exists());
957        assert_eq!(pz.path(), b"AAa");
958        assert_eq!(pz.val(), Some(&0));
959        assert_eq!(pz.child_count(), 3);
960
961        //Step to the next factor
962        pz.descend_to(b"DD");
963        assert!(pz.path_exists());
964        assert_eq!(pz.path(), b"AAaDD");
965        assert_eq!(pz.val(), None);
966        assert_eq!(pz.child_count(), 1);
967        pz.descend_to(b"d");
968        assert!(pz.path_exists());
969        assert_eq!(pz.path(), b"AAaDDd");
970        assert_eq!(pz.val(), Some(&1000));
971        assert_eq!(pz.child_count(), 0);
972        pz.descend_to(b"GGg");
973        assert!(!pz.path_exists());
974        assert_eq!(pz.path(), b"AAaDDdGGg");
975        assert_eq!(pz.val(), None);
976        assert_eq!(pz.child_count(), 0);
977
978        //Test Reset, if the zipper was in another factor
979        pz.reset();
980        assert_eq!(pz.path(), b"");
981        pz.descend_to(b"AA");
982        assert!(pz.path_exists());
983        assert_eq!(pz.path(), b"AA");
984        assert_eq!(pz.val(), None);
985        assert_eq!(pz.child_count(), 3);
986
987        //Try to descend to a non-existent path that would be within the first factor
988        pz.descend_to(b"aBBb");
989        assert!(!pz.path_exists());
990        assert_eq!(pz.path(), b"AAaBBb");
991        assert_eq!(pz.val(), None);
992        assert_eq!(pz.child_count(), 0);
993
994        //Now descend to the second factor in one jump
995        pz.reset();
996        pz.descend_to(b"AAaDD");
997        assert!(pz.path_exists());
998        assert_eq!(pz.path(), b"AAaDD");
999        assert_eq!(pz.val(), None);
1000        assert_eq!(pz.child_count(), 1);
1001        pz.reset();
1002        pz.descend_to(b"AAaDDd");
1003        assert!(pz.path_exists());
1004        assert_eq!(pz.path(), b"AAaDDd");
1005        assert_eq!(pz.val(), Some(&1000));
1006        assert_eq!(pz.child_count(), 0);
1007        pz.descend_to(b"GG");
1008        assert!(!pz.path_exists());
1009        assert_eq!(pz.path(), b"AAaDDdGG");
1010        assert_eq!(pz.val(), None);
1011        assert_eq!(pz.child_count(), 0);
1012
1013        //Make sure we can ascend out of a secondary factor; in this sub-test we'll hit the path middles
1014        assert!(pz.ascend(1));
1015        assert_eq!(pz.val(), None);
1016        assert_eq!(pz.path(), b"AAaDDdG");
1017        assert_eq!(pz.child_count(), 0);
1018        assert!(pz.ascend(3));
1019        assert_eq!(pz.path(), b"AAaD");
1020        assert_eq!(pz.val(), None);
1021        assert_eq!(pz.child_count(), 1);
1022        assert!(pz.ascend(2));
1023        assert_eq!(pz.path(), b"AA");
1024        assert_eq!(pz.val(), None);
1025        assert_eq!(pz.child_count(), 3);
1026        assert!(!pz.ascend(3));
1027        assert_eq!(pz.path(), b"");
1028        assert_eq!(pz.val(), None);
1029        assert_eq!(pz.child_count(), 1);
1030        assert!(pz.at_root());
1031
1032        pz.descend_to(b"AAaDDdGG");
1033        assert!(!pz.path_exists());
1034        assert_eq!(pz.path(), b"AAaDDdGG");
1035        assert_eq!(pz.val(), None);
1036        assert_eq!(pz.child_count(), 0);
1037
1038        //Now try to hit the path transition points
1039        assert!(pz.ascend(2));
1040        assert_eq!(pz.path(), b"AAaDDd");
1041        assert_eq!(pz.val(), Some(&1000));
1042        assert_eq!(pz.child_count(), 0);
1043        assert!(pz.ascend(3));
1044        assert_eq!(pz.path(), b"AAa");
1045        assert_eq!(pz.val(), Some(&0));
1046        assert_eq!(pz.child_count(), 3);
1047        assert!(pz.ascend(3));
1048        assert_eq!(pz.path(), b"");
1049        assert_eq!(pz.val(), None);
1050        assert_eq!(pz.child_count(), 1);
1051        assert!(pz.at_root());
1052    }
1053
1054    /// Tests a 3-level product zipper, with a catamorphism, and no funny-business in the tries
1055    ///
1056    ///TODO: Port this test away from the deprecated `SplitCata` / `SplitCataJumping` API
1057    #[test]
1058    fn product_zipper_test2() {
1059        let lpaths = ["abcdefghijklmnopqrstuvwxyz".as_bytes(), "arrow".as_bytes(), "x".as_bytes()];
1060        let rpaths = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ".as_bytes(), "a".as_bytes(), "bow".as_bytes()];
1061        let epaths = ["foo".as_bytes(), "pho".as_bytes()];
1062        let l = PathMap::from_iter(lpaths.iter().map(|x| (x, ())));
1063        let r = PathMap::from_iter(rpaths.iter().map(|x| (x, ())));
1064        let e = PathMap::from_iter(epaths.iter().map(|x| (x, ())));
1065        $convert!(l);
1066        $convert!(r);
1067        $convert!(e);
1068        let p = $ProductZipper::new(l.read_zipper(), [r.read_zipper(), e.read_zipper()]);
1069
1070        let mut map_cnt = 0;
1071        let mut collapse_cnt = 0;
1072        #[allow(deprecated)]
1073        p.into_cata_side_effect(crate::morphisms::SplitCata::new(
1074            |_, _p| {
1075                // println!("Map  {}", String::from_utf8_lossy(_p));
1076                map_cnt += 1;
1077            },
1078            |_, _, _p| {
1079                // println!("Col *{}", String::from_utf8_lossy(_p));
1080                collapse_cnt += 1
1081            },
1082            |_, _, _| ()));
1083
1084        // println!("{map_cnt} {collapse_cnt}");
1085        assert_eq!(map_cnt, 18);
1086        assert_eq!(collapse_cnt, 12);
1087    }
1088
1089    /// Same as `product_zipper_test2` but with tries that contain values along the paths
1090    ///
1091    ///TODO: Port this test away from the deprecated `SplitCata` / `SplitCataJumping` API
1092    #[test]
1093    fn product_zipper_test3() {
1094        let lpaths = ["abcdefghijklmnopqrstuvwxyz".as_bytes(), "arrow".as_bytes(), "x".as_bytes(), "arr".as_bytes()];
1095        let rpaths = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ".as_bytes(), "a".as_bytes(), "bow".as_bytes(), "bo".as_bytes()];
1096        let epaths = ["foo".as_bytes(), "pho".as_bytes(), "f".as_bytes()];
1097        let l = PathMap::from_iter(lpaths.iter().map(|x| (x, ())));
1098        let r = PathMap::from_iter(rpaths.iter().map(|x| (x, ())));
1099        let e = PathMap::from_iter(epaths.iter().map(|x| (x, ())));
1100        $convert!(l);
1101        $convert!(r);
1102        $convert!(e);
1103        let p = $ProductZipper::new(l.read_zipper(), [r.read_zipper(), e.read_zipper()]);
1104
1105        let mut map_cnt = 0;
1106        let mut collapse_cnt = 0;
1107        #[allow(deprecated)]
1108        p.into_cata_side_effect(crate::morphisms::SplitCata::new(
1109            |_, _p| {
1110                // println!("Map  {}", String::from_utf8_lossy(_p));
1111                map_cnt += 1;
1112            },
1113            |_, _, _p| {
1114                // println!("Col *{}", String::from_utf8_lossy(_p));
1115                collapse_cnt += 1
1116            },
1117            |_, _, _| ()));
1118
1119        // println!("{map_cnt} {collapse_cnt}");
1120        assert_eq!(map_cnt, 18);
1121        assert_eq!(collapse_cnt, 25);
1122    }
1123
1124    /// Narrows in on some tricky behavior surrounding values at factor transitions.  The issue is that the
1125    /// same path can be represented with more than one regularized form.  In the test below, the path:
1126    /// `abcdefghijklmnopqrstuvwxyzbo` falls on the transition point (value) in the second factor, signaling
1127    /// a step to the third factor.
1128    ///
1129    /// However, the regularization behavior means that the zipper's `focus_node` will be regularized to point
1130    /// to the 'w' in "bow".  This doesn't actually represent the 'w', but rather represents "the node that
1131    /// follows 'o', which just happens to be 'w'".  On ascent, however, the `focus_node` will be the base
1132    /// of the third factor, e.g. the {'f', 'p'} node.
1133    ///
1134    /// These are both valid configurations for the zipper and the user-facing methods should behave the same
1135    /// regardless of the config.
1136    ///
1137    /// NOTE: This logic is the same regardless of node type, but using `all_dense_nodes` will shake out any
1138    /// problems more aggressively.
1139    #[test]
1140    fn product_zipper_test4() {
1141        let lpaths = ["abcdefghijklmnopqrstuvwxyz".as_bytes(), "arrow".as_bytes(), "x".as_bytes(), "arr".as_bytes()];
1142        let rpaths = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ".as_bytes(), "a".as_bytes(), "bow".as_bytes(), "bo".as_bytes()];
1143        let epaths = ["foo".as_bytes(), "pho".as_bytes(), "f".as_bytes()];
1144        let l = PathMap::from_iter(lpaths.iter().map(|x| (x, ())));
1145        let r = PathMap::from_iter(rpaths.iter().map(|x| (x, ())));
1146        let e = PathMap::from_iter(epaths.iter().map(|x| (x, ())));
1147        $convert!(l);
1148        $convert!(r);
1149        $convert!(e);
1150        let mut p = $ProductZipper::new(l.read_zipper(), [r.read_zipper(), e.read_zipper()]);
1151
1152        p.descend_to("abcdefghijklmnopqrstuvwxyzbow");
1153        assert!(p.is_val());
1154        assert_eq!(p.child_count(), 2);
1155        assert_eq!(p.child_mask(), ByteMask::from_iter([b'p', b'f']));
1156
1157        p.descend_first_byte();
1158        p.ascend_byte();
1159        assert!(p.is_val());
1160        assert_eq!(p.child_count(), 2);
1161        assert_eq!(p.child_mask(), ByteMask::from_iter([b'p', b'f']));
1162    }
1163
1164    #[test]
1165    fn product_zipper_test5() {
1166        let lpaths = ["abcdefghijklmnopqrstuvwxyz".as_bytes(), "arrow".as_bytes(), "x".as_bytes(), "arr".as_bytes()];
1167        let rpaths = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ".as_bytes(), "a".as_bytes(), "bow".as_bytes(), "bo".as_bytes()];
1168        let epaths = ["foo".as_bytes(), "pho".as_bytes(), "f".as_bytes()];
1169        let l = PathMap::from_iter(lpaths.iter().map(|x| (x, ())));
1170        let r = PathMap::from_iter(rpaths.iter().map(|x| (x, ())));
1171        let e = PathMap::from_iter(epaths.iter().map(|x| (x, ())));
1172        $convert!(l);
1173        $convert!(r);
1174        $convert!(e);
1175
1176        {
1177            let mut p = $ProductZipper::new(l.read_zipper(), [r.read_zipper(), e.read_zipper()]);
1178            p.descend_to("abcdefghijklmnopqrstuvwxyzbowfo");
1179            assert!(p.path_exists());
1180            assert_eq!(p.path(), b"abcdefghijklmnopqrstuvwxyzbowfo");
1181            assert!(p.descend_first_byte());
1182            assert_eq!(p.path(), b"abcdefghijklmnopqrstuvwxyzbowfoo");
1183        }
1184        {
1185            let mut p = $ProductZipper::new(l.read_zipper(), [r.read_zipper(), e.read_zipper()]);
1186            p.descend_to("abcdefghijklmnopqrstuvwxyzbowf");
1187            assert_eq!(p.path(), b"abcdefghijklmnopqrstuvwxyzbowf");
1188            assert!(p.is_val());
1189            p.descend_to("oo");
1190            assert!(p.path_exists());
1191            assert!(p.is_val());
1192        }
1193        {
1194            let mut p = $ProductZipper::new(l.read_zipper(), [r.read_zipper(), e.read_zipper()]);
1195            p.descend_to("abcdefghijklmnopqrstuvwxyzbowfo");
1196            assert_eq!(p.path(), b"abcdefghijklmnopqrstuvwxyzbowfo");
1197            assert!(p.ascend_byte());
1198            assert_eq!(p.path(), b"abcdefghijklmnopqrstuvwxyzbowf");
1199            assert!(p.ascend_byte());
1200            assert_eq!(p.path(), b"abcdefghijklmnopqrstuvwxyzbow");
1201            p.descend_to_byte(b'p');
1202            assert!(p.path_exists());
1203            assert_eq!(p.path(), b"abcdefghijklmnopqrstuvwxyzbowp");
1204            p.descend_to_byte(b'h');
1205            assert!(p.path_exists());
1206            assert_eq!(p.path(), b"abcdefghijklmnopqrstuvwxyzbowph");
1207            p.descend_to_byte(b'o');
1208            assert!(p.path_exists());
1209            assert_eq!(p.path(), b"abcdefghijklmnopqrstuvwxyzbowpho");
1210            assert!(p.is_val());
1211            assert!(p.ascend_until());
1212            assert_eq!(p.path(), b"abcdefghijklmnopqrstuvwxyzbow");
1213            assert!(p.ascend(3));
1214            assert_eq!(vec![b'A', b'a', b'b'], p.child_mask().iter().collect::<Vec<_>>());
1215            p.descend_to("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
1216            assert!(p.path_exists());
1217            assert_eq!(vec![b'f', b'p'], p.child_mask().iter().collect::<Vec<_>>())
1218        }
1219    }
1220
1221    #[test]
1222    fn product_zipper_test6() {
1223        let lpaths = ["abcdefghijklmnopqrstuvwxyz".as_bytes(), "arrow".as_bytes(), "x".as_bytes(), "arr".as_bytes()];
1224        let rpaths = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ".as_bytes(), "a".as_bytes(), "bow".as_bytes(), "bo".as_bytes()];
1225        let epaths = ["foo".as_bytes(), "pho".as_bytes(), "f".as_bytes()];
1226        let l = PathMap::from_iter(lpaths.iter().map(|x| (x, ())));
1227        let r = PathMap::from_iter(rpaths.iter().map(|x| (x, ())));
1228        let e = PathMap::from_iter(epaths.iter().map(|x| (x, ())));
1229        $convert!(l);
1230        $convert!(r);
1231        $convert!(e);
1232
1233        {
1234            let mut p = $ProductZipper::new(l.read_zipper(), [r.read_zipper(), e.read_zipper()]);
1235            p.descend_to("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
1236            assert!(!p.path_exists());
1237            // println!("p {}", std::str::from_utf8(p.path()).unwrap());
1238            assert!(!p.ascend(27));
1239        }
1240    }
1241
1242    /// Hits an additional bug where an intermediate value might be stepped over by one `descend_to`
1243    /// but used as a marker to move to the product zipper by the other `descend...` methods 
1244    #[test]
1245    fn product_zipper_test7() {
1246        let apaths = ["arr".as_bytes(), "arrow".as_bytes(), "arrowhead".as_bytes()];
1247        let bpaths = ["bo".as_bytes(), "bow".as_bytes(), "bowie".as_bytes()];
1248        let cpaths = ["cl".as_bytes(), "club".as_bytes(), "clubhouse".as_bytes()];
1249        let a = PathMap::from_iter(apaths.iter().map(|x| (x, ())));
1250        let b = PathMap::from_iter(bpaths.iter().map(|x| (x, ())));
1251        let c = PathMap::from_iter(cpaths.iter().map(|x| (x, ())));
1252        $convert!(a);
1253        $convert!(b);
1254        $convert!(c);
1255        let mut p1 = $ProductZipper::new(a.read_zipper(), [b.read_zipper(), c.read_zipper()]);
1256        let mut p2 = $ProductZipper::new(a.read_zipper(), [b.read_zipper(), c.read_zipper()]);
1257
1258        // Reference
1259        for _ in 0..23 {
1260            p1.descend_first_byte();
1261        }
1262        assert_eq!(p1.path_exists(), true);
1263        assert_eq!(p1.path(), b"arrowheadbowieclubhouse");
1264        assert!(p1.is_val());
1265
1266        // Validate that I can do the same thing with descend_to()
1267        p2.descend_to(b"arrowheadbowieclubhouse");
1268        assert_eq!(p2.path_exists(), true);
1269        assert_eq!(p2.path(), b"arrowheadbowieclubhouse");
1270        assert!(p2.is_val());
1271
1272        // Validate that I can back up, and re-descend
1273        {
1274            p2.ascend(20);
1275            assert_eq!(p2.path(), b"arr");
1276            assert_eq!(p2.path_exists(), true);
1277            assert!(p2.is_val());
1278
1279            p2.descend_to(b"owheadbowieclub");
1280            assert_eq!(p2.path(), b"arrowheadbowieclub");
1281            assert_eq!(p2.path_exists(), true);
1282            assert!(p2.is_val());
1283        }
1284
1285        //Now descend to a non-existent path off of the first factor, and re-ascend to
1286        // an existing path
1287        {
1288            p2.reset();
1289            // "arrowbow" should't exist because the path continues from "arrowhead"
1290            p2.descend_to(b"arrowbow");
1291            assert_eq!(p2.path(), b"arrowbow");
1292            assert_eq!(p2.path_exists(), false);
1293
1294            // "arrowbowclub" should't exist because we started in a trie that doesn't exist
1295            p2.descend_to(b"club");
1296            assert_eq!(p2.path(), b"arrowbowclub");
1297            assert_eq!(p2.path_exists(), false);
1298
1299            p2.ascend(9);
1300            assert_eq!(p2.path(), b"arr");
1301            assert_eq!(p2.path_exists(), true);
1302            assert!(p2.is_val());
1303
1304            p2.descend_to(b"owheadbowieclub");
1305            assert_eq!(p2.path(), b"arrowheadbowieclub");
1306            assert_eq!(p2.path_exists(), true);
1307            assert!(p2.is_val());
1308        }
1309
1310        //Now descend to a non-existent path off of the second factor, and re-ascend to
1311        // get back to an existing path
1312        {
1313            p2.reset();
1314            // "arrowheadbowclub" should't exist because the path continues from "bowie"
1315            p2.descend_to(b"arrowheadbowclub");
1316            assert_eq!(p2.path(), b"arrowheadbowclub");
1317            assert_eq!(p2.path_exists(), false);
1318
1319            p2.ascend(5);
1320            assert_eq!(p2.path(), b"arrowheadbo");
1321            assert_eq!(p2.path_exists(), true);
1322            assert!(p2.is_val());
1323
1324            p2.descend_to(b"wieclub");
1325            assert_eq!(p2.path(), b"arrowheadbowieclub");
1326            assert_eq!(p2.path_exists(), true);
1327            assert!(p2.is_val());
1328        }
1329    }
1330
1331    #[test]
1332    fn product_zipper_test8() {
1333        let lpaths = ["abcdefghijklmnopqrstuvwxyz".as_bytes(), "arr".as_bytes(), "arrow".as_bytes(), "x".as_bytes()];
1334        let rpaths = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ".as_bytes(), "a".as_bytes(), "bo".as_bytes(), "bow".as_bytes(), "bat".as_bytes(), "bit".as_bytes()];
1335        let epaths = ["foo".as_bytes(), "pho".as_bytes(), "f".as_bytes()];
1336        let l = PathMap::from_iter(lpaths.iter().map(|x| (x, ())));
1337        let r = PathMap::from_iter(rpaths.iter().map(|x| (x, ())));
1338        let e = PathMap::from_iter(epaths.iter().map(|x| (x, ())));
1339        $convert!(l);
1340        $convert!(r);
1341        $convert!(e);
1342
1343        let new_pz = || $ProductZipper::new(l.read_zipper(), [r.read_zipper(), e.read_zipper()]);
1344
1345        let mut moving_pz = new_pz();
1346        let cata_pz = new_pz();
1347        cata_pz.into_cata_side_effect(|_, _, _, path| {
1348            // println!("{}", String::from_utf8_lossy(path));
1349            let overlap = find_prefix_overlap(path, moving_pz.path());
1350            if overlap < moving_pz.path().len() {
1351                moving_pz.ascend(moving_pz.path().len() - overlap);
1352            }
1353            if moving_pz.path().len() < path.len() {
1354                moving_pz.descend_to(&path[moving_pz.path().len()..]);
1355                assert!(moving_pz.path_exists());
1356            }
1357            assert_eq!(moving_pz.path(), path);
1358
1359            let mut fresh_pz = new_pz();
1360            fresh_pz.descend_to(path);
1361
1362            assert_eq!(moving_pz.path(), fresh_pz.path());
1363            assert_eq!(moving_pz.path_exists(), fresh_pz.path_exists());
1364            assert_eq!(moving_pz.val(), fresh_pz.val());
1365            assert_eq!(moving_pz.child_count(), fresh_pz.child_count());
1366            assert_eq!(moving_pz.child_mask(), fresh_pz.child_mask());
1367        })
1368    }
1369
1370    /// Tests the ProductZipper's implementation of `to_next_k_path` or `to_next_sibling_byte`, stepping across factors
1371    #[test]
1372    fn product_zipper_test9() {
1373        let paths = [
1374            vec![3, 196, 50, 193, 52],
1375            vec![3, 196, 50, 194, 49, 54],
1376            vec![3, 196, 50, 194, 49, 55],
1377        ];
1378        let map: PathMap<()> = paths.iter().map(|path| (path, ())).collect();
1379        $convert!(map);
1380        let mut z = $ProductZipper::new(map.read_zipper(), [map.read_zipper(), map.read_zipper()]);
1381
1382        z.descend_to([3, 196, 50, 193, 52, 3, 196, 50, 194, 49, 54]);
1383        assert_eq!(z.path_exists(), true);
1384        assert_eq!(z.to_next_k_path(2), true);
1385        assert_eq!(z.path_exists(), true);
1386        assert_eq!(z.child_mask(), ByteMask::from_iter([3]));
1387    }
1388
1389    /// Reproduce a bug in ProductZipperG, where continuing to descend past a non-existent
1390    /// path somehow leads to re-entering the next factor
1391    #[test]
1392    fn product_zipper_testa() {
1393        let paths = [
1394            vec![3, 196, 101, 100, 103, 101, 193, 49, 194, 49, 56],
1395            vec![3, 196, 101, 100, 103, 101, 193, 49, 194, 50, 48],
1396        ];
1397        let map: PathMap<()> = paths.iter().map(|path| (path, ())).collect();
1398        $convert!(map);
1399        let mut z = $ProductZipper::new(map.read_zipper(), [map.read_zipper(), map.read_zipper()]);
1400
1401        assert_eq!(z.path_exists(), true);
1402        z.descend_to_byte(3);
1403        assert_eq!(z.path_exists(), true);
1404        z.descend_to_byte(196);
1405        assert_eq!(z.path_exists(), true);
1406        z.descend_to([101, 100, 103, 101]);
1407        assert_eq!(z.path_exists(), true);
1408        z.descend_to_byte(193);
1409        assert_eq!(z.path_exists(), true);
1410        assert_eq!(z.path(), [3, 196, 101, 100, 103, 101, 193]);
1411        z.descend_to_byte(194);
1412        assert_eq!(z.path(), [3, 196, 101, 100, 103, 101, 193, 194]);
1413        assert_eq!(z.path_exists(), false);
1414        z.descend_to_byte(3);
1415        assert_eq!(z.path(), [3, 196, 101, 100, 103, 101, 193, 194, 3]);
1416        assert_eq!(z.path_exists(), false);
1417    }
1418
1419    /// Test focussed heavily on `descend_to_byte`, with tests for stitching at dangling paths
1420    #[test]
1421    fn product_zipper_testb() {
1422        let paths = [
1423            vec![3, 196, 101, 49],
1424            vec![3, 196, 101, 50],
1425        ];
1426        let mut map = PathMap::<()>::new();
1427        paths.into_iter().for_each(|path| { map.create_path(path); });
1428        map.insert([3, 196], ());
1429        map.insert([3, 196, 101, 49], ());
1430        $convert!(map);
1431        let mut z = $ProductZipper::new(map.read_zipper(), [map.read_zipper(), map.read_zipper()]);
1432
1433        assert_eq!(z.path_exists(), true);
1434        assert_eq!(z.child_count(), 1);
1435        assert_eq!(z.child_mask(), ByteMask::from_iter([3u8]));
1436        assert_eq!(z.is_val(), false);
1437
1438        z.descend_to_byte(3);
1439        assert_eq!(z.path_exists(), true);
1440        assert_eq!(z.child_count(), 1);
1441        assert_eq!(z.child_mask(), ByteMask::from_iter([196u8]));
1442        assert_eq!(z.is_val(), false);
1443
1444        z.descend_to_byte(196);
1445        assert_eq!(z.path_exists(), true);
1446        assert_eq!(z.child_count(), 1);
1447        assert_eq!(z.child_mask(), ByteMask::from_iter([101u8]));
1448        assert_eq!(z.is_val(), true);
1449
1450        z.descend_to_byte(101);
1451        assert_eq!(z.path_exists(), true);
1452        assert_eq!(z.child_count(), 2);
1453        assert_eq!(z.child_mask(), ByteMask::from_iter([49u8, 50]));
1454        assert_eq!(z.is_val(), false);
1455
1456        z.descend_to_byte(50);
1457        assert_eq!(z.path_exists(), true);
1458        assert_eq!(z.child_count(), 1);
1459        assert_eq!(z.child_mask(), ByteMask::from_iter([3u8]));
1460        assert_eq!(z.is_val(), false);
1461
1462        z.descend_to_byte(3);
1463        assert_eq!(z.path_exists(), true);
1464        assert_eq!(z.child_count(), 1);
1465        assert_eq!(z.child_mask(), ByteMask::from_iter([196u8]));
1466        assert_eq!(z.is_val(), false);
1467
1468        z.descend_to_byte(196);
1469        assert_eq!(z.path_exists(), true);
1470        assert_eq!(z.is_val(), true);
1471        assert_eq!(z.child_count(), 1);
1472        assert_eq!(z.child_mask(), ByteMask::from_iter([101u8]));
1473
1474        z.descend_to_byte(101);
1475        assert_eq!(z.path_exists(), true);
1476        assert_eq!(z.child_count(), 2);
1477        assert_eq!(z.child_mask(), ByteMask::from_iter([49u8, 50]));
1478        assert_eq!(z.is_val(), false);
1479
1480        z.descend_to_byte(49);
1481        assert_eq!(z.path_exists(), true);
1482        assert_eq!(z.child_count(), 1);
1483        assert_eq!(z.child_mask(), ByteMask::from_iter([3u8]));
1484        assert_eq!(z.is_val(), true);
1485
1486        z.descend_to_byte(3);
1487        assert_eq!(z.path_exists(), true);
1488        assert_eq!(z.child_count(), 1);
1489        assert_eq!(z.child_mask(), ByteMask::from_iter([196u8]));
1490        assert_eq!(z.is_val(), false);
1491
1492        z.descend_to_byte(196);
1493        assert_eq!(z.path_exists(), true);
1494        assert_eq!(z.child_count(), 1);
1495        assert_eq!(z.child_mask(), ByteMask::from_iter([101u8]));
1496        assert_eq!(z.is_val(), true);
1497
1498        z.descend_to_byte(101);
1499        assert_eq!(z.path_exists(), true);
1500        assert_eq!(z.child_count(), 2);
1501        assert_eq!(z.child_mask(), ByteMask::from_iter([49u8, 50]));
1502        assert_eq!(z.is_val(), false);
1503
1504        z.descend_to_byte(50);
1505        assert_eq!(z.path_exists(), true);
1506        assert_eq!(z.child_count(), 0);
1507        assert_eq!(z.child_mask(), ByteMask::EMPTY);
1508        assert_eq!(z.is_val(), false);
1509
1510        z.descend_to_byte(3);
1511        assert_eq!(z.path_exists(), false);
1512        assert_eq!(z.child_count(), 0);
1513        assert_eq!(z.child_mask(), ByteMask::EMPTY);
1514        assert_eq!(z.is_val(), false);
1515    }
1516
1517    /// Hits some of the `descend_to_byte` stitch transitions, in the context where we'll have a ByteNode
1518    #[test]
1519    fn product_zipper_testc() {
1520        let pm: PathMap<()> = [
1521            (&[1, 192], ()),
1522            (&[4, 196], ()),
1523            (&[193, 102], ())
1524        ].into_iter().collect();
1525
1526        let mut pz = $ProductZipper::new(pm.read_zipper(), [pm.read_zipper()]);
1527
1528        pz.descend_to_byte(1);
1529        pz.descend_to_byte(192);
1530        assert_eq!(pz.child_count(), 3);
1531        assert_eq!(pz.child_mask(), ByteMask::from_iter([1u8, 4, 193]));
1532    }
1533
1534    /// This test assembles a map with a single dangling path, and stitches multiple of them
1535    /// together into a PZ, so the resulting virtual trie is just one long path with repetitions.
1536    ///
1537    /// We then validate that `ascend`, `ascend_until`, `ascend_until_branch`, etc. all do the right
1538    /// thing traversing across multiple factors, not stopping spuriously at the factor stitch points.
1539    ///
1540    /// Also we test `descend_until` in this case, because the correct behavior should be to
1541    /// seamlessly descend, flowing across multiple factor zippers in one call
1542    #[test]
1543    fn product_zipper_testd() {
1544        let snip = b"-=**=-";
1545        let repeats = 5;
1546        let mut map = PathMap::<()>::new();
1547        map.create_path(snip);
1548
1549        let factors: Vec<_> = (0..repeats-1).into_iter().map(|_| map.read_zipper()).collect();
1550        let mut pz = $ProductZipper::new(map.read_zipper(), factors);
1551
1552        let mut full_path = snip.to_vec();
1553        for _ in 0..repeats-1 {
1554            full_path.extend(snip);
1555        }
1556
1557        // descend_to is already well tested, but we're using it to set up the conditions for the ascend tests
1558        pz.descend_to(&full_path);
1559        assert_eq!(pz.path(), full_path);
1560        assert_eq!(pz.path_exists(), true);
1561        assert_eq!(pz.child_count(), 0);
1562        assert_eq!(pz.is_val(), false);
1563
1564        // test ascend
1565        assert_eq!(pz.ascend(snip.len() * (repeats-1)), true);
1566        assert_eq!(pz.path(), snip);
1567        assert_eq!(pz.path_exists(), true);
1568        assert_eq!(pz.child_count(), 1);
1569        assert_eq!(pz.is_val(), false);
1570
1571        // test ascend_until
1572        pz.reset();
1573        pz.descend_to(&full_path);
1574        assert_eq!(pz.ascend_until(), true);
1575        assert_eq!(pz.path(), []);
1576        assert_eq!(pz.path_exists(), true);
1577        assert_eq!(pz.child_count(), 1);
1578        assert_eq!(pz.is_val(), false);
1579
1580        // test ascend_until_branch
1581        pz.descend_to(&full_path);
1582        assert_eq!(pz.ascend_until_branch(), true);
1583        assert_eq!(pz.path(), []);
1584        assert_eq!(pz.path_exists(), true);
1585        assert_eq!(pz.child_count(), 1);
1586        assert_eq!(pz.is_val(), false);
1587
1588        // test descend_until
1589        assert_eq!(pz.descend_until(), true);
1590        assert_eq!(pz.path(), full_path);
1591        assert_eq!(pz.path_exists(), true);
1592        assert_eq!(pz.child_count(), 0);
1593        assert_eq!(pz.is_val(), false);
1594    }
1595
1596    #[test]
1597    fn product_zipper_inspection_test() {
1598        let lpaths = ["abcdefghijklmnopqrstuvwxyz".as_bytes(), "arr".as_bytes(), "arrow".as_bytes(), "x".as_bytes()];
1599        let rpaths = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ".as_bytes(), "a".as_bytes(), "bo".as_bytes(), "bow".as_bytes(), "bat".as_bytes(), "bit".as_bytes()];
1600        let epaths = ["foo".as_bytes(), "pho".as_bytes(), "f".as_bytes()];
1601        let l = PathMap::from_iter(lpaths.iter().map(|x| (x, ())));
1602        let r = PathMap::from_iter(rpaths.iter().map(|x| (x, ())));
1603        let e = PathMap::from_iter(epaths.iter().map(|x| (x, ())));
1604        $convert!(l);
1605        $convert!(r);
1606        $convert!(e);
1607        let mut pz = $ProductZipper::new(l.read_zipper_at_borrowed_path(b"abcdefghijklm"), [r.read_zipper(), e.read_zipper()]);
1608
1609        assert_eq!(pz.factor_count(), 3);
1610        assert_eq!(pz.focus_factor(), 0);
1611        assert_eq!(pz.path_indices().len(), 0);
1612        assert_eq!(pz.path(), b"");
1613        assert_eq!(pz.origin_path(), b"abcdefghijklm");
1614
1615        pz.descend_to(b"nopqrstuvwxyz");
1616        assert!(pz.path_exists());
1617
1618        assert_eq!(pz.focus_factor(), 0);
1619        assert_eq!(pz.path(), b"nopqrstuvwxyz");
1620        assert_eq!(pz.origin_path(), b"abcdefghijklmnopqrstuvwxyz");
1621
1622        pz.descend_to(b"AB");
1623        assert!(pz.path_exists());
1624
1625        assert_eq!(pz.focus_factor(), 1);
1626        assert_eq!(pz.path_indices()[0], 13);
1627        assert_eq!(pz.path().len(), 15);
1628        assert_eq!(pz.path(), b"nopqrstuvwxyzAB");
1629        assert_eq!(pz.origin_path(), b"abcdefghijklmnopqrstuvwxyzAB");
1630
1631        pz.reset();
1632        assert_eq!(pz.child_mask(), ByteMask::from_iter([b'n']));
1633        pz.descend_to(b"nopqrstuvwxyzbowph");
1634        assert!(pz.path_exists());
1635        assert_eq!(pz.focus_factor(), 2);
1636        assert_eq!(pz.path_indices()[0], 13);
1637        assert_eq!(pz.path_indices()[1], 16);
1638        assert_eq!(pz.path(), b"nopqrstuvwxyzbowph");
1639    }
1640            }
1641            // --- END OF MACRO GENERATED MOD ---
1642        };
1643    }
1644
1645    macro_rules! noop { ($x:ident) => {}; (*$x:ident) => {}; }
1646    impl_product_zipper_tests!(pz_concrete, ProductZipper, noop);
1647    impl_product_zipper_tests!(pz_generic, ProductZipperG, noop);
1648
1649    #[cfg(feature="arena_compact")]
1650    macro_rules! to_act {
1651        (*$x:ident) => {
1652            to_act!($x, |x| *x);
1653        };
1654        ($x:ident) => {
1655            to_act!($x, |_x| 0);
1656        };
1657        ($x:ident, $m:expr) => {
1658            let $x = crate::arena_compact::ArenaCompactTree::from_zipper($x.read_zipper(), $m);
1659        };
1660    }
1661
1662    #[cfg(feature="arena_compact")]
1663    impl_product_zipper_tests!(pz_generic_act, ProductZipperG, to_act, read_zipper_u64);
1664
1665    crate::zipper::zipper_moving_tests::zipper_moving_tests!(product_zipper,
1666        |keys: &[&[u8]]| {
1667            let mut btm = PathMap::new();
1668            keys.iter().for_each(|k| { btm.set_val_at(k, ()); });
1669            btm
1670        },
1671        |btm: &mut PathMap<()>, path: &[u8]| -> _ {
1672            ProductZipper::new::<_, TrieRef<()>, _>(btm.read_zipper_at_path(path), [])
1673    });
1674
1675    crate::zipper::zipper_iteration_tests::zipper_iteration_tests!(product_zipper,
1676        |keys: &[&[u8]]| {
1677            let mut btm = PathMap::new();
1678            keys.iter().for_each(|k| { btm.set_val_at(k, ()); });
1679            btm
1680        },
1681        |btm: &mut PathMap<()>, path: &[u8]| -> _ {
1682            ProductZipper::new::<_, TrieRef<()>, _>(btm.read_zipper_at_path(path), [])
1683    });
1684
1685    crate::zipper::zipper_moving_tests::zipper_moving_tests!(product_zipper_generic,
1686        |keys: &[&[u8]]| {
1687            let mut btm = PathMap::new();
1688            keys.iter().for_each(|k| { btm.set_val_at(k, ()); });
1689            btm
1690        },
1691        |btm: &mut PathMap<()>, path: &[u8]| -> _ {
1692            ProductZipperG::new::<[ReadZipperUntracked<()>; 0]>(btm.read_zipper_at_path(path), [])
1693    });
1694
1695    crate::zipper::zipper_iteration_tests::zipper_iteration_tests!(product_zipper_generic,
1696        |keys: &[&[u8]]| {
1697            let mut btm = PathMap::new();
1698            keys.iter().for_each(|k| { btm.set_val_at(k, ()); });
1699            btm
1700        },
1701        |btm: &mut PathMap<()>, path: &[u8]| -> _ {
1702            ProductZipperG::new::<[ReadZipperUntracked<()>; 0]>(btm.read_zipper_at_path(path), [])
1703    });
1704}
1705
1706//POSSIBLE FUTURE DIRECTION:
1707// A ProductZipper appears to create a new space for the purposes of zipper movement, but
1708// the space is an ephemeral projection.  Unlike other space operations, if the user tried
1709// to graft this space or materialize it into a map, they would get something that would
1710// not match their expectations.
1711//
1712// This is the reason the ProductZipper doesn't implement the `ZipperSubtries` trait, and
1713// why it cannot supply a source for `graft`, `make_map`, or any other algebraic ops.
1714//
1715// A more holistic way of performing this kind of transformation is likely desirable, but
1716// that has a number of unexplored complications such as the impact to exclusivity (is this
1717// de-facto aliasing?) and how the linkages could be parameterized after-the-fact, or
1718// re-parameterized en masse (without visiting each node in the sub-space), or when the
1719// parameters would be allowed to change vs. when they must remain constant.
1720//