key_paths_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{Data, DeriveInput, Fields, Type, parse_macro_input};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6enum WrapperKind {
7    None,
8    Option,
9    Box,
10    Rc,
11    Arc,
12    Vec,
13    HashMap,
14    BTreeMap,
15    HashSet,
16    BTreeSet,
17    VecDeque,
18    LinkedList,
19    BinaryHeap,
20    // Nested container support
21    OptionBox,
22    OptionRc,
23    OptionArc,
24    BoxOption,
25    RcOption,
26    ArcOption,
27    VecOption,
28    OptionVec,
29    HashMapOption,
30    OptionHashMap,
31}
32
33#[proc_macro_derive(Keypaths)]
34pub fn derive_keypaths(input: TokenStream) -> TokenStream {
35    let input = parse_macro_input!(input as DeriveInput);
36    let name = input.ident;
37
38    let methods = match input.data {
39        Data::Struct(data_struct) => match data_struct.fields {
40            Fields::Named(fields_named) => {
41                let mut tokens = proc_macro2::TokenStream::new();
42                for field in fields_named.named.iter() {
43                    let field_ident = field.ident.as_ref().unwrap();
44                    let ty = &field.ty;
45
46                    let r_fn = format_ident!("{}_r", field_ident);
47                    let w_fn = format_ident!("{}_w", field_ident);
48                    let fr_fn = format_ident!("{}_fr", field_ident);
49                    let fw_fn = format_ident!("{}_fw", field_ident);
50                    let fr_at_fn = format_ident!("{}_fr_at", field_ident);
51                    let fw_at_fn = format_ident!("{}_fw_at", field_ident);
52
53                    let (kind, inner_ty) = extract_wrapper_inner_type(ty);
54
55                    match (kind, inner_ty) {
56                        (WrapperKind::Option, Some(inner_ty)) => {
57                            tokens.extend(quote! {
58                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
59                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
60                                }
61                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
62                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
63                                }
64                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
65                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.as_ref())
66                                }
67                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
68                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#field_ident.as_mut())
69                                }
70                            });
71                        }
72                        (WrapperKind::Vec, Some(inner_ty)) => {
73                            tokens.extend(quote! {
74                                pub fn #fr_at_fn(index: usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
75                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#field_ident.get(index))
76                                }
77                                pub fn #fw_at_fn(index: usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
78                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#field_ident.get_mut(index))
79                                }
80                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
81                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
82                                }
83                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
84                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
85                                }
86                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
87                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.first())
88                                }
89                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
90                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#field_ident.first_mut())
91                                }
92                            });
93                        }
94                        (WrapperKind::HashMap, Some(inner_ty)) => {
95                            tokens.extend(quote! {
96                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
97                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
98                                }
99                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
100                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
101                                }
102                                pub fn #fr_fn(key: String) -> key_paths_core::KeyPaths<#name, #inner_ty> {
103                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#field_ident.get(&key))
104                                }
105                                pub fn #fw_fn(key: String) -> key_paths_core::KeyPaths<#name, #inner_ty> {
106                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#field_ident.get_mut(&key))
107                                }
108                                pub fn #fr_at_fn(key: String) -> key_paths_core::KeyPaths<#name, #inner_ty> {
109                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#field_ident.get(&key))
110                                }
111                                pub fn #fw_at_fn(key: String) -> key_paths_core::KeyPaths<#name, #inner_ty> {
112                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#field_ident.get_mut(&key))
113                                }
114                            });
115                        }
116                        (WrapperKind::Box, Some(inner_ty)) => {
117                            tokens.extend(quote! {
118                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
119                                    key_paths_core::KeyPaths::readable(|s: &#name| &*s.#field_ident)
120                                }
121                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
122                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut *s.#field_ident)
123                                }
124                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
125                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| Some(&*s.#field_ident))
126                                }
127                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
128                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| Some(&mut *s.#field_ident))
129                                }
130                            });
131                        }
132                        (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
133                            tokens.extend(quote! {
134                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
135                                    key_paths_core::KeyPaths::readable(|s: &#name| &*s.#field_ident)
136                                }
137                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
138                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| Some(&*s.#field_ident))
139                                }
140                            });
141                        }
142                        (WrapperKind::BTreeMap, Some(inner_ty)) => {
143                            tokens.extend(quote! {
144                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
145                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
146                                }
147                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
148                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
149                                }
150                                // Note: Key-based access methods for BTreeMap require the exact key type
151                                // For now, we'll skip generating these methods to avoid generic constraint issues
152                            });
153                        }
154                        (WrapperKind::HashSet, Some(inner_ty)) => {
155                            tokens.extend(quote! {
156                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
157                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
158                                }
159                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
160                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
161                                }
162                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
163                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.iter().next())
164                                }
165                            });
166                        }
167                        (WrapperKind::BTreeSet, Some(inner_ty)) => {
168                            tokens.extend(quote! {
169                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
170                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
171                                }
172                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
173                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
174                                }
175                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
176                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.iter().next())
177                                }
178                            });
179                        }
180                        (WrapperKind::VecDeque, Some(inner_ty)) => {
181                            tokens.extend(quote! {
182                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
183                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
184                                }
185                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
186                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
187                                }
188                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
189                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.front())
190                                }
191                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
192                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#field_ident.front_mut())
193                                }
194                                pub fn #fr_at_fn(index: usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
195                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#field_ident.get(index))
196                                }
197                                pub fn #fw_at_fn(index: usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
198                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#field_ident.get_mut(index))
199                                }
200                            });
201                        }
202                        (WrapperKind::LinkedList, Some(inner_ty)) => {
203                            tokens.extend(quote! {
204                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
205                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
206                                }
207                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
208                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
209                                }
210                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
211                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.front())
212                                }
213                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
214                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#field_ident.front_mut())
215                                }
216                            });
217                        }
218                        (WrapperKind::BinaryHeap, Some(inner_ty)) => {
219                            tokens.extend(quote! {
220                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
221                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
222                                }
223                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
224                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
225                                }
226                                // Note: BinaryHeap peek() returns &T, but we need &inner_ty
227                                // For now, we'll skip failable methods for BinaryHeap to avoid type issues
228                            });
229                        }
230                        // Nested container combinations - COMMENTED OUT FOR NOW
231                        // TODO: Fix type mismatch issues in nested combinations
232                        /*
233                        (WrapperKind::OptionBox, Some(inner_ty)) => {
234                            tokens.extend(quote! {
235                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
236                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
237                                }
238                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
239                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
240                                }
241                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
242                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.as_ref().map(|b| &**b))
243                                }
244                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
245                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#field_ident.as_mut().map(|b| &mut **b))
246                                }
247                            });
248                        }
249                        (WrapperKind::OptionRc, Some(inner_ty)) => {
250                            tokens.extend(quote! {
251                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
252                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
253                                }
254                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
255                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.as_ref().map(|r| &**r))
256                                }
257                            });
258                        }
259                        (WrapperKind::OptionArc, Some(inner_ty)) => {
260                            tokens.extend(quote! {
261                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
262                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
263                                }
264                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
265                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.as_ref().map(|a| &**a))
266                                }
267                            });
268                        }
269                        (WrapperKind::BoxOption, Some(inner_ty)) => {
270                            tokens.extend(quote! {
271                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
272                                    key_paths_core::KeyPaths::readable(|s: &#name| &*s.#field_ident)
273                                }
274                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
275                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut *s.#field_ident)
276                                }
277                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
278                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| (*s.#field_ident).as_ref())
279                                }
280                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
281                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| (*s.#field_ident).as_mut())
282                                }
283                            });
284                        }
285                        (WrapperKind::RcOption, Some(inner_ty)) => {
286                            tokens.extend(quote! {
287                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
288                                    key_paths_core::KeyPaths::readable(|s: &#name| &*s.#field_ident)
289                                }
290                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
291                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| (*s.#field_ident).as_ref())
292                                }
293                            });
294                        }
295                        (WrapperKind::ArcOption, Some(inner_ty)) => {
296                            tokens.extend(quote! {
297                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
298                                    key_paths_core::KeyPaths::readable(|s: &#name| &*s.#field_ident)
299                                }
300                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
301                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| (*s.#field_ident).as_ref())
302                                }
303                            });
304                        }
305                        (WrapperKind::VecOption, Some(inner_ty)) => {
306                            tokens.extend(quote! {
307                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
308                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
309                                }
310                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
311                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
312                                }
313                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
314                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.first().and_then(|opt| opt.as_ref()))
315                                }
316                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
317                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#field_ident.first_mut().and_then(|opt| opt.as_mut()))
318                                }
319                                pub fn #fr_at_fn(index: usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
320                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#field_ident.get(index).and_then(|opt| opt.as_ref()))
321                                }
322                                pub fn #fw_at_fn(index: usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
323                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#field_ident.get_mut(index).and_then(|opt| opt.as_mut()))
324                                }
325                            });
326                        }
327                        (WrapperKind::OptionVec, Some(inner_ty)) => {
328                            tokens.extend(quote! {
329                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
330                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
331                                }
332                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
333                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
334                                }
335                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
336                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#field_ident.as_ref().and_then(|v| v.first()))
337                                }
338                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
339                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#field_ident.as_mut().and_then(|v| v.first_mut()))
340                                }
341                                pub fn #fr_at_fn(index: usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
342                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#field_ident.as_ref().and_then(|v| v.get(index)))
343                                }
344                                pub fn #fw_at_fn(index: usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
345                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#field_ident.as_mut().and_then(|v| v.get_mut(index)))
346                                }
347                            });
348                        }
349                        (WrapperKind::HashMapOption, Some(inner_ty)) => {
350                            tokens.extend(quote! {
351                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
352                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
353                                }
354                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
355                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
356                                }
357                                pub fn #fr_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
358                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#field_ident.get(&key).and_then(|opt| opt.as_ref()))
359                                }
360                                pub fn #fw_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
361                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#field_ident.get_mut(&key).and_then(|opt| opt.as_mut()))
362                                }
363                                pub fn #fr_at_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
364                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#field_ident.get(&key).and_then(|opt| opt.as_ref()))
365                                }
366                                pub fn #fw_at_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
367                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#field_ident.get_mut(&key).and_then(|opt| opt.as_mut()))
368                                }
369                            });
370                        }
371                        (WrapperKind::OptionHashMap, Some(inner_ty)) => {
372                            tokens.extend(quote! {
373                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
374                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
375                                }
376                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
377                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
378                                }
379                                pub fn #fr_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
380                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#field_ident.as_ref().and_then(|m| m.get(&key)))
381                                }
382                                pub fn #fw_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
383                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#field_ident.as_mut().and_then(|m| m.get_mut(&key)))
384                                }
385                                pub fn #fr_at_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
386                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#field_ident.as_ref().and_then(|m| m.get(&key)))
387                                }
388                                pub fn #fw_at_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
389                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#field_ident.as_mut().and_then(|m| m.get_mut(&key)))
390                                }
391                            });
392                        }
393                        */
394                        (WrapperKind::None, None) => {
395                            tokens.extend(quote! {
396                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
397                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
398                                }
399                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
400                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
401                                }
402                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #ty> {
403                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| Some(&s.#field_ident))
404                                }
405                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #ty> {
406                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| Some(&mut s.#field_ident))
407                                }
408                            });
409                        }
410                        _ => {
411                            tokens.extend(quote! {
412                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
413                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#field_ident)
414                                }
415                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
416                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#field_ident)
417                                }
418                            });
419                        }
420                    }
421                }
422                tokens
423            }
424            Fields::Unnamed(unnamed) => {
425                let mut tokens = proc_macro2::TokenStream::new();
426                for (idx, field) in unnamed.unnamed.iter().enumerate() {
427                    let idx_lit = syn::Index::from(idx);
428                    let ty = &field.ty;
429
430                    let r_fn = format_ident!("f{}_r", idx);
431                    let w_fn = format_ident!("f{}_w", idx);
432                    let fr_fn = format_ident!("f{}_fr", idx);
433                    let fw_fn = format_ident!("f{}_fw", idx);
434                    let fr_at_fn = format_ident!("f{}_fr_at", idx);
435                    let fw_at_fn = format_ident!("f{}_fw_at", idx);
436
437                    let (kind, inner_ty) = extract_wrapper_inner_type(ty);
438
439                    match (kind, inner_ty) {
440                        (WrapperKind::Option, Some(inner_ty)) => {
441                            tokens.extend(quote! {
442                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
443                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
444                                }
445                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
446                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
447                                }
448                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
449                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.as_ref())
450                                }
451                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
452                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#idx_lit.as_mut())
453                                }
454                            });
455                        }
456                        (WrapperKind::Vec, Some(inner_ty)) => {
457                            tokens.extend(quote! {
458                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
459                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
460                                }
461                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
462                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
463                                }
464                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
465                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.first())
466                                }
467                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
468                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#idx_lit.first_mut())
469                                }
470                                pub fn #fr_at_fn(index: &'static usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
471                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.get(*index))
472                                }
473                                pub fn #fw_at_fn(index: &'static usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
474                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#idx_lit.get_mut(*index))
475                                }
476                            });
477                        }
478                        (WrapperKind::HashMap, Some(inner_ty)) => {
479                            tokens.extend(quote! {
480                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
481                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
482                                }
483                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
484                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
485                                }
486                                pub fn #fr_fn(key: String) -> key_paths_core::KeyPaths<#name, #inner_ty> {
487                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#idx_lit.get(&key))
488                                }
489                                pub fn #fw_fn(key: String) -> key_paths_core::KeyPaths<#name, #inner_ty> {
490                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#idx_lit.get_mut(&key))
491                                }
492                                pub fn #fr_at_fn(key: String) -> key_paths_core::KeyPaths<#name, #inner_ty> {
493                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#idx_lit.get(&key))
494                                }
495                                pub fn #fw_at_fn(key: String) -> key_paths_core::KeyPaths<#name, #inner_ty> {
496                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#idx_lit.get_mut(&key))
497                                }
498                            });
499                        }
500                        (WrapperKind::Box, Some(inner_ty)) => {
501                            tokens.extend(quote! {
502                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
503                                    key_paths_core::KeyPaths::readable(|s: &#name| &*s.#idx_lit)
504                                }
505                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
506                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut *s.#idx_lit)
507                                }
508                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
509                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| Some(&*s.#idx_lit))
510                                }
511                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
512                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| Some(&mut *s.#idx_lit))
513                                }
514                            });
515                        }
516                        (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
517                            tokens.extend(quote! {
518                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
519                                    key_paths_core::KeyPaths::readable(|s: &#name| &*s.#idx_lit)
520                                }
521                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
522                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| Some(&*s.#idx_lit))
523                                }
524                            });
525                        }
526                        (WrapperKind::BTreeMap, Some(inner_ty)) => {
527                            tokens.extend(quote! {
528                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
529                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
530                                }
531                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
532                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
533                                }
534                                // Note: Key-based access methods for BTreeMap require the exact key type
535                                // For now, we'll skip generating these methods to avoid generic constraint issues
536                            });
537                        }
538                        (WrapperKind::HashSet, Some(inner_ty)) => {
539                            tokens.extend(quote! {
540                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
541                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
542                                }
543                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
544                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
545                                }
546                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
547                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.iter().next())
548                                }
549                            });
550                        }
551                        (WrapperKind::BTreeSet, Some(inner_ty)) => {
552                            tokens.extend(quote! {
553                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
554                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
555                                }
556                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
557                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
558                                }
559                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
560                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.iter().next())
561                                }
562                            });
563                        }
564                        (WrapperKind::VecDeque, Some(inner_ty)) => {
565                            tokens.extend(quote! {
566                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
567                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
568                                }
569                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
570                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
571                                }
572                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
573                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.front())
574                                }
575                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
576                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#idx_lit.front_mut())
577                                }
578                            });
579                        }
580                        (WrapperKind::LinkedList, Some(inner_ty)) => {
581                            tokens.extend(quote! {
582                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
583                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
584                                }
585                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
586                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
587                                }
588                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
589                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.front())
590                                }
591                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
592                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#idx_lit.front_mut())
593                                }
594                            });
595                        }
596                        (WrapperKind::BinaryHeap, Some(inner_ty)) => {
597                            tokens.extend(quote! {
598                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
599                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
600                                }
601                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
602                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
603                                }
604                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
605                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.peek())
606                                }
607                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
608                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#idx_lit.peek_mut().map(|v| &mut **v))
609                                }
610                            });
611                        }
612                        // Nested container combinations for tuple structs - COMMENTED OUT FOR NOW
613                        /*
614                        (WrapperKind::OptionBox, Some(inner_ty)) => {
615                            tokens.extend(quote! {
616                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
617                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
618                                }
619                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
620                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
621                                }
622                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
623                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.as_ref().map(|b| &**b))
624                                }
625                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
626                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#idx_lit.as_mut().map(|b| &mut **b))
627                                }
628                            });
629                        }
630                        (WrapperKind::OptionRc, Some(inner_ty)) => {
631                            tokens.extend(quote! {
632                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
633                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
634                                }
635                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
636                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.as_ref().map(|r| &**r))
637                                }
638                            });
639                        }
640                        (WrapperKind::OptionArc, Some(inner_ty)) => {
641                            tokens.extend(quote! {
642                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
643                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
644                                }
645                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
646                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.as_ref().map(|a| &**a))
647                                }
648                            });
649                        }
650                        (WrapperKind::BoxOption, Some(inner_ty)) => {
651                            tokens.extend(quote! {
652                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
653                                    key_paths_core::KeyPaths::readable(|s: &#name| &*s.#idx_lit)
654                                }
655                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
656                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut *s.#idx_lit)
657                                }
658                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
659                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| (*s.#idx_lit).as_ref())
660                                }
661                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
662                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| (*s.#idx_lit).as_mut())
663                                }
664                            });
665                        }
666                        (WrapperKind::RcOption, Some(inner_ty)) => {
667                            tokens.extend(quote! {
668                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
669                                    key_paths_core::KeyPaths::readable(|s: &#name| &*s.#idx_lit)
670                                }
671                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
672                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| (*s.#idx_lit).as_ref())
673                                }
674                            });
675                        }
676                        (WrapperKind::ArcOption, Some(inner_ty)) => {
677                            tokens.extend(quote! {
678                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
679                                    key_paths_core::KeyPaths::readable(|s: &#name| &*s.#idx_lit)
680                                }
681                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
682                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| (*s.#idx_lit).as_ref())
683                                }
684                            });
685                        }
686                        (WrapperKind::VecOption, Some(inner_ty)) => {
687                            tokens.extend(quote! {
688                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
689                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
690                                }
691                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
692                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
693                                }
694                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
695                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.first().and_then(|opt| opt.as_ref()))
696                                }
697                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
698                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#idx_lit.first_mut().and_then(|opt| opt.as_mut()))
699                                }
700                            });
701                        }
702                        (WrapperKind::OptionVec, Some(inner_ty)) => {
703                            tokens.extend(quote! {
704                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
705                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
706                                }
707                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
708                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
709                                }
710                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
711                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| s.#idx_lit.as_ref().and_then(|v| v.first()))
712                                }
713                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
714                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| s.#idx_lit.as_mut().and_then(|v| v.first_mut()))
715                                }
716                            });
717                        }
718                        (WrapperKind::HashMapOption, Some(inner_ty)) => {
719                            tokens.extend(quote! {
720                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
721                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
722                                }
723                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
724                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
725                                }
726                                pub fn #fr_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
727                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#idx_lit.get(&key).and_then(|opt| opt.as_ref()))
728                                }
729                                pub fn #fw_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
730                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#idx_lit.get_mut(&key).and_then(|opt| opt.as_mut()))
731                                }
732                            });
733                        }
734                        (WrapperKind::OptionHashMap, Some(inner_ty)) => {
735                            tokens.extend(quote! {
736                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
737                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
738                                }
739                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
740                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
741                                }
742                                pub fn #fr_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
743                                    key_paths_core::KeyPaths::failable_readable(move |s: &#name| s.#idx_lit.as_ref().and_then(|m| m.get(&key)))
744                                }
745                                pub fn #fw_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
746                                    key_paths_core::KeyPaths::failable_writable(move |s: &mut #name| s.#idx_lit.as_mut().and_then(|m| m.get_mut(&key)))
747                                }
748                            });
749                        }
750                        */
751                        (WrapperKind::None, None) => {
752                            tokens.extend(quote! {
753                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
754                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
755                                }
756                                pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #ty> {
757                                    key_paths_core::KeyPaths::writable(|s: &mut #name| &mut s.#idx_lit)
758                                }
759                                pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #ty> {
760                                    key_paths_core::KeyPaths::failable_readable(|s: &#name| Some(&s.#idx_lit))
761                                }
762                                pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #ty> {
763                                    key_paths_core::KeyPaths::failable_writable(|s: &mut #name| Some(&mut s.#idx_lit))
764                                }
765                            });
766                        }
767                        _ => {
768                            tokens.extend(quote! {
769                                pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #ty> {
770                                    key_paths_core::KeyPaths::readable(|s: &#name| &s.#idx_lit)
771                                }
772                            });
773                        }
774                    }
775                }
776                tokens
777            }
778            _ => quote! {
779                compile_error!("Keypaths derive supports only structs with named or unnamed fields");
780            },
781        },
782        Data::Enum(data_enum) => {
783            let mut tokens = proc_macro2::TokenStream::new();
784            for variant in data_enum.variants.iter() {
785                let v_ident = &variant.ident;
786                let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
787                let r_fn = format_ident!("{}_case_r", snake);
788                let w_fn = format_ident!("{}_case_w", snake);
789                let fr_fn = format_ident!("{}_case_fr", snake);
790                let fw_fn = format_ident!("{}_case_fw", snake);
791                let fr_at_fn = format_ident!("{}_case_fr_at", snake);
792                let fw_at_fn = format_ident!("{}_case_fw_at", snake);
793
794                match &variant.fields {
795                    Fields::Unit => {
796                        tokens.extend(quote! {
797                            pub fn #r_fn() -> key_paths_core::KeyPaths<#name, ()> {
798                                static UNIT: () = ();
799                                key_paths_core::KeyPaths::readable_enum(
800                                    |_| #name::#v_ident,
801                                    |e: &#name| match e { #name::#v_ident => Some(&UNIT), _ => None }
802                                )
803                            }
804                        });
805                    }
806                    Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
807                        let field_ty = &unnamed.unnamed.first().unwrap().ty;
808                        let (kind, inner_ty_opt) = extract_wrapper_inner_type(field_ty);
809
810                        match (kind, inner_ty_opt) {
811                            (WrapperKind::Option, Some(inner_ty)) => {
812                                tokens.extend(quote! {
813                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
814                                        key_paths_core::KeyPaths::readable_enum(
815                                            #name::#v_ident,
816                                            |e: &#name| match e { #name::#v_ident(v) => v.as_ref(), _ => None }
817                                        )
818                                    }
819                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
820                                        key_paths_core::KeyPaths::writable_enum(
821                                            #name::#v_ident,
822                                            |e: &#name| match e { #name::#v_ident(v) => v.as_ref(), _ => None },
823                                            |e: &mut #name| match e { #name::#v_ident(v) => v.as_mut(), _ => None },
824                                        )
825                                    }
826                                });
827                            }
828                            (WrapperKind::Vec, Some(inner_ty)) => {
829                                tokens.extend(quote! {
830                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
831                                        key_paths_core::KeyPaths::readable_enum(
832                                            #name::#v_ident,
833                                            |e: &#name| match e { #name::#v_ident(v) => v.first(), _ => None }
834                                        )
835                                    }
836                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
837                                        key_paths_core::KeyPaths::writable_enum(
838                                            #name::#v_ident,
839                                            |e: &#name| match e { #name::#v_ident(v) => v.first(), _ => None },
840                                            |e: &mut #name| match e { #name::#v_ident(v) => v.first_mut(), _ => None },
841                                        )
842                                    }
843                                    pub fn #fr_at_fn(index: &'static usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
844                                        key_paths_core::KeyPaths::readable_enum(
845                                            #name::#v_ident,
846                                            |e: &#name| match e { #name::#v_ident(v) => v.get(*index), _ => None }
847                                        )
848                                    }
849                                    pub fn #fw_at_fn(index: &'static usize) -> key_paths_core::KeyPaths<#name, #inner_ty> {
850                                        key_paths_core::KeyPaths::writable_enum(
851                                            #name::#v_ident,
852                                            |e: &#name| match e { #name::#v_ident(v) => v.get(*index), _ => None },
853                                            |e: &mut #name| match e { #name::#v_ident(v) => v.get_mut(*index), _ => None },
854                                        )
855                                    }
856                                });
857                            }
858                        (WrapperKind::HashMap, Some(inner_ty)) => {
859                            tokens.extend(quote! {
860                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
861                                        key_paths_core::KeyPaths::readable_enum(
862                                            #name::#v_ident,
863                                            |e: &#name| match e { #name::#v_ident(v) => v.first().map(|(_, v)| v), _ => None }
864                                        )
865                                    }
866                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
867                                        key_paths_core::KeyPaths::writable_enum(
868                                            #name::#v_ident,
869                                            |e: &#name| match e { #name::#v_ident(v) => v.first().map(|(_, v)| v), _ => None },
870                                            |e: &mut #name| match e { #name::#v_ident(v) => v.first_mut().map(|(_, v)| v), _ => None },
871                                        )
872                                    }
873                                    pub fn #fr_at_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: &'static K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
874                                        key_paths_core::KeyPaths::readable_enum(
875                                            #name::#v_ident,
876                                            |e: &#name| match e { #name::#v_ident(v) => v.get(key), _ => None }
877                                        )
878                                    }
879                                    pub fn #fw_at_fn<K: ::std::hash::Hash + ::std::cmp::Eq + 'static>(key: &'static K) -> key_paths_core::KeyPaths<#name, #inner_ty> {
880                                        key_paths_core::KeyPaths::writable_enum(
881                                            #name::#v_ident,
882                                            |e: &#name| match e { #name::#v_ident(v) => v.get(key), _ => None },
883                                            |e: &mut #name| match e { #name::#v_ident(v) => v.get_mut(key), _ => None },
884                                        )
885                                    }
886                                });
887                            }
888                            (WrapperKind::Box, Some(inner_ty)) => {
889                                tokens.extend(quote! {
890                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
891                                        key_paths_core::KeyPaths::readable_enum(
892                                            #name::#v_ident,
893                                            |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None }
894                                        )
895                                    }
896                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
897                                        key_paths_core::KeyPaths::writable_enum(
898                                            #name::#v_ident,
899                                            |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None },
900                                            |e: &mut #name| match e { #name::#v_ident(v) => Some(&mut *v), _ => None },
901                                        )
902                                    }
903                                });
904                            }
905                            (WrapperKind::Rc, Some(inner_ty))
906                            | (WrapperKind::Arc, Some(inner_ty)) => {
907                                tokens.extend(quote! {
908                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
909                                        key_paths_core::KeyPaths::readable_enum(
910                                            #name::#v_ident,
911                                            |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None }
912                                        )
913                                    }
914                                });
915                            }
916                            (WrapperKind::BTreeMap, Some(inner_ty)) => {
917                                tokens.extend(quote! {
918                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
919                                        key_paths_core::KeyPaths::readable_enum(
920                                            #name::#v_ident,
921                                            |e: &#name| match e { #name::#v_ident(v) => v.first().map(|(_, v)| v), _ => None }
922                                        )
923                                    }
924                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
925                                        key_paths_core::KeyPaths::writable_enum(
926                                            #name::#v_ident,
927                                            |e: &#name| match e { #name::#v_ident(v) => v.first().map(|(_, v)| v), _ => None },
928                                            |e: &mut #name| match e { #name::#v_ident(v) => v.first_mut().map(|(_, v)| v), _ => None },
929                                        )
930                                    }
931                                });
932                            }
933                            (WrapperKind::HashSet, Some(inner_ty)) => {
934                                tokens.extend(quote! {
935                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
936                                        key_paths_core::KeyPaths::readable_enum(
937                                            #name::#v_ident,
938                                            |e: &#name| match e { #name::#v_ident(v) => v.iter().next(), _ => None }
939                                        )
940                                    }
941                                });
942                            }
943                            (WrapperKind::BTreeSet, Some(inner_ty)) => {
944                                tokens.extend(quote! {
945                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
946                                        key_paths_core::KeyPaths::readable_enum(
947                                            #name::#v_ident,
948                                            |e: &#name| match e { #name::#v_ident(v) => v.iter().next(), _ => None }
949                                        )
950                                    }
951                                });
952                            }
953                            (WrapperKind::VecDeque, Some(inner_ty)) => {
954                                tokens.extend(quote! {
955                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
956                                        key_paths_core::KeyPaths::readable_enum(
957                                            #name::#v_ident,
958                                            |e: &#name| match e { #name::#v_ident(v) => v.front(), _ => None }
959                                        )
960                                    }
961                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
962                                        key_paths_core::KeyPaths::writable_enum(
963                                            #name::#v_ident,
964                                            |e: &#name| match e { #name::#v_ident(v) => v.front(), _ => None },
965                                            |e: &mut #name| match e { #name::#v_ident(v) => v.front_mut(), _ => None },
966                                        )
967                                    }
968                                });
969                            }
970                            (WrapperKind::LinkedList, Some(inner_ty)) => {
971                                tokens.extend(quote! {
972                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
973                                        key_paths_core::KeyPaths::readable_enum(
974                                            #name::#v_ident,
975                                            |e: &#name| match e { #name::#v_ident(v) => v.front(), _ => None }
976                                        )
977                                    }
978                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
979                                        key_paths_core::KeyPaths::writable_enum(
980                                            #name::#v_ident,
981                                            |e: &#name| match e { #name::#v_ident(v) => v.front(), _ => None },
982                                            |e: &mut #name| match e { #name::#v_ident(v) => v.front_mut(), _ => None },
983                                        )
984                                    }
985                                });
986                            }
987                            (WrapperKind::BinaryHeap, Some(inner_ty)) => {
988                                tokens.extend(quote! {
989                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
990                                        key_paths_core::KeyPaths::readable_enum(
991                                            #name::#v_ident,
992                                            |e: &#name| match e { #name::#v_ident(v) => v.peek(), _ => None }
993                                        )
994                                    }
995                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
996                                        key_paths_core::KeyPaths::writable_enum(
997                                            #name::#v_ident,
998                                            |e: &#name| match e { #name::#v_ident(v) => v.peek(), _ => None },
999                                            |e: &mut #name| match e { #name::#v_ident(v) => v.peek_mut().map(|v| &mut **v), _ => None },
1000                                        )
1001                                    }
1002                                });
1003                            }
1004                            // Nested container combinations for enums - COMMENTED OUT FOR NOW
1005                            /*
1006                            (WrapperKind::OptionBox, Some(inner_ty)) => {
1007                                tokens.extend(quote! {
1008                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1009                                        key_paths_core::KeyPaths::readable_enum(
1010                                            #name::#v_ident,
1011                                            |e: &#name| match e { #name::#v_ident(v) => v.as_ref().map(|b| &**b), _ => None }
1012                                        )
1013                                    }
1014                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1015                                        key_paths_core::KeyPaths::writable_enum(
1016                                            #name::#v_ident,
1017                                            |e: &#name| match e { #name::#v_ident(v) => v.as_ref().map(|b| &**b), _ => None },
1018                                            |e: &mut #name| match e { #name::#v_ident(v) => v.as_mut().map(|b| &mut **b), _ => None },
1019                                        )
1020                                    }
1021                                });
1022                            }
1023                            (WrapperKind::OptionRc, Some(inner_ty)) => {
1024                                tokens.extend(quote! {
1025                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1026                                        key_paths_core::KeyPaths::readable_enum(
1027                                            #name::#v_ident,
1028                                            |e: &#name| match e { #name::#v_ident(v) => v.as_ref().map(|r| &**r), _ => None }
1029                                        )
1030                                    }
1031                                });
1032                            }
1033                            (WrapperKind::OptionArc, Some(inner_ty)) => {
1034                                tokens.extend(quote! {
1035                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1036                                        key_paths_core::KeyPaths::readable_enum(
1037                                            #name::#v_ident,
1038                                            |e: &#name| match e { #name::#v_ident(v) => v.as_ref().map(|a| &**a), _ => None }
1039                                        )
1040                                    }
1041                                });
1042                            }
1043                            (WrapperKind::BoxOption, Some(inner_ty)) => {
1044                                tokens.extend(quote! {
1045                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #field_ty> {
1046                                        key_paths_core::KeyPaths::readable_enum(
1047                                            #name::#v_ident,
1048                                            |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None }
1049                                        )
1050                                    }
1051                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #field_ty> {
1052                                        key_paths_core::KeyPaths::writable_enum(
1053                                            #name::#v_ident,
1054                                            |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None },
1055                                            |e: &mut #name| match e { #name::#v_ident(v) => Some(&mut *v), _ => None },
1056                                        )
1057                                    }
1058                                    pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1059                                        key_paths_core::KeyPaths::readable_enum(
1060                                            #name::#v_ident,
1061                                            |e: &#name| match e { #name::#v_ident(v) => (*v).as_ref(), _ => None }
1062                                        )
1063                                    }
1064                                    pub fn #fw_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1065                                        key_paths_core::KeyPaths::writable_enum(
1066                                            #name::#v_ident,
1067                                            |e: &#name| match e { #name::#v_ident(v) => (*v).as_ref(), _ => None },
1068                                            |e: &mut #name| match e { #name::#v_ident(v) => (*v).as_mut(), _ => None },
1069                                        )
1070                                    }
1071                                });
1072                            }
1073                            (WrapperKind::RcOption, Some(inner_ty)) => {
1074                                tokens.extend(quote! {
1075                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #field_ty> {
1076                                        key_paths_core::KeyPaths::readable_enum(
1077                                            #name::#v_ident,
1078                                            |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None }
1079                                        )
1080                                    }
1081                                    pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1082                                        key_paths_core::KeyPaths::readable_enum(
1083                                            #name::#v_ident,
1084                                            |e: &#name| match e { #name::#v_ident(v) => (*v).as_ref(), _ => None }
1085                                        )
1086                                    }
1087                                });
1088                            }
1089                            (WrapperKind::ArcOption, Some(inner_ty)) => {
1090                                tokens.extend(quote! {
1091                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #field_ty> {
1092                                        key_paths_core::KeyPaths::readable_enum(
1093                                            #name::#v_ident,
1094                                            |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None }
1095                                        )
1096                                    }
1097                                    pub fn #fr_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1098                                        key_paths_core::KeyPaths::readable_enum(
1099                                            #name::#v_ident,
1100                                            |e: &#name| match e { #name::#v_ident(v) => (*v).as_ref(), _ => None }
1101                                        )
1102                                    }
1103                                });
1104                            }
1105                            (WrapperKind::VecOption, Some(inner_ty)) => {
1106                                tokens.extend(quote! {
1107                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1108                                        key_paths_core::KeyPaths::readable_enum(
1109                                            #name::#v_ident,
1110                                            |e: &#name| match e { #name::#v_ident(v) => v.first().and_then(|opt| opt.as_ref()), _ => None }
1111                                        )
1112                                    }
1113                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1114                                        key_paths_core::KeyPaths::writable_enum(
1115                                            #name::#v_ident,
1116                                            |e: &#name| match e { #name::#v_ident(v) => v.first().and_then(|opt| opt.as_ref()), _ => None },
1117                                            |e: &mut #name| match e { #name::#v_ident(v) => v.first_mut().and_then(|opt| opt.as_mut()), _ => None },
1118                                        )
1119                                    }
1120                                });
1121                            }
1122                            (WrapperKind::OptionVec, Some(inner_ty)) => {
1123                                tokens.extend(quote! {
1124                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1125                                        key_paths_core::KeyPaths::readable_enum(
1126                                            #name::#v_ident,
1127                                            |e: &#name| match e { #name::#v_ident(v) => v.as_ref().and_then(|vec| vec.first()), _ => None }
1128                                        )
1129                                    }
1130                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1131                                        key_paths_core::KeyPaths::writable_enum(
1132                                            #name::#v_ident,
1133                                            |e: &#name| match e { #name::#v_ident(v) => v.as_ref().and_then(|vec| vec.first()), _ => None },
1134                                            |e: &mut #name| match e { #name::#v_ident(v) => v.as_mut().and_then(|vec| vec.first_mut()), _ => None },
1135                                        )
1136                                    }
1137                                });
1138                            }
1139                            (WrapperKind::HashMapOption, Some(inner_ty)) => {
1140                                tokens.extend(quote! {
1141                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1142                                        key_paths_core::KeyPaths::readable_enum(
1143                                            #name::#v_ident,
1144                                            |e: &#name| match e { #name::#v_ident(v) => v.first().and_then(|(_, opt)| opt.as_ref()), _ => None }
1145                                        )
1146                                    }
1147                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1148                                        key_paths_core::KeyPaths::writable_enum(
1149                                            #name::#v_ident,
1150                                            |e: &#name| match e { #name::#v_ident(v) => v.first().and_then(|(_, opt)| opt.as_ref()), _ => None },
1151                                            |e: &mut #name| match e { #name::#v_ident(v) => v.first_mut().and_then(|(_, opt)| opt.as_mut()), _ => None },
1152                                        )
1153                                    }
1154                                });
1155                            }
1156                            (WrapperKind::OptionHashMap, Some(inner_ty)) => {
1157                                tokens.extend(quote! {
1158                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1159                                        key_paths_core::KeyPaths::readable_enum(
1160                                            #name::#v_ident,
1161                                            |e: &#name| match e { #name::#v_ident(v) => v.as_ref().and_then(|map| map.first().map(|(_, v)| v)), _ => None }
1162                                        )
1163                                    }
1164                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1165                                        key_paths_core::KeyPaths::writable_enum(
1166                                            #name::#v_ident,
1167                                            |e: &#name| match e { #name::#v_ident(v) => v.as_ref().and_then(|map| map.first().map(|(_, v)| v)), _ => None },
1168                                            |e: &mut #name| match e { #name::#v_ident(v) => v.as_mut().and_then(|map| map.first_mut().map(|(_, v)| v)), _ => None },
1169                                        )
1170                                    }
1171                                });
1172                            }
1173                            */
1174                            (WrapperKind::None, None) => {
1175                                let inner_ty = field_ty;
1176                                tokens.extend(quote! {
1177                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1178                                        key_paths_core::KeyPaths::readable_enum(
1179                                            #name::#v_ident,
1180                                            |e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None }
1181                                        )
1182                                    }
1183                                    pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1184                                        key_paths_core::KeyPaths::writable_enum(
1185                                            #name::#v_ident,
1186                                            |e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None },
1187                                            |e: &mut #name| match e { #name::#v_ident(v) => Some(v), _ => None },
1188                                        )
1189                                    }
1190                                });
1191                            }
1192                            _ => {
1193                                tokens.extend(quote! {
1194                                    pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #field_ty> {
1195                                        key_paths_core::KeyPaths::readable_enum(
1196                                            #name::#v_ident,
1197                                            |e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None }
1198                                        )
1199                                    }
1200                                });
1201                            }
1202                        }
1203                    }
1204                    _ => {
1205                        tokens.extend(quote! {
1206                            compile_error!("Casepaths derive supports only unit and single-field tuple variants");
1207                        });
1208                    }
1209                }
1210            }
1211            tokens
1212        }
1213        _ => quote! {
1214            compile_error!("Keypaths derive supports only structs and enums");
1215        },
1216    };
1217
1218    let expanded = quote! {
1219        impl #name {
1220            #methods
1221        }
1222    };
1223
1224    TokenStream::from(expanded)
1225}
1226
1227fn extract_wrapper_inner_type(ty: &Type) -> (WrapperKind, Option<Type>) {
1228    use syn::{GenericArgument, PathArguments};
1229    
1230    if let Type::Path(tp) = ty {
1231        if let Some(seg) = tp.path.segments.last() {
1232            let ident_str = seg.ident.to_string();
1233            
1234            if let PathArguments::AngleBracketed(ab) = &seg.arguments {
1235                let args: Vec<_> = ab.args.iter().collect();
1236                
1237                // Handle map types (HashMap, BTreeMap) - they have K, V parameters
1238                if ident_str == "HashMap" || ident_str == "BTreeMap" {
1239                    if let (Some(_key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
1240                        if let GenericArgument::Type(inner) = value_arg {
1241                            eprintln!("Detected {} type, extracting value type", ident_str);
1242                            return match ident_str.as_str() {
1243                                "HashMap" => (WrapperKind::HashMap, Some(inner.clone())),
1244                                "BTreeMap" => (WrapperKind::BTreeMap, Some(inner.clone())),
1245                                _ => (WrapperKind::None, None),
1246                            };
1247                        }
1248                    }
1249                }
1250                // Handle single-parameter container types
1251                else if let Some(arg) = args.get(0) {
1252                    if let GenericArgument::Type(inner) = arg {
1253                        // Check for nested containers first
1254                        let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
1255                        
1256                        // Handle nested combinations
1257                        match (ident_str.as_str(), inner_kind) {
1258                            ("Option", WrapperKind::Box) => {
1259                                return (WrapperKind::OptionBox, inner_inner);
1260                            }
1261                            ("Option", WrapperKind::Rc) => {
1262                                return (WrapperKind::OptionRc, inner_inner);
1263                            }
1264                            ("Option", WrapperKind::Arc) => {
1265                                return (WrapperKind::OptionArc, inner_inner);
1266                            }
1267                            ("Option", WrapperKind::Vec) => {
1268                                return (WrapperKind::OptionVec, inner_inner);
1269                            }
1270                            ("Option", WrapperKind::HashMap) => {
1271                                return (WrapperKind::OptionHashMap, inner_inner);
1272                            }
1273                            ("Box", WrapperKind::Option) => {
1274                                return (WrapperKind::BoxOption, inner_inner);
1275                            }
1276                            ("Rc", WrapperKind::Option) => {
1277                                return (WrapperKind::RcOption, inner_inner);
1278                            }
1279                            ("Arc", WrapperKind::Option) => {
1280                                return (WrapperKind::ArcOption, inner_inner);
1281                            }
1282                            ("Vec", WrapperKind::Option) => {
1283                                return (WrapperKind::VecOption, inner_inner);
1284                            }
1285                            ("HashMap", WrapperKind::Option) => {
1286                                return (WrapperKind::HashMapOption, inner_inner);
1287                            }
1288                            _ => {
1289                                // Handle single-level containers
1290                                return match ident_str.as_str() {
1291                                    "Option" => (WrapperKind::Option, Some(inner.clone())),
1292                                    "Box" => (WrapperKind::Box, Some(inner.clone())),
1293                                    "Rc" => (WrapperKind::Rc, Some(inner.clone())),
1294                                    "Arc" => (WrapperKind::Arc, Some(inner.clone())),
1295                                    "Vec" => (WrapperKind::Vec, Some(inner.clone())),
1296                                    "HashSet" => (WrapperKind::HashSet, Some(inner.clone())),
1297                                    "BTreeSet" => (WrapperKind::BTreeSet, Some(inner.clone())),
1298                                    "VecDeque" => (WrapperKind::VecDeque, Some(inner.clone())),
1299                                    "LinkedList" => (WrapperKind::LinkedList, Some(inner.clone())),
1300                                    "BinaryHeap" => (WrapperKind::BinaryHeap, Some(inner.clone())),
1301                                    _ => (WrapperKind::None, None),
1302                                };
1303                            }
1304                        }
1305                    }
1306                }
1307            }
1308        }
1309    }
1310    (WrapperKind::None, None)
1311}
1312
1313
1314fn to_snake_case(name: &str) -> String {
1315    let mut out = String::new();
1316    for (i, c) in name.chars().enumerate() {
1317        if c.is_uppercase() {
1318            if i != 0 {
1319                out.push('_');
1320            }
1321            out.push(c.to_ascii_lowercase());
1322        } else {
1323            out.push(c);
1324        }
1325    }
1326    out
1327}
1328
1329#[proc_macro_derive(Casepaths)]
1330pub fn derive_casepaths(input: TokenStream) -> TokenStream {
1331    let input = parse_macro_input!(input as DeriveInput);
1332    let name = input.ident;
1333
1334    let tokens = match input.data {
1335        Data::Enum(data_enum) => {
1336            let mut tokens = proc_macro2::TokenStream::new();
1337            for variant in data_enum.variants.iter() {
1338                let v_ident = &variant.ident;
1339                let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
1340                let r_fn = format_ident!("{}_case_r", snake);
1341                let w_fn = format_ident!("{}_case_w", snake);
1342
1343                match &variant.fields {
1344                    Fields::Unit => {
1345                        tokens.extend(quote! {
1346                            pub fn #r_fn() -> key_paths_core::KeyPaths<#name, ()> {
1347                                static UNIT: () = ();
1348                                key_paths_core::KeyPaths::readable_enum(
1349                                    |_| #name::#v_ident,
1350                                    |e: &#name| match e { #name::#v_ident => Some(&UNIT), _ => None }
1351                                )
1352                            }
1353                        });
1354                    }
1355                    Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
1356                        let inner_ty = &unnamed.unnamed.first().unwrap().ty;
1357                        tokens.extend(quote! {
1358                            pub fn #r_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1359                                key_paths_core::KeyPaths::readable_enum(
1360                                    #name::#v_ident,
1361                                    |e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None }
1362                                )
1363                            }
1364                            pub fn #w_fn() -> key_paths_core::KeyPaths<#name, #inner_ty> {
1365                                key_paths_core::KeyPaths::writable_enum(
1366                                    #name::#v_ident,
1367                                    |e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None },
1368                                    |e: &mut #name| match e { #name::#v_ident(v) => Some(v), _ => None },
1369                                )
1370                            }
1371                        });
1372                    }
1373                    _ => {
1374                        tokens.extend(quote! {
1375                            compile_error!("Casepaths derive supports only unit and single-field tuple variants");
1376                        });
1377                    }
1378                }
1379            }
1380            tokens
1381        }
1382        _ => quote! { compile_error!("Casepaths can only be derived for enums"); },
1383    };
1384
1385    let expanded = quote! {
1386        impl #name {
1387            #tokens
1388        }
1389    };
1390
1391    TokenStream::from(expanded)
1392}