Skip to main content

pathmap_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput, Data, Fields};
4use syn::{Attribute, Ident};
5use std::collections::BTreeSet;
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
8enum PolyZipperTrait {
9    Zipper,
10    ZipperValues,
11    ZipperReadOnlyValues,
12    ZipperReadOnlyConditionalValues,
13    ZipperReadOnlyConditionalIteration,
14    ZipperReadOnlyIteration,
15    ZipperMoving,
16    ZipperIteration,
17    ZipperConcrete,
18    ZipperAbsolutePath,
19    ZipperPathBuffer,
20    ZipperSubtries,
21    ZipperInfallibleSubtries,
22}
23
24impl PolyZipperTrait {
25    fn from_ident(ident: &Ident) -> Option<Self> {
26        match ident.to_string().as_str() {
27            "Zipper" => Some(Self::Zipper),
28            "ZipperValues" => Some(Self::ZipperValues),
29            "ZipperReadOnlyValues" => Some(Self::ZipperReadOnlyValues),
30            "ZipperReadOnlyConditionalValues" => Some(Self::ZipperReadOnlyConditionalValues),
31            "ZipperReadOnlyConditionalIteration" => Some(Self::ZipperReadOnlyConditionalIteration),
32            "ZipperReadOnlyIteration" => Some(Self::ZipperReadOnlyIteration),
33            "ZipperMoving" => Some(Self::ZipperMoving),
34            "ZipperIteration" => Some(Self::ZipperIteration),
35            "ZipperConcrete" => Some(Self::ZipperConcrete),
36            "ZipperAbsolutePath" => Some(Self::ZipperAbsolutePath),
37            "ZipperPathBuffer" => Some(Self::ZipperPathBuffer),
38            "ZipperSubtries" => Some(Self::ZipperSubtries),
39            "ZipperInfallibleSubtries" => Some(Self::ZipperInfallibleSubtries),
40            _ => None,
41        }
42    }
43}
44
45fn all_poly_zipper_traits() -> BTreeSet<PolyZipperTrait> {
46    use PolyZipperTrait::*;
47    BTreeSet::from([
48        Zipper,
49        ZipperValues,
50        ZipperReadOnlyValues,
51        ZipperReadOnlyConditionalValues,
52        ZipperReadOnlyConditionalIteration,
53        ZipperReadOnlyIteration,
54        ZipperMoving,
55        ZipperIteration,
56        ZipperConcrete,
57        ZipperAbsolutePath,
58        ZipperPathBuffer,
59        ZipperSubtries,
60        ZipperInfallibleSubtries,
61    ])
62}
63
64fn add_trait_dependencies(traits: &mut BTreeSet<PolyZipperTrait>) {
65    use PolyZipperTrait::*;
66    let mut changed = true;
67    while changed {
68        changed = false;
69        if traits.contains(&ZipperReadOnlyIteration) {
70            if traits.insert(ZipperReadOnlyValues) {
71                changed = true;
72            }
73            if traits.insert(ZipperIteration) {
74                changed = true;
75            }
76        }
77        if traits.contains(&ZipperReadOnlyConditionalIteration) {
78            if traits.insert(ZipperReadOnlyConditionalValues) {
79                changed = true;
80            }
81            if traits.insert(ZipperIteration) {
82                changed = true;
83            }
84        }
85        if traits.contains(&ZipperReadOnlyValues) {
86            if traits.insert(ZipperValues) {
87                changed = true;
88            }
89        }
90        if traits.contains(&ZipperReadOnlyConditionalValues) {
91            if traits.insert(ZipperValues) {
92                changed = true;
93            }
94        }
95        if traits.contains(&ZipperIteration) {
96            if traits.insert(ZipperMoving) {
97                changed = true;
98            }
99        }
100        if traits.contains(&ZipperAbsolutePath) {
101            if traits.insert(ZipperMoving) {
102                changed = true;
103            }
104        }
105        if traits.contains(&ZipperPathBuffer) {
106            if traits.insert(ZipperMoving) {
107                changed = true;
108            }
109        }
110        if traits.contains(&ZipperMoving) {
111            if traits.insert(Zipper) {
112                changed = true;
113            }
114        }
115        if traits.contains(&ZipperSubtries) {
116            if traits.insert(ZipperValues) {
117                changed = true;
118            }
119        }
120        if traits.contains(&ZipperInfallibleSubtries) {
121            if traits.insert(ZipperValues) {
122                changed = true;
123            }
124        }
125    }
126}
127
128fn parse_explicit_traits(attrs: &[Attribute]) -> Result<Option<BTreeSet<PolyZipperTrait>>, syn::Error> {
129    let mut explicit: Option<BTreeSet<PolyZipperTrait>> = None;
130    for attr in attrs {
131        if !attr.path().is_ident("poly_zipper_explicit") {
132            continue;
133        }
134        if explicit.is_some() {
135            return Err(syn::Error::new_spanned(attr, "duplicate `poly_zipper_explicit` attribute"));
136        }
137        let mut trait_set = BTreeSet::new();
138        let mut saw_traits = false;
139        attr.parse_nested_meta(|meta| {
140            if meta.path.is_ident("traits") {
141                saw_traits = true;
142                meta.parse_nested_meta(|meta| {
143                    let ident = meta.path.get_ident().ok_or_else(|| {
144                        meta.error("expected trait name identifier")
145                    })?;
146                    let trait_kind = PolyZipperTrait::from_ident(ident).ok_or_else(|| {
147                        meta.error("unknown trait name in poly_zipper_explicit traits list")
148                    })?;
149                    trait_set.insert(trait_kind);
150                    Ok(())
151                })
152            } else {
153                Err(meta.error("expected `traits(...)`"))
154            }
155        })?;
156        if !saw_traits {
157            return Err(syn::Error::new_spanned(attr, "expected `traits(...)`"));
158        }
159        if trait_set.is_empty() {
160            return Err(syn::Error::new_spanned(attr, "traits list must not be empty"));
161        }
162        explicit = Some(trait_set);
163    }
164    Ok(explicit)
165}
166
167// See the docs for `PolyZipper` in `pathmap::zipper::PolyZipper`
168#[proc_macro_derive(PolyZipper)]
169pub fn derive_poly_zipper(input: TokenStream) -> TokenStream {
170    let input = parse_macro_input!(input as DeriveInput);
171    derive_poly_zipper_with_traits(input, all_poly_zipper_traits(), true)
172}
173
174// See the docs for `PolyZipperExplicit` in `pathmap::zipper::PolyZipperExplicit`
175#[proc_macro_derive(PolyZipperExplicit, attributes(poly_zipper_explicit))]
176pub fn derive_poly_zipper_explicit(input: TokenStream) -> TokenStream {
177    let input = parse_macro_input!(input as DeriveInput);
178    let explicit_traits = match parse_explicit_traits(&input.attrs) {
179        Ok(value) => value,
180        Err(err) => return TokenStream::from(err.to_compile_error()),
181    };
182    let mut traits = explicit_traits.unwrap_or_else(all_poly_zipper_traits);
183    add_trait_dependencies(&mut traits);
184    derive_poly_zipper_with_traits(input, traits, false)
185}
186
187fn derive_poly_zipper_with_traits(
188    input: DeriveInput,
189    traits: BTreeSet<PolyZipperTrait>,
190    include_where_clause: bool,
191) -> TokenStream {
192
193    let enum_name = &input.ident;
194    let generics = &input.generics;
195    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
196
197    // Extract enum variants
198    let variants = match &input.data {
199        Data::Enum(data_enum) => &data_enum.variants,
200        _ => panic!("PolyZipper can only be derived for enums"),
201    };
202
203    // Generate From and TryFrom impls for each variant
204    let from_impls = variants.iter().map(|variant| {
205        let variant_name = &variant.ident;
206
207        // Get the inner type (assuming single unnamed field)
208        let inner_type = match &variant.fields {
209            Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
210                &fields.unnamed[0].ty
211            }
212            _ => panic!("Each variant must have exactly one unnamed field"),
213        };
214
215        quote! {
216            impl #impl_generics From<#inner_type> for #enum_name #ty_generics #where_clause {
217                fn from(value: #inner_type) -> Self {
218                    #enum_name::#variant_name(value)
219                }
220            }
221
222            impl #impl_generics core::convert::TryFrom<#enum_name #ty_generics> for #inner_type #where_clause {
223                type Error = ();
224
225                fn try_from(value: #enum_name #ty_generics) -> Result<Self, Self::Error> {
226                    match value {
227                        #enum_name::#variant_name(inner) => Ok(inner),
228                        _ => Err(()),
229                    }
230                }
231            }
232        }
233    });
234
235    let variant_arms: Vec<_> = variants.iter().map(|variant| {
236        let variant_name = &variant.ident;
237        quote! { Self::#variant_name(inner) }
238    }).collect();
239
240    let inner_types: Vec<_> = variants.iter().map(|variant| {
241        match &variant.fields {
242            Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
243                &fields.unnamed[0].ty
244            }
245            _ => panic!("Each variant must have exactly one unnamed field"),
246        }
247    }).collect();
248
249    // Generate Zipper trait implementation
250    let zipper_impl = if traits.contains(&PolyZipperTrait::Zipper) {
251        let variant_arms = &variant_arms;
252        let zipper_where = if include_where_clause {
253            quote! {
254                where
255                    #(#inner_types: pathmap::zipper::Zipper,)*
256                    #where_clause
257            }
258        } else {
259            quote! {}
260        };
261        Some(quote! {
262            impl #impl_generics pathmap::zipper::Zipper for #enum_name #ty_generics
263            #zipper_where
264            {
265                fn path_exists(&self) -> bool {
266                    match self {
267                        #(#variant_arms => inner.path_exists(),)*
268                    }
269                }
270
271                fn is_val(&self) -> bool {
272                    match self {
273                        #(#variant_arms => inner.is_val(),)*
274                    }
275                }
276
277                fn child_count(&self) -> usize {
278                    match self {
279                        #(#variant_arms => inner.child_count(),)*
280                    }
281                }
282
283                fn child_mask(&self) -> pathmap::utils::ByteMask {
284                    match self {
285                        #(#variant_arms => inner.child_mask(),)*
286                    }
287                }
288            }
289        })
290    } else {
291        None
292    };
293
294    // Generate ZipperValues trait implementation
295    let zipper_values_impl = if traits.contains(&PolyZipperTrait::ZipperValues) {
296        let variant_arms = &variant_arms;
297        let zipper_values_where = if include_where_clause {
298            quote! {
299                where
300                    #(#inner_types: pathmap::zipper::ZipperValues<V>,)*
301                    #where_clause
302            }
303        } else {
304            quote! {}
305        };
306        Some(quote! {
307            impl #impl_generics pathmap::zipper::ZipperValues<V> for #enum_name #ty_generics
308            #zipper_values_where
309            {
310                fn val(&self) -> Option<&V> {
311                    match self {
312                        #(#variant_arms => inner.val(),)*
313                    }
314                }
315
316                fn val_at<K: AsRef<[u8]>>(&self, path: K) -> Option<&V> {
317                    match self {
318                        #(#variant_arms => inner.val_at(path),)*
319                    }
320                }
321            }
322        })
323    } else {
324        None
325    };
326
327    // Generate ZipperReadOnlyValues trait implementation
328    let zipper_read_only_values_impl = if traits.contains(&PolyZipperTrait::ZipperReadOnlyValues) {
329        let variant_arms = &variant_arms;
330        let zipper_read_only_values_where = if include_where_clause {
331            quote! {
332                where
333                    #(#inner_types: pathmap::zipper::ZipperReadOnlyValues<'trie, V>,)*
334                    #where_clause
335            }
336        } else {
337            quote! {}
338        };
339        Some(quote! {
340            impl #impl_generics pathmap::zipper::ZipperReadOnlyValues<'trie, V> for #enum_name #ty_generics
341            #zipper_read_only_values_where
342            {
343                fn get_val(&self) -> Option<&'trie V> {
344                    match self {
345                        #(#variant_arms => inner.get_val(),)*
346                    }
347                }
348
349                fn get_val_at<K: AsRef<[u8]>>(&self, path: K) -> Option<&'trie V> {
350                    match self {
351                        #(#variant_arms => inner.get_val_at(path),)*
352                    }
353                }
354            }
355        })
356    } else {
357        None
358    };
359
360    // Generate witness enum name and variant names for conditional traits
361    let witness_enum_name = syn::Ident::new(&format!("{}Witness", enum_name), enum_name.span());
362    let variant_names: Vec<_> = variants.iter().map(|variant| &variant.ident).collect();
363
364    // Generate ZipperReadOnlyConditionalValues trait implementation with witness enum
365    let zipper_read_only_conditional_values_impl = if traits.contains(&PolyZipperTrait::ZipperReadOnlyConditionalValues) {
366        let zipper_read_only_conditional_values_where = if include_where_clause {
367            quote! {
368                where
369                    #(#inner_types: pathmap::zipper::ZipperReadOnlyConditionalValues<'trie, V>,)*
370                    #where_clause
371            }
372        } else {
373            quote! {}
374        };
375        Some(quote! {
376            //GOAT TODO: I think we could get into trouble if the witness types have fewer generics than
377            // the outer PolyZipper enum.  So we probably should add a phantom case too.
378            pub enum #witness_enum_name #impl_generics
379            #zipper_read_only_conditional_values_where
380            {
381                #(#variant_names(<#inner_types as pathmap::zipper::ZipperReadOnlyConditionalValues<'trie, V>>::WitnessT),)*
382            }
383
384            impl #impl_generics pathmap::zipper::ZipperReadOnlyConditionalValues<'trie, V> for #enum_name #ty_generics
385            #zipper_read_only_conditional_values_where
386            {
387                type WitnessT = #witness_enum_name #ty_generics;
388
389                fn witness<'w>(&self) -> Self::WitnessT {
390                    match self {
391                        #(Self::#variant_names(inner) => #witness_enum_name::#variant_names(inner.witness()),)*
392                    }
393                }
394
395                fn get_val_with_witness<'w>(&self, witness: &'w Self::WitnessT) -> Option<&'w V> where 'trie: 'w {
396                    match (self, witness) {
397                        #((Self::#variant_names(inner), #witness_enum_name::#variant_names(w)) => inner.get_val_with_witness(w),)*
398                        _ => {
399                            debug_assert!(false, "Witness variant must match zipper + variant");
400                            None
401                        },
402                    }
403                }
404            }
405        })
406    } else {
407        None
408    };
409
410    //GOAT, this is probably dead code given the decision (described in the PolyZipper docs)
411    // not to support a `ZipperForking` impl
412    //
413    //I can't seem to figure out how to align the `'a` and the `'read_z` lifetimes without changing the trait definition,
414    // and ideally we'd want to return a new enum-based zipper.  The elegant way to do that would be to actually invoke
415    // the PolyZipper macro recursively to get maximum support on the new zipper, but there are a bunch of obnoxious details
416    // to make that work. - like what to do about the recursion so we don't have infinite recursion in the macro, and how
417    // to map the lifetimes required by the trait onto the lifetimes of the new zippers.
418    //
419    // // Generate ZipperForking trait implementation
420    // let zipper_forking_impl = {
421    //     let variant_arms = &variant_arms;
422    //     let first_inner_type = &inner_types[0];
423    //     let other_inner_types = &inner_types[1..];
424
425    //     // Create modified generics with additional lifetime
426    //     let mut forking_generics = generics.clone();
427    //     forking_generics.params.insert(0, syn::parse_quote!('read_z));
428    //     let (forking_impl_generics, _, _) = forking_generics.split_for_impl();
429
430    //     quote! {
431    //         impl #forking_impl_generics pathmap::zipper::ZipperForking<V> for #enum_name #ty_generics
432    //         where
433    //             #(#inner_types: pathmap::zipper::ZipperForking<V>,)*
434    //             #(#other_inner_types: pathmap::zipper::ZipperForking<V, ReadZipperT<'read_z> = <#first_inner_type as pathmap::zipper::ZipperForking<V>>::ReadZipperT<'read_z>>,)*
435    //             Self: 'read_z,
436    //             #where_clause
437    //         {
438    //             type ReadZipperT<'a> = <#first_inner_type as pathmap::zipper::ZipperForking<V>>::ReadZipperT<'a> where Self: 'a;
439
440    //             fn fork_read_zipper<'a>(&'a self) -> Self::ReadZipperT<'a> {
441    //                 match self {
442    //                     #(#variant_arms => inner.fork_read_zipper(),)*
443    //                 }
444    //             }
445    //         }
446    //     }
447    // };
448
449    // Generate ZipperMoving trait implementation
450    let zipper_moving_impl = if traits.contains(&PolyZipperTrait::ZipperMoving) {
451        let variant_arms = &variant_arms;
452        let zipper_moving_where = if include_where_clause {
453            quote! {
454                where
455                    #(#inner_types: pathmap::zipper::ZipperMoving,)*
456                    #where_clause
457            }
458        } else {
459            quote! {}
460        };
461        Some(quote! {
462            impl #impl_generics pathmap::zipper::ZipperMoving for #enum_name #ty_generics
463            #zipper_moving_where
464            {
465                fn path(&self) -> &[u8] {
466                    match self {
467                        #(#variant_arms => inner.path(),)*
468                    }
469                }
470
471                fn val_count(&self) -> usize {
472                    match self {
473                        #(#variant_arms => inner.val_count(),)*
474                    }
475                }
476
477                fn descend_to<K: AsRef<[u8]>>(&mut self, k: K) {
478                    match self {
479                        #(#variant_arms => inner.descend_to(k),)*
480                    }
481                }
482
483                fn descend_to_check<K: AsRef<[u8]>>(&mut self, k: K) -> bool {
484                    match self {
485                        #(#variant_arms => inner.descend_to_check(k),)*
486                    }
487                }
488
489                #[inline]
490                fn descend_to_byte(&mut self, k: u8) {
491                    match self {
492                        #(#variant_arms => inner.descend_to_byte(k),)*
493                    }
494                }
495
496                #[inline]
497                fn descend_to_existing_byte(&mut self, k: u8) -> bool {
498                    match self {
499                        #(#variant_arms => inner.descend_to_existing_byte(k),)*
500                    }
501                }
502
503                fn ascend(&mut self, steps: usize) -> bool {
504                    match self {
505                        #(#variant_arms => inner.ascend(steps),)*
506                    }
507                }
508
509                fn ascend_until(&mut self) -> bool {
510                    match self {
511                        #(#variant_arms => inner.ascend_until(),)*
512                    }
513                }
514
515                fn ascend_until_branch(&mut self) -> bool {
516                    match self {
517                        #(#variant_arms => inner.ascend_until_branch(),)*
518                    }
519                }
520            }
521        })
522    } else {
523        None
524    };
525
526    // Generate ZipperConcrete trait implementation
527    let zipper_concrete_impl = if traits.contains(&PolyZipperTrait::ZipperConcrete) {
528        let variant_arms = &variant_arms;
529        let zipper_concrete_where = if include_where_clause {
530            quote! {
531                where
532                    #(#inner_types: pathmap::zipper::ZipperConcrete,)*
533                    #where_clause
534            }
535        } else {
536            quote! {}
537        };
538        Some(quote! {
539            impl #impl_generics pathmap::zipper::ZipperConcrete for #enum_name #ty_generics
540            #zipper_concrete_where
541            {
542                fn shared_node_id(&self) -> Option<u64> {
543                    match self {
544                        #(#variant_arms => inner.shared_node_id(),)*
545                    }
546                }
547                fn is_shared(&self) -> bool {
548                    match self {
549                        #(#variant_arms => inner.is_shared(),)*
550                    }
551                }
552            }
553        })
554    } else {
555        None
556    };
557
558    // Generate ZipperAbsolutePath trait implementation
559    let zipper_absolute_path_impl = if traits.contains(&PolyZipperTrait::ZipperAbsolutePath) {
560        let variant_arms = &variant_arms;
561        let zipper_absolute_path_where = if include_where_clause {
562            quote! {
563                where
564                    #(#inner_types: pathmap::zipper::ZipperAbsolutePath,)*
565                    #where_clause
566            }
567        } else {
568            quote! {}
569        };
570        Some(quote! {
571            impl #impl_generics pathmap::zipper::ZipperAbsolutePath for #enum_name #ty_generics
572            #zipper_absolute_path_where
573            {
574                fn origin_path(&self) -> &[u8] {
575                    match self {
576                        #(#variant_arms => inner.origin_path(),)*
577                    }
578                }
579
580                fn root_prefix_path(&self) -> &[u8] {
581                    match self {
582                        #(#variant_arms => inner.root_prefix_path(),)*
583                    }
584                }
585            }
586        })
587    } else {
588        None
589    };
590
591    // Generate ZipperPathBuffer trait implementation
592    let zipper_path_buffer_impl = if traits.contains(&PolyZipperTrait::ZipperPathBuffer) {
593        let variant_arms = &variant_arms;
594        let zipper_path_buffer_where = if include_where_clause {
595            quote! {
596                where
597                    #(#inner_types: pathmap::zipper::ZipperPathBuffer,)*
598                    #where_clause
599            }
600        } else {
601            quote! {}
602        };
603        Some(quote! {
604            impl #impl_generics pathmap::zipper::ZipperPathBuffer for #enum_name #ty_generics
605            #zipper_path_buffer_where
606            {
607                unsafe fn origin_path_assert_len(&self, len: usize) -> &[u8] {
608                    match self {
609                        #(#variant_arms => unsafe { inner.origin_path_assert_len(len) },)*
610                    }
611                }
612
613                fn prepare_buffers(&mut self) {
614                    match self {
615                        #(#variant_arms => inner.prepare_buffers(),)*
616                    }
617                }
618
619                fn reserve_buffers(&mut self, path_len: usize, stack_depth: usize) {
620                    match self {
621                        #(#variant_arms => inner.reserve_buffers(path_len, stack_depth),)*
622                    }
623                }
624            }
625        })
626    } else {
627        None
628    };
629
630    // Generate ZipperIteration trait implementation
631    let zipper_iteration_impl = if traits.contains(&PolyZipperTrait::ZipperIteration) {
632        let variant_arms = &variant_arms;
633        let zipper_iteration_where = if include_where_clause {
634            quote! {
635                where
636                    #(#inner_types: pathmap::zipper::ZipperIteration,)*
637                    #where_clause
638            }
639        } else {
640            quote! {}
641        };
642        Some(quote! {
643            impl #impl_generics pathmap::zipper::ZipperIteration for #enum_name #ty_generics
644            #zipper_iteration_where
645            {
646                fn to_next_val(&mut self) -> bool {
647                    match self {
648                        #(#variant_arms => inner.to_next_val(),)*
649                    }
650                }
651
652                fn descend_last_path(&mut self) -> bool {
653                    match self {
654                        #(#variant_arms => inner.descend_last_path(),)*
655                    }
656                }
657
658                fn descend_first_k_path(&mut self, k: usize) -> bool {
659                    match self {
660                        #(#variant_arms => inner.descend_first_k_path(k),)*
661                    }
662                }
663
664                fn to_next_k_path(&mut self, k: usize) -> bool {
665                    match self {
666                        #(#variant_arms => inner.to_next_k_path(k),)*
667                    }
668                }
669            }
670        })
671    } else {
672        None
673    };
674
675    // Generate ZipperReadOnlyIteration trait implementation
676    let zipper_read_only_iteration_impl = if traits.contains(&PolyZipperTrait::ZipperReadOnlyIteration) {
677        let variant_arms = &variant_arms;
678        let zipper_read_only_iteration_where = if include_where_clause {
679            quote! {
680                where
681                    #(#inner_types: pathmap::zipper::ZipperReadOnlyIteration<'trie, V>,)*
682                    #where_clause
683            }
684        } else {
685            quote! {}
686        };
687        Some(quote! {
688            impl #impl_generics pathmap::zipper::ZipperReadOnlyIteration<'trie, V> for #enum_name #ty_generics
689            #zipper_read_only_iteration_where
690            {
691                fn to_next_get_val(&mut self) -> Option<&'trie V> {
692                    match self {
693                        #(#variant_arms => inner.to_next_get_val(),)*
694                    }
695                }
696            }
697        })
698    } else {
699        None
700    };
701
702    // Generate ZipperReadOnlyConditionalIteration trait implementation
703    let zipper_read_only_conditional_iteration_impl = if traits.contains(&PolyZipperTrait::ZipperReadOnlyConditionalIteration) {
704        let zipper_read_only_conditional_iteration_where = if include_where_clause {
705            quote! {
706                where
707                    #(#inner_types: pathmap::zipper::ZipperReadOnlyConditionalIteration<'trie, V>,)*
708                    #where_clause
709            }
710        } else {
711            quote! {}
712        };
713        Some(quote! {
714            impl #impl_generics pathmap::zipper::ZipperReadOnlyConditionalIteration<'trie, V> for #enum_name #ty_generics
715            #zipper_read_only_conditional_iteration_where
716            {
717                fn to_next_get_val_with_witness<'w>(&mut self, witness: &'w Self::WitnessT) -> Option<&'w V> where 'trie: 'w {
718                    match (self, witness) {
719                        #((Self::#variant_names(inner), #witness_enum_name::#variant_names(w)) => inner.to_next_get_val_with_witness(w),)*
720                        _ => {
721                            debug_assert!(false, "Witness variant must match zipper variant");
722                            None
723                        },
724                    }
725                }
726            }
727        })
728    } else {
729        None
730    };
731
732    // Generate ZipperSubtries trait implementation
733    //GOAT, TODO: We ought to use the generic allocator A, if the enum has one, but use the GlobalAlloc if not,
734    // this requires parsing the impl_generics to see if there is an `A: Allocator` that is defined
735    let zipper_subtries_impl = if traits.contains(&PolyZipperTrait::ZipperSubtries) {
736        let zipper_subtries_where = if include_where_clause {
737            quote! {
738                where
739                    #(#inner_types: pathmap::zipper::ZipperSubtries<V>,)*
740                    #where_clause
741            }
742        } else {
743            quote! {}
744        };
745        Some(quote! {
746            impl #impl_generics pathmap::zipper::ZipperSubtries<V> for #enum_name #ty_generics
747            #zipper_subtries_where
748            {
749                fn native_subtries(&self) -> bool {
750                    match self {
751                        #(#variant_arms => inner.native_subtries(),)*
752                    }
753                }
754                fn try_make_map(&self) -> Option<pathmap::PathMap<V>> {
755                    match self {
756                        #(#variant_arms => inner.try_make_map(),)*
757                    }
758                }
759                fn trie_ref(&self) -> Option<pathmap::zipper::TrieRef<'_, V>> {
760                    match self {
761                        #(#variant_arms => inner.trie_ref(),)*
762                    }
763                }
764                fn alloc(&self) -> pathmap::alloc::GlobalAlloc {
765                    pathmap::alloc::global_alloc()
766                }
767            }
768        })
769    } else {
770        None
771    };
772
773    //GOAT, TODO: Same as above, we ought to use the generic allocator A, if the enum has one, but use the GlobalAlloc if not,
774    // this requires parsing the impl_generics to see if there is an `A: Allocator` that is defined
775    let zipper_infallible_subtries_impl = if traits.contains(&PolyZipperTrait::ZipperInfallibleSubtries) {
776        let zipper_infallible_subtries_where = if include_where_clause {
777            quote! {
778                where
779                    #(#inner_types: pathmap::zipper::ZipperInfallibleSubtries<V>,)*
780                    #where_clause
781            }
782        } else {
783            quote! {}
784        };
785        Some(quote! {
786            impl #impl_generics pathmap::zipper::ZipperInfallibleSubtries<V> for #enum_name #ty_generics
787            #zipper_infallible_subtries_where
788            {
789                fn make_map(&self) -> pathmap::PathMap<V> {
790                    match self {
791                        #(#variant_arms => inner.make_map(),)*
792                    }
793                }
794
795                fn get_trie_ref(&self) -> pathmap::zipper::TrieRef<'_, V> {
796                    match self {
797                        #(#variant_arms => inner.get_trie_ref(),)*
798                    }
799                }
800
801                fn get_focus(&self) -> pathmap::zipper::OpaqueAbstractNodeRef<'_, V, pathmap::alloc::GlobalAlloc> {
802                    match self {
803                        #(#variant_arms => inner.get_focus(),)*
804                    }
805                }
806
807                fn get_focus_at<K: AsRef<[u8]>>(&self, path: K) -> pathmap::zipper::OpaqueAbstractNodeRef<'_, V, pathmap::alloc::GlobalAlloc> {
808                    match self {
809                        #(#variant_arms => inner.get_focus_at(path),)*
810                    }
811                }
812
813                fn try_borrow_focus(&self) -> Option<pathmap::zipper::OpaqueTrieNodeRef<'_, V, pathmap::alloc::GlobalAlloc>> {
814                    match self {
815                        #(#variant_arms => inner.try_borrow_focus(),)*
816                    }
817                }
818            }
819        })
820    } else {
821        None
822    };
823
824    let expanded = quote! {
825        #(#from_impls)*
826        #zipper_impl
827        #zipper_values_impl
828        #zipper_read_only_values_impl
829        #zipper_read_only_conditional_values_impl
830        // #zipper_forking_impl
831        #zipper_moving_impl
832        #zipper_concrete_impl
833        #zipper_absolute_path_impl
834        #zipper_path_buffer_impl
835        #zipper_iteration_impl
836        #zipper_read_only_iteration_impl
837        #zipper_read_only_conditional_iteration_impl
838        #zipper_subtries_impl
839        #zipper_infallible_subtries_impl
840    };
841
842    TokenStream::from(expanded)
843}