1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput, Data, Fields};
4
5#[proc_macro_derive(PolyZipper)]
7pub fn derive_poly_zipper(input: TokenStream) -> TokenStream {
8 let input = parse_macro_input!(input as DeriveInput);
9
10 let enum_name = &input.ident;
11 let generics = &input.generics;
12 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
13
14 let variants = match &input.data {
16 Data::Enum(data_enum) => &data_enum.variants,
17 _ => panic!("PolyZipper can only be derived for enums"),
18 };
19
20 let from_impls = variants.iter().map(|variant| {
22 let variant_name = &variant.ident;
23
24 let inner_type = match &variant.fields {
26 Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
27 &fields.unnamed[0].ty
28 }
29 _ => panic!("Each variant must have exactly one unnamed field"),
30 };
31
32 quote! {
33 impl #impl_generics From<#inner_type> for #enum_name #ty_generics #where_clause {
34 fn from(value: #inner_type) -> Self {
35 #enum_name::#variant_name(value)
36 }
37 }
38
39 impl #impl_generics core::convert::TryFrom<#enum_name #ty_generics> for #inner_type #where_clause {
40 type Error = ();
41
42 fn try_from(value: #enum_name #ty_generics) -> Result<Self, Self::Error> {
43 match value {
44 #enum_name::#variant_name(inner) => Ok(inner),
45 _ => Err(()),
46 }
47 }
48 }
49 }
50 });
51
52 let variant_arms: Vec<_> = variants.iter().map(|variant| {
53 let variant_name = &variant.ident;
54 quote! { Self::#variant_name(inner) }
55 }).collect();
56
57 let inner_types: Vec<_> = variants.iter().map(|variant| {
58 match &variant.fields {
59 Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
60 &fields.unnamed[0].ty
61 }
62 _ => panic!("Each variant must have exactly one unnamed field"),
63 }
64 }).collect();
65
66 let zipper_impl = {
68 let variant_arms = &variant_arms;
69 quote! {
70 impl #impl_generics pathmap::zipper::Zipper for #enum_name #ty_generics #where_clause {
71 fn path_exists(&self) -> bool {
72 match self {
73 #(#variant_arms => inner.path_exists(),)*
74 }
75 }
76
77 fn is_val(&self) -> bool {
78 match self {
79 #(#variant_arms => inner.is_val(),)*
80 }
81 }
82
83 fn child_count(&self) -> usize {
84 match self {
85 #(#variant_arms => inner.child_count(),)*
86 }
87 }
88
89 fn child_mask(&self) -> pathmap::utils::ByteMask {
90 match self {
91 #(#variant_arms => inner.child_mask(),)*
92 }
93 }
94 }
95 }
96 };
97
98 let zipper_values_impl = {
100 let variant_arms = &variant_arms;
101 quote! {
102 impl #impl_generics pathmap::zipper::ZipperValues<V> for #enum_name #ty_generics
103 where
104 #(#inner_types: pathmap::zipper::ZipperValues<V>,)*
105 #where_clause
106 {
107 fn val(&self) -> Option<&V> {
108 match self {
109 #(#variant_arms => inner.val(),)*
110 }
111 }
112 }
113 }
114 };
115
116 let zipper_read_only_values_impl = {
118 let variant_arms = &variant_arms;
119 quote! {
120 impl #impl_generics pathmap::zipper::ZipperReadOnlyValues<'trie, V> for #enum_name #ty_generics
121 where
122 #(#inner_types: pathmap::zipper::ZipperReadOnlyValues<'trie, V>,)*
123 #where_clause
124 {
125 fn get_val(&self) -> Option<&'trie V> {
126 match self {
127 #(#variant_arms => inner.get_val(),)*
128 }
129 }
130 }
131 }
132 };
133
134 let witness_enum_name = syn::Ident::new(&format!("{}Witness", enum_name), enum_name.span());
136 let variant_names: Vec<_> = variants.iter().map(|variant| &variant.ident).collect();
137
138 let zipper_read_only_conditional_values_impl = {
140 quote! {
141 pub enum #witness_enum_name #impl_generics
144 where
145 #(#inner_types: pathmap::zipper::ZipperReadOnlyConditionalValues<'trie, V>,)*
146 #where_clause
147 {
148 #(#variant_names(<#inner_types as pathmap::zipper::ZipperReadOnlyConditionalValues<'trie, V>>::WitnessT),)*
149 }
150
151 impl #impl_generics pathmap::zipper::ZipperReadOnlyConditionalValues<'trie, V> for #enum_name #ty_generics
152 where
153 #(#inner_types: pathmap::zipper::ZipperReadOnlyConditionalValues<'trie, V>,)*
154 #where_clause
155 {
156 type WitnessT = #witness_enum_name #ty_generics;
157
158 fn witness<'w>(&self) -> Self::WitnessT {
159 match self {
160 #(Self::#variant_names(inner) => #witness_enum_name::#variant_names(inner.witness()),)*
161 }
162 }
163
164 fn get_val_with_witness<'w>(&self, witness: &'w Self::WitnessT) -> Option<&'w V> where 'trie: 'w {
165 match (self, witness) {
166 #((Self::#variant_names(inner), #witness_enum_name::#variant_names(w)) => inner.get_val_with_witness(w),)*
167 _ => {
168 debug_assert!(false, "Witness variant must match zipper + variant");
169 None
170 },
171 }
172 }
173 }
174 }
175 };
176
177 let zipper_moving_impl = {
218 let variant_arms = &variant_arms;
219 quote! {
220 impl #impl_generics pathmap::zipper::ZipperMoving for #enum_name #ty_generics
221 where
222 #(#inner_types: pathmap::zipper::ZipperMoving,)*
223 #where_clause
224 {
225 fn path(&self) -> &[u8] {
226 match self {
227 #(#variant_arms => inner.path(),)*
228 }
229 }
230
231 fn val_count(&self) -> usize {
232 match self {
233 #(#variant_arms => inner.val_count(),)*
234 }
235 }
236
237 fn descend_to<K: AsRef<[u8]>>(&mut self, k: K) {
238 match self {
239 #(#variant_arms => inner.descend_to(k),)*
240 }
241 }
242
243 fn descend_to_check<K: AsRef<[u8]>>(&mut self, k: K) -> bool {
244 match self {
245 #(#variant_arms => inner.descend_to_check(k),)*
246 }
247 }
248
249 #[inline]
250 fn descend_to_byte(&mut self, k: u8) {
251 match self {
252 #(#variant_arms => inner.descend_to_byte(k),)*
253 }
254 }
255
256 #[inline]
257 fn descend_to_existing_byte(&mut self, k: u8) -> bool {
258 match self {
259 #(#variant_arms => inner.descend_to_existing_byte(k),)*
260 }
261 }
262
263 fn ascend(&mut self, steps: usize) -> bool {
264 match self {
265 #(#variant_arms => inner.ascend(steps),)*
266 }
267 }
268
269 fn ascend_until(&mut self) -> bool {
270 match self {
271 #(#variant_arms => inner.ascend_until(),)*
272 }
273 }
274
275 fn ascend_until_branch(&mut self) -> bool {
276 match self {
277 #(#variant_arms => inner.ascend_until_branch(),)*
278 }
279 }
280 }
281 }
282 };
283
284 let zipper_concrete_impl = {
286 let variant_arms = &variant_arms;
287 quote! {
288 impl #impl_generics pathmap::zipper::ZipperConcrete for #enum_name #ty_generics
289 where
290 #(#inner_types: pathmap::zipper::ZipperConcrete,)*
291 #where_clause
292 {
293 fn shared_node_id(&self) -> Option<u64> {
294 match self {
295 #(#variant_arms => inner.shared_node_id(),)*
296 }
297 }
298 fn is_shared(&self) -> bool {
299 match self {
300 #(#variant_arms => inner.is_shared(),)*
301 }
302 }
303 }
304 }
305 };
306
307 let zipper_absolute_path_impl = {
309 let variant_arms = &variant_arms;
310 quote! {
311 impl #impl_generics pathmap::zipper::ZipperAbsolutePath for #enum_name #ty_generics
312 where
313 #(#inner_types: pathmap::zipper::ZipperAbsolutePath,)*
314 #where_clause
315 {
316 fn origin_path(&self) -> &[u8] {
317 match self {
318 #(#variant_arms => inner.origin_path(),)*
319 }
320 }
321
322 fn root_prefix_path(&self) -> &[u8] {
323 match self {
324 #(#variant_arms => inner.root_prefix_path(),)*
325 }
326 }
327 }
328 }
329 };
330
331 let zipper_path_buffer_impl = {
333 let variant_arms = &variant_arms;
334 quote! {
335 impl #impl_generics pathmap::zipper::ZipperPathBuffer for #enum_name #ty_generics
336 where
337 #(#inner_types: pathmap::zipper::ZipperPathBuffer,)*
338 #where_clause
339 {
340 unsafe fn origin_path_assert_len(&self, len: usize) -> &[u8] {
341 match self {
342 #(#variant_arms => unsafe { inner.origin_path_assert_len(len) },)*
343 }
344 }
345
346 fn prepare_buffers(&mut self) {
347 match self {
348 #(#variant_arms => inner.prepare_buffers(),)*
349 }
350 }
351
352 fn reserve_buffers(&mut self, path_len: usize, stack_depth: usize) {
353 match self {
354 #(#variant_arms => inner.reserve_buffers(path_len, stack_depth),)*
355 }
356 }
357 }
358 }
359 };
360
361 let zipper_iteration_impl = {
363 let variant_arms = &variant_arms;
364 quote! {
365 impl #impl_generics pathmap::zipper::ZipperIteration for #enum_name #ty_generics
366 where
367 #(#inner_types: pathmap::zipper::ZipperIteration,)*
368 #where_clause
369 {
370 fn to_next_val(&mut self) -> bool {
371 match self {
372 #(#variant_arms => inner.to_next_val(),)*
373 }
374 }
375
376 fn descend_last_path(&mut self) -> bool {
377 match self {
378 #(#variant_arms => inner.descend_last_path(),)*
379 }
380 }
381
382 fn descend_first_k_path(&mut self, k: usize) -> bool {
383 match self {
384 #(#variant_arms => inner.descend_first_k_path(k),)*
385 }
386 }
387
388 fn to_next_k_path(&mut self, k: usize) -> bool {
389 match self {
390 #(#variant_arms => inner.to_next_k_path(k),)*
391 }
392 }
393 }
394 }
395 };
396
397 let zipper_read_only_iteration_impl = {
399 let variant_arms = &variant_arms;
400 quote! {
401 impl #impl_generics pathmap::zipper::ZipperReadOnlyIteration<'trie, V> for #enum_name #ty_generics
402 where
403 #(#inner_types: pathmap::zipper::ZipperReadOnlyIteration<'trie, V>,)*
404 #where_clause
405 {
406 fn to_next_get_val(&mut self) -> Option<&'trie V> {
407 match self {
408 #(#variant_arms => inner.to_next_get_val(),)*
409 }
410 }
411
412 #[deprecated]
413 fn to_next_get_value(&mut self) -> Option<&'trie V> {
414 match self {
415 #(#variant_arms => inner.to_next_get_value(),)*
416 }
417 }
418 }
419 }
420 };
421
422 let zipper_read_only_conditional_iteration_impl = {
424 quote! {
425 impl #impl_generics pathmap::zipper::ZipperReadOnlyConditionalIteration<'trie, V> for #enum_name #ty_generics
426 where
427 #(#inner_types: pathmap::zipper::ZipperReadOnlyConditionalIteration<'trie, V>,)*
428 #where_clause
429 {
430 fn to_next_get_val_with_witness<'w>(&mut self, witness: &'w Self::WitnessT) -> Option<&'w V> where 'trie: 'w {
431 match (self, witness) {
432 #((Self::#variant_names(inner), #witness_enum_name::#variant_names(w)) => inner.to_next_get_val_with_witness(w),)*
433 _ => {
434 debug_assert!(false, "Witness variant must match zipper variant");
435 None
436 },
437 }
438 }
439 }
440 }
441 };
442
443 let expanded = quote! {
444 #(#from_impls)*
445 #zipper_impl
446 #zipper_values_impl
447 #zipper_read_only_values_impl
448 #zipper_read_only_conditional_values_impl
449 #zipper_moving_impl
451 #zipper_concrete_impl
452 #zipper_absolute_path_impl
453 #zipper_path_buffer_impl
454 #zipper_iteration_impl
455 #zipper_read_only_iteration_impl
456 #zipper_read_only_conditional_iteration_impl
457 };
458
459 TokenStream::from(expanded)
460}