Skip to main content

key_paths_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{Data, DeriveInput, Fields, Type, parse_macro_input, spanned::Spanned};
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    // Error handling containers
21    Result,
22    // Reference counting with weak references
23    Weak,
24    // String types (currently unused)
25    // String,
26    // OsString,
27    // PathBuf,
28    // Nested container support
29    OptionBox,
30    OptionRc,
31    OptionArc,
32    BoxOption,
33    RcOption,
34    ArcOption,
35    VecOption,
36    OptionVec,
37    HashMapOption,
38    OptionHashMap,
39    // Arc with synchronization primitives (default)
40    StdArcMutex,
41    StdArcRwLock,
42    OptionStdArcMutex,
43    OptionStdArcRwLock,
44    // Synchronization primitives default
45    StdMutex,
46    StdRwLock,
47    OptionStdMutex,
48    OptionStdRwLock,
49    // Synchronization primitives (parking_lot)
50    Mutex,
51    RwLock,
52    OptionMutex,
53    OptionRwLock,
54    // Synchronization primitives (tokio::sync - requires tokio feature)
55    TokioMutex,
56    TokioRwLock,
57    // parking_lot
58    ArcMutex,
59    ArcRwLock,
60    OptionArcMutex,
61    OptionArcRwLock,
62    // Arc with synchronization primitives (tokio::sync - requires tokio feature)
63    TokioArcMutex,
64    TokioArcRwLock,
65    OptionTokioArcMutex,
66    OptionTokioArcRwLock,
67    // Tagged types
68    Tagged,
69    // Clone-on-write (std::borrow::Cow)
70    Cow,
71    OptionCow,
72}
73
74/// Helper function to check if a type path includes std::sync module
75fn is_std_sync_type(path: &syn::Path) -> bool {
76    // Check for paths like std::sync::Mutex, std::sync::RwLock
77    let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
78    segments.len() >= 2
79        && segments.contains(&"std".to_string())
80        && segments.contains(&"sync".to_string())
81}
82
83/// Helper function to check if a type path includes tokio::sync module
84fn is_tokio_sync_type(path: &syn::Path) -> bool {
85    // Check for paths like tokio::sync::Mutex, tokio::sync::RwLock
86    let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
87    segments.len() >= 2
88        && segments.contains(&"tokio".to_string())
89        && segments.contains(&"sync".to_string())
90}
91
92fn extract_wrapper_inner_type(ty: &Type) -> (WrapperKind, Option<Type>) {
93    use syn::{GenericArgument, PathArguments};
94
95    if let Type::Path(tp) = ty {
96        // Check if this is explicitly a std::sync type
97        let is_std_sync = is_std_sync_type(&tp.path);
98        // Check if this is explicitly a tokio::sync type
99        let is_tokio_sync = is_tokio_sync_type(&tp.path);
100
101        if let Some(seg) = tp.path.segments.last() {
102            let ident_str = seg.ident.to_string();
103
104            if let PathArguments::AngleBracketed(ab) = &seg.arguments {
105                let args: Vec<_> = ab.args.iter().collect();
106
107                // Handle map types (HashMap, BTreeMap) - they have K, V parameters
108                if ident_str == "HashMap" || ident_str == "BTreeMap" {
109                    if let (Some(_key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
110                        if let GenericArgument::Type(inner) = value_arg {
111                            // Check for nested Option in map values
112                            let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
113                            match (ident_str.as_str(), inner_kind) {
114                                ("HashMap", WrapperKind::Option) => {
115                                    return (WrapperKind::HashMapOption, inner_inner);
116                                }
117                                _ => {
118                                    return match ident_str.as_str() {
119                                        "HashMap" => (WrapperKind::HashMap, Some(inner.clone())),
120                                        "BTreeMap" => (WrapperKind::BTreeMap, Some(inner.clone())),
121                                        _ => (WrapperKind::None, None),
122                                    };
123                                }
124                            }
125                        }
126                    }
127                }
128                // Handle Cow<'a, B> - has lifetime then type parameter
129                else if ident_str == "Cow" {
130                    if let Some(inner) = args.iter().find_map(|arg| {
131                        if let GenericArgument::Type(t) = arg {
132                            Some(t.clone())
133                        } else {
134                            None
135                        }
136                    }) {
137                        return (WrapperKind::Cow, Some(inner));
138                    }
139                }
140                // Handle single-parameter container types
141                else if let Some(arg) = args.get(0) {
142                    if let GenericArgument::Type(inner) = arg {
143                        // Check for nested containers first
144                        let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
145
146                        // Handle nested combinations
147                        match (ident_str.as_str(), inner_kind) {
148                            ("Option", WrapperKind::Box) => {
149                                return (WrapperKind::OptionBox, inner_inner);
150                            }
151                            ("Option", WrapperKind::Rc) => {
152                                return (WrapperKind::OptionRc, inner_inner);
153                            }
154                            ("Option", WrapperKind::Arc) => {
155                                return (WrapperKind::OptionArc, inner_inner);
156                            }
157                            ("Option", WrapperKind::Vec) => {
158                                return (WrapperKind::OptionVec, inner_inner);
159                            }
160                            ("Option", WrapperKind::HashMap) => {
161                                return (WrapperKind::OptionHashMap, inner_inner);
162                            }
163                            ("Option", WrapperKind::StdArcMutex) => {
164                                return (WrapperKind::OptionStdArcMutex, inner_inner);
165                            }
166                            ("Option", WrapperKind::StdArcRwLock) => {
167                                return (WrapperKind::OptionStdArcRwLock, inner_inner);
168                            }
169                            ("Option", WrapperKind::ArcMutex) => {
170                                return (WrapperKind::OptionArcMutex, inner_inner);
171                            }
172                            ("Option", WrapperKind::ArcRwLock) => {
173                                return (WrapperKind::OptionArcRwLock, inner_inner);
174                            }
175                            ("Option", WrapperKind::StdMutex) => {
176                                return (WrapperKind::OptionStdMutex, inner_inner);
177                            }
178                            ("Option", WrapperKind::StdRwLock) => {
179                                return (WrapperKind::OptionStdRwLock, inner_inner);
180                            }
181                            ("Option", WrapperKind::Mutex) => {
182                                return (WrapperKind::OptionMutex, inner_inner);
183                            }
184                            ("Option", WrapperKind::RwLock) => {
185                                return (WrapperKind::OptionRwLock, inner_inner);
186                            }
187                            ("Option", WrapperKind::TokioArcMutex) => {
188                                return (WrapperKind::OptionTokioArcMutex, inner_inner);
189                            }
190                            ("Option", WrapperKind::TokioArcRwLock) => {
191                                return (WrapperKind::OptionTokioArcRwLock, inner_inner);
192                            }
193                            ("Option", WrapperKind::Cow) => {
194                                return (WrapperKind::OptionCow, inner_inner);
195                            }
196                            ("Box", WrapperKind::Option) => {
197                                return (WrapperKind::BoxOption, inner_inner);
198                            }
199                            ("Rc", WrapperKind::Option) => {
200                                return (WrapperKind::RcOption, inner_inner);
201                            }
202                            ("Arc", WrapperKind::Option) => {
203                                return (WrapperKind::ArcOption, inner_inner);
204                            }
205                            ("Vec", WrapperKind::Option) => {
206                                return (WrapperKind::VecOption, inner_inner);
207                            }
208                            ("HashMap", WrapperKind::Option) => {
209                                return (WrapperKind::HashMapOption, inner_inner);
210                            }
211                            // std::sync variants (when inner is StdMutex/StdRwLock)
212                            ("Arc", WrapperKind::StdMutex) => {
213                                return (WrapperKind::StdArcMutex, inner_inner);
214                            }
215                            ("Arc", WrapperKind::StdRwLock) => {
216                                return (WrapperKind::StdArcRwLock, inner_inner);
217                            }
218                            // parking_lot variants (default - when inner is Mutex/RwLock without std::sync prefix)
219                            ("Arc", WrapperKind::Mutex) => {
220                                return (WrapperKind::ArcMutex, inner_inner);
221                            }
222                            ("Arc", WrapperKind::RwLock) => {
223                                return (WrapperKind::ArcRwLock, inner_inner);
224                            }
225                            // tokio::sync variants (when inner is TokioMutex/TokioRwLock)
226                            ("Arc", WrapperKind::TokioMutex) => {
227                                return (WrapperKind::TokioArcMutex, inner_inner);
228                            }
229                            ("Arc", WrapperKind::TokioRwLock) => {
230                                return (WrapperKind::TokioArcRwLock, inner_inner);
231                            }
232                            _ => {
233                                // Handle single-level containers
234                                // For Mutex and RwLock:
235                                // - If path contains std::sync, it's std::sync (StdMutex/StdRwLock)
236                                // - Otherwise, default to parking_lot (Mutex/RwLock)
237                                return match ident_str.as_str() {
238                                    "Option" => (WrapperKind::Option, Some(inner.clone())),
239                                    "Box" => (WrapperKind::Box, Some(inner.clone())),
240                                    "Rc" => (WrapperKind::Rc, Some(inner.clone())),
241                                    "Arc" => (WrapperKind::Arc, Some(inner.clone())),
242                                    "Vec" => (WrapperKind::Vec, Some(inner.clone())),
243                                    "HashSet" => (WrapperKind::HashSet, Some(inner.clone())),
244                                    "BTreeSet" => (WrapperKind::BTreeSet, Some(inner.clone())),
245                                    "VecDeque" => (WrapperKind::VecDeque, Some(inner.clone())),
246                                    "LinkedList" => (WrapperKind::LinkedList, Some(inner.clone())),
247                                    "BinaryHeap" => (WrapperKind::BinaryHeap, Some(inner.clone())),
248                                    "Result" => (WrapperKind::Result, Some(inner.clone())),
249                                    // For std::sync::Mutex and std::sync::RwLock, use Std variants
250                                    "Mutex" if is_std_sync => {
251                                        (WrapperKind::StdMutex, Some(inner.clone()))
252                                    }
253                                    "RwLock" if is_std_sync => {
254                                        (WrapperKind::StdRwLock, Some(inner.clone()))
255                                    }
256                                    // For tokio::sync::Mutex and tokio::sync::RwLock, use Tokio variants
257                                    "Mutex" if is_tokio_sync => {
258                                        (WrapperKind::TokioMutex, Some(inner.clone()))
259                                    }
260                                    "RwLock" if is_tokio_sync => {
261                                        (WrapperKind::TokioRwLock, Some(inner.clone()))
262                                    }
263                                    // Default: parking_lot (no std::sync or tokio::sync prefix)
264                                    "Mutex" => (WrapperKind::Mutex, Some(inner.clone())),
265                                    "RwLock" => (WrapperKind::RwLock, Some(inner.clone())),
266                                    "Weak" => (WrapperKind::Weak, Some(inner.clone())),
267                                    "Tagged" => (WrapperKind::Tagged, Some(inner.clone())),
268                                    "Cow" => (WrapperKind::Cow, Some(inner.clone())),
269                                    _ => (WrapperKind::None, None),
270                                };
271                            }
272                        }
273                    }
274                }
275            }
276        }
277    }
278    (WrapperKind::None, None)
279}
280
281/// For HashMap<K,V> or BTreeMap<K,V>, returns Some((key_ty, value_ty)).
282fn extract_map_key_value(ty: &Type) -> Option<(Type, Type)> {
283    use syn::{GenericArgument, PathArguments};
284
285    if let Type::Path(tp) = ty {
286        if let Some(seg) = tp.path.segments.last() {
287            let ident_str = seg.ident.to_string();
288            if ident_str == "HashMap" || ident_str == "BTreeMap" {
289                if let PathArguments::AngleBracketed(ab) = &seg.arguments {
290                    let args: Vec<_> = ab.args.iter().collect();
291                    if let (Some(key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
292                        if let (GenericArgument::Type(key_ty), GenericArgument::Type(value_ty)) =
293                            (key_arg, value_arg)
294                        {
295                            return Some((key_ty.clone(), value_ty.clone()));
296                        }
297                    }
298                }
299            }
300        }
301    }
302    None
303}
304
305fn to_snake_case(name: &str) -> String {
306    let mut out = String::new();
307    for (i, c) in name.chars().enumerate() {
308        if c.is_uppercase() {
309            if i != 0 {
310                out.push('_');
311            }
312            out.push(c.to_ascii_lowercase());
313        } else {
314            out.push(c);
315        }
316    }
317    out
318}
319
320/// Derive macro for generating simple keypath methods.
321/// 
322/// Generates one method per field: `StructName::field_name()` that returns a `Kp`.
323/// Intelligently handles wrapper types (Option, Vec, Box, Arc, etc.) to generate appropriate keypaths.
324/// 
325/// # Example
326/// 
327/// ```ignore
328/// #[derive(Kp)]
329/// struct Person {
330///     name: String,
331///     age: i32,
332///     email: Option<String>,
333///     addresses: Vec<String>,
334/// }
335/// 
336/// // Generates:
337/// // impl Person {
338/// //     pub fn name() -> Kp<...> { ... }
339/// //     pub fn age() -> Kp<...> { ... }
340/// //     pub fn email() -> Kp<...> { ... } // unwraps Option
341/// //     pub fn addresses() -> Kp<...> { ... } // accesses first element
342/// // }
343/// ```
344#[proc_macro_derive(Kp)]
345pub fn derive_keypaths(input: TokenStream) -> TokenStream {
346    let input = parse_macro_input!(input as DeriveInput);
347    let name = &input.ident;
348    let input_span = input.span();
349
350    let methods = match input.data {
351        Data::Struct(data_struct) => match data_struct.fields {
352            Fields::Named(fields_named) => {
353                let mut tokens = proc_macro2::TokenStream::new();
354
355                // Generate identity methods for the struct
356                tokens.extend(quote! {
357                    /// Returns a generic identity keypath for this type
358                    #[inline]
359                    pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
360                        #name,
361                        #name,
362                        Root,
363                        Root,
364                        MutRoot,
365                        MutRoot,
366                        fn(Root) -> Option<Root>,
367                        fn(MutRoot) -> Option<MutRoot>,
368                    >
369                    where
370                        Root: std::borrow::Borrow<#name>,
371                        MutRoot: std::borrow::BorrowMut<#name>,
372                    {
373                        rust_key_paths::Kp::new(
374                            |r: Root| Some(r),
375                            |r: MutRoot| Some(r)
376                        )
377                    }
378
379                    /// Returns a simple identity keypath for this type
380                    #[inline]
381                    pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
382                        rust_key_paths::Kp::new(
383                            |r: &#name| Some(r),
384                            |r: &mut #name| Some(r)
385                        )
386                    }
387                });
388                
389                for field in fields_named.named.iter() {
390                    let field_ident = field.ident.as_ref().unwrap();
391                    let ty = &field.ty;
392                    // Centralized keypath method names – change here to adjust for all types
393                    let kp_fn = format_ident!("{}", field_ident);
394                    let kp_at_fn = format_ident!("{}_at", field_ident);
395
396                    let (kind, inner_ty) = extract_wrapper_inner_type(ty);
397
398                    match (kind, inner_ty.clone()) {
399                        (WrapperKind::Option, Some(inner_ty)) => {
400                            // For Option<T>, unwrap and access inner type
401                            tokens.extend(quote! {
402                                #[inline]
403                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
404                                    rust_key_paths::Kp::new(
405                                        |root: &#name| root.#field_ident.as_ref(),
406                                        |root: &mut #name| root.#field_ident.as_mut(),
407                                    )
408                                }
409                            });
410                        }
411                        (WrapperKind::Vec, Some(inner_ty)) => {
412                            tokens.extend(quote! {
413                                #[inline]
414                                    #[inline]
415                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
416                                    rust_key_paths::Kp::new(
417                                        |root: &#name| Some(&root.#field_ident),
418                                        |root: &mut #name| Some(&mut root.#field_ident),
419                                    )
420                                }
421                                #[inline]
422                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
423                                    rust_key_paths::Kp::new(
424                                        Box::new(move |root: &#name| root.#field_ident.get(index)),
425                                        Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
426                                    )
427                                }
428                            });
429                        }
430                        (WrapperKind::HashMap, Some(inner_ty)) => {
431                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
432                                tokens.extend(quote! {
433                                    #[inline]
434                                    #[inline]
435                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
436                                        rust_key_paths::Kp::new(
437                                            |root: &#name| Some(&root.#field_ident),
438                                            |root: &mut #name| Some(&mut root.#field_ident),
439                                        )
440                                    }
441                                    #[inline]
442                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
443                                    where
444                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
445                                    {
446                                        let key2 = key.clone();
447                                        rust_key_paths::Kp::new(
448                                            Box::new(move |root: &#name| root.#field_ident.get(&key)),
449                                            Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
450                                        )
451                                    }
452                                });
453                            } else {
454                                tokens.extend(quote! {
455                                    #[inline]
456                                    #[inline]
457                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
458                                        rust_key_paths::Kp::new(
459                                            |root: &#name| Some(&root.#field_ident),
460                                            |root: &mut #name| Some(&mut root.#field_ident),
461                                        )
462                                    }
463                                });
464                            }
465                        }
466                        (WrapperKind::BTreeMap, Some(inner_ty)) => {
467                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
468                                tokens.extend(quote! {
469                                    #[inline]
470                                    #[inline]
471                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
472                                        rust_key_paths::Kp::new(
473                                            |root: &#name| Some(&root.#field_ident),
474                                            |root: &mut #name| Some(&mut root.#field_ident),
475                                        )
476                                    }
477                                    #[inline]
478                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
479                                    where
480                                        #key_ty: Clone + Ord + 'static,
481                                    {
482                                        let key2 = key.clone();
483                                        rust_key_paths::Kp::new(
484                                            Box::new(move |root: &#name| root.#field_ident.get(&key)),
485                                            Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
486                                        )
487                                    }
488                                });
489                            } else {
490                                tokens.extend(quote! {
491                                    #[inline]
492                                    #[inline]
493                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
494                                        rust_key_paths::Kp::new(
495                                            |root: &#name| Some(&root.#field_ident),
496                                            |root: &mut #name| Some(&mut root.#field_ident),
497                                        )
498                                    }
499                                });
500                            }
501                        }
502                        (WrapperKind::Box, Some(inner_ty)) => {
503                            // For Box<T>, deref to inner type (returns &T / &mut T, not &Box<T>)
504                            // Matches reference: WritableKeyPath::new(|s: &mut #name| &mut *s.#field_ident)
505                            tokens.extend(quote! {
506                                #[inline]
507                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
508                                    rust_key_paths::Kp::new(
509                                        |root: &#name| Some(&*root.#field_ident),
510                                        |root: &mut #name| Some(&mut *root.#field_ident),
511                                    )
512                                }
513                            });
514                        }
515                        (WrapperKind::Rc, Some(inner_ty)) => {
516                            // For Rc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
517                            tokens.extend(quote! {
518                                #[inline]
519                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
520                                    rust_key_paths::Kp::new(
521                                        |root: &#name| Some(root.#field_ident.as_ref()),
522                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#field_ident),
523                                    )
524                                }
525                            });
526                        }
527                        (WrapperKind::Arc, Some(inner_ty)) => {
528                            // For Arc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
529                            tokens.extend(quote! {
530                                #[inline]
531                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
532                                    rust_key_paths::Kp::new(
533                                        |root: &#name| Some(root.#field_ident.as_ref()),
534                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#field_ident),
535                                    )
536                                }
537                            });
538                        }
539                        (WrapperKind::Cow, Some(inner_ty)) => {
540                            // For Cow<'_, B>, deref to inner type (as_ref/to_mut)
541                            tokens.extend(quote! {
542                                #[inline]
543                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
544                                    rust_key_paths::Kp::new(
545                                        |root: &#name| Some(root.#field_ident.as_ref()),
546                                        |root: &mut #name| Some(root.#field_ident.to_mut()),
547                                    )
548                                }
549                            });
550                        }
551                        
552                        (WrapperKind::OptionCow, Some(inner_ty)) => {
553                            // For Option<Cow<'_, B>>
554                            tokens.extend(quote! {
555                                #[inline]
556                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
557                                    rust_key_paths::Kp::new(
558                                        |root: &#name| root.#field_ident.as_ref().map(|c| c.as_ref()),
559                                        |root: &mut #name| root.#field_ident.as_mut().map(|c| c.to_mut()),
560                                    )
561                                }
562                            });
563                        }
564                        (WrapperKind::HashSet, Some(_inner_ty)) => {
565                            tokens.extend(quote! {
566                                #[inline]
567                                    #[inline]
568                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
569                                    rust_key_paths::Kp::new(
570                                        |root: &#name| Some(&root.#field_ident),
571                                        |root: &mut #name| Some(&mut root.#field_ident),
572                                    )
573                                }
574                            });
575                        }
576                        (WrapperKind::BTreeSet, Some(_inner_ty)) => {
577                            tokens.extend(quote! {
578                                #[inline]
579                                    #[inline]
580                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
581                                    rust_key_paths::Kp::new(
582                                        |root: &#name| Some(&root.#field_ident),
583                                        |root: &mut #name| Some(&mut root.#field_ident),
584                                    )
585                                }
586                            });
587                        }
588                        (WrapperKind::VecDeque, Some(inner_ty)) => {
589                            tokens.extend(quote! {
590                                #[inline]
591                                    #[inline]
592                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
593                                    rust_key_paths::Kp::new(
594                                        |root: &#name| Some(&root.#field_ident),
595                                        |root: &mut #name| Some(&mut root.#field_ident),
596                                    )
597                                }
598                                #[inline]
599                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
600                                    rust_key_paths::Kp::new(
601                                        Box::new(move |root: &#name| root.#field_ident.get(index)),
602                                        Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
603                                    )
604                                }
605                            });
606                        }
607                        (WrapperKind::LinkedList, Some(_inner_ty)) => {
608                            tokens.extend(quote! {
609                                #[inline]
610                                    #[inline]
611                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
612                                    rust_key_paths::Kp::new(
613                                        |root: &#name| Some(&root.#field_ident),
614                                        |root: &mut #name| Some(&mut root.#field_ident),
615                                    )
616                                }
617                            });
618                        }
619                        (WrapperKind::BinaryHeap, Some(_inner_ty)) => {
620                            tokens.extend(quote! {
621                                #[inline]
622                                    #[inline]
623                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
624                                    rust_key_paths::Kp::new(
625                                        |root: &#name| Some(&root.#field_ident),
626                                        |root: &mut #name| Some(&mut root.#field_ident),
627                                    )
628                                }
629                            });
630                        }
631                        (WrapperKind::Result, Some(inner_ty)) => {
632                            // For Result<T, E>, access Ok value
633                            tokens.extend(quote! {
634                                #[inline]
635                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
636                                    rust_key_paths::Kp::new(
637                                        |root: &#name| root.#field_ident.as_ref().ok(),
638                                        |root: &mut #name| root.#field_ident.as_mut().ok(),
639                                    )
640                                }
641                            });
642                        }
643                        (WrapperKind::StdArcMutex, Some(inner_ty)) => {
644                            // For Arc<std::sync::Mutex<T>>
645                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
646                            tokens.extend(quote! {
647                                #[inline]
648                                    #[inline]
649                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
650                                    rust_key_paths::Kp::new(
651                                        |root: &#name| Some(&root.#field_ident),
652                                        |root: &mut #name| Some(&mut root.#field_ident),
653                                    )
654                                }
655                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #ty, #inner_ty> {
656                                    rust_key_paths::lock::LockKp::new(
657                                        rust_key_paths::Kp::new(
658                                            |root: &#name| Some(&root.#field_ident),
659                                            |root: &mut #name| Some(&mut root.#field_ident),
660                                        ),
661                                        rust_key_paths::lock::ArcMutexAccess::new(),
662                                        rust_key_paths::Kp::new(
663                                            |v: &#inner_ty| Some(v),
664                                            |v: &mut #inner_ty| Some(v),
665                                        ),
666                                    )
667                                }
668                            });
669                        }
670                        (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
671                            // For Arc<std::sync::RwLock<T>>
672                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
673                            tokens.extend(quote! {
674                                #[inline]
675                                    #[inline]
676                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
677                                    rust_key_paths::Kp::new(
678                                        |root: &#name| Some(&root.#field_ident),
679                                        |root: &mut #name| Some(&mut root.#field_ident),
680                                    )
681                                }
682                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #ty, #inner_ty> {
683                                    rust_key_paths::lock::LockKp::new(
684                                        rust_key_paths::Kp::new(
685                                            |root: &#name| Some(&root.#field_ident),
686                                            |root: &mut #name| Some(&mut root.#field_ident),
687                                        ),
688                                        rust_key_paths::lock::ArcRwLockAccess::new(),
689                                        rust_key_paths::Kp::new(
690                                            |v: &#inner_ty| Some(v),
691                                            |v: &mut #inner_ty| Some(v),
692                                        ),
693                                    )
694                                }
695                            });
696                        }
697                        (WrapperKind::ArcRwLock, Some(inner_ty)) => {
698                            // For Arc<parking_lot::RwLock<T>> (requires rust-key-paths "parking_lot" feature)
699                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
700                            tokens.extend(quote! {
701                                #[inline]
702                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
703                                    rust_key_paths::Kp::new(
704                                        |root: &#name| Some(&root.#field_ident),
705                                        |root: &mut #name| Some(&mut root.#field_ident),
706                                    )
707                                }
708                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #ty, #inner_ty> {
709                                    rust_key_paths::lock::LockKp::new(
710                                        rust_key_paths::Kp::new(
711                                            |root: &#name| Some(&root.#field_ident),
712                                            |root: &mut #name| Some(&mut root.#field_ident),
713                                        ),
714                                        rust_key_paths::lock::ParkingLotRwLockAccess::new(),
715                                        rust_key_paths::Kp::new(
716                                            |v: &#inner_ty| Some(v),
717                                            |v: &mut #inner_ty| Some(v),
718                                        ),
719                                    )
720                                }
721                            });
722                        }
723                        (WrapperKind::ArcMutex, Some(inner_ty)) => {
724                            // For Arc<parking_lot::Mutex<T>> (requires rust-key-paths "parking_lot" feature)
725                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
726                            tokens.extend(quote! {
727                                #[inline]
728                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
729                                    rust_key_paths::Kp::new(
730                                        |root: &#name| Some(&root.#field_ident),
731                                        |root: &mut #name| Some(&mut root.#field_ident),
732                                    )
733                                }
734                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #ty, #inner_ty> {
735                                    rust_key_paths::lock::LockKp::new(
736                                        rust_key_paths::Kp::new(
737                                            |root: &#name| Some(&root.#field_ident),
738                                            |root: &mut #name| Some(&mut root.#field_ident),
739                                        ),
740                                        rust_key_paths::lock::ParkingLotMutexAccess::new(),
741                                        rust_key_paths::Kp::new(
742                                            |v: &#inner_ty| Some(v),
743                                            |v: &mut #inner_ty| Some(v),
744                                        ),
745                                    )
746                                }
747                            });
748                        }
749                        (WrapperKind::Mutex, Some(_inner_ty))
750                        | (WrapperKind::StdMutex, Some(_inner_ty)) => {
751                            // For Mutex<T>, return keypath to container
752                            tokens.extend(quote! {
753                                #[inline]
754                                    #[inline]
755                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
756                                    rust_key_paths::Kp::new(
757                                        |root: &#name| Some(&root.#field_ident),
758                                        |root: &mut #name| Some(&mut root.#field_ident),
759                                    )
760                                }
761                            });
762                        }
763                        (WrapperKind::RwLock, Some(_inner_ty))
764                        | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
765                            // For RwLock<T>, return keypath to container
766                            tokens.extend(quote! {
767                                #[inline]
768                                    #[inline]
769                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
770                                    rust_key_paths::Kp::new(
771                                        |root: &#name| Some(&root.#field_ident),
772                                        |root: &mut #name| Some(&mut root.#field_ident),
773                                    )
774                                }
775                            });
776                        }
777                        (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
778                            let kp_async_fn = format_ident!("{}_async", field_ident);
779                            tokens.extend(quote! {
780                                #[inline]
781                                    #[inline]
782                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
783                                    rust_key_paths::Kp::new(
784                                        |root: &#name| Some(&root.#field_ident),
785                                        |root: &mut #name| Some(&mut root.#field_ident),
786                                    )
787                                }
788                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
789                                    rust_key_paths::async_lock::AsyncLockKp::new(
790                                        rust_key_paths::Kp::new(
791                                            |root: &#name| Some(&root.#field_ident),
792                                            |root: &mut #name| Some(&mut root.#field_ident),
793                                        ),
794                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
795                                        rust_key_paths::Kp::new(
796                                            |v: &#inner_ty| Some(v),
797                                            |v: &mut #inner_ty| Some(v),
798                                        ),
799                                    )
800                                }
801                            });
802                        }
803                        (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
804                            let kp_async_fn = format_ident!("{}_async", field_ident);
805                            tokens.extend(quote! {
806                                #[inline]
807                                    #[inline]
808                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
809                                    rust_key_paths::Kp::new(
810                                        |root: &#name| Some(&root.#field_ident),
811                                        |root: &mut #name| Some(&mut root.#field_ident),
812                                    )
813                                }
814                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
815                                    rust_key_paths::async_lock::AsyncLockKp::new(
816                                        rust_key_paths::Kp::new(
817                                            |root: &#name| Some(&root.#field_ident),
818                                            |root: &mut #name| Some(&mut root.#field_ident),
819                                        ),
820                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
821                                        rust_key_paths::Kp::new(
822                                            |v: &#inner_ty| Some(v),
823                                            |v: &mut #inner_ty| Some(v),
824                                        ),
825                                    )
826                                }
827                            });
828                        }
829                        (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
830                            let kp_async_fn = format_ident!("{}_async", field_ident);
831                            tokens.extend(quote! {
832                                #[inline]
833                                    #[inline]
834                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
835                                    rust_key_paths::Kp::new(
836                                        |root: &#name| Some(&root.#field_ident),
837                                        |root: &mut #name| Some(&mut root.#field_ident),
838                                    )
839                                }
840                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
841                                    rust_key_paths::async_lock::AsyncLockKp::new(
842                                        rust_key_paths::Kp::new(
843                                            |root: &#name| root.#field_ident.as_ref(),
844                                            |root: &mut #name| root.#field_ident.as_mut(),
845                                        ),
846                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
847                                        rust_key_paths::Kp::new(
848                                            |v: &#inner_ty| Some(v),
849                                            |v: &mut #inner_ty| Some(v),
850                                        ),
851                                    )
852                                }
853                            });
854                        }
855                        (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
856                            let kp_async_fn = format_ident!("{}_async", field_ident);
857                            tokens.extend(quote! {
858                                #[inline]
859                                    #[inline]
860                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
861                                    rust_key_paths::Kp::new(
862                                        |root: &#name| Some(&root.#field_ident),
863                                        |root: &mut #name| Some(&mut root.#field_ident),
864                                    )
865                                }
866                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
867                                    rust_key_paths::async_lock::AsyncLockKp::new(
868                                        rust_key_paths::Kp::new(
869                                            |root: &#name| root.#field_ident.as_ref(),
870                                            |root: &mut #name| root.#field_ident.as_mut(),
871                                        ),
872                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
873                                        rust_key_paths::Kp::new(
874                                            |v: &#inner_ty| Some(v),
875                                            |v: &mut #inner_ty| Some(v),
876                                        ),
877                                    )
878                                }
879                            });
880                        }
881                        (WrapperKind::OptionStdArcMutex, Some(inner_ty))
882                        | (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
883                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
884                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
885                            tokens.extend(quote! {
886                                #[inline]
887                                    #[inline]
888                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
889                                    rust_key_paths::Kp::new(
890                                        |root: &#name| Some(&root.#field_ident),
891                                        |root: &mut #name| Some(&mut root.#field_ident),
892                                    )
893                                }
894                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
895                                    rust_key_paths::Kp::new(
896                                        |root: &#name| root.#field_ident.as_ref(),
897                                        |root: &mut #name| root.#field_ident.as_mut(),
898                                    )
899                                }
900                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
901                                    rust_key_paths::lock::LockKp::new(
902                                        rust_key_paths::Kp::new(
903                                            |root: &#name| root.#field_ident.as_ref(),
904                                            |root: &mut #name| root.#field_ident.as_mut(),
905                                        ),
906                                        rust_key_paths::lock::ArcMutexAccess::new(),
907                                        rust_key_paths::Kp::new(
908                                            |v: &#inner_ty| Some(v),
909                                            |v: &mut #inner_ty| Some(v),
910                                        ),
911                                    )
912                                }
913                            });
914                        }
915                        (WrapperKind::OptionStdArcRwLock, Some(inner_ty))
916                        | (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
917                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
918                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
919                            tokens.extend(quote! {
920                                #[inline]
921                                    #[inline]
922                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
923                                    rust_key_paths::Kp::new(
924                                        |root: &#name| Some(&root.#field_ident),
925                                        |root: &mut #name| Some(&mut root.#field_ident),
926                                    )
927                                }
928                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
929                                    rust_key_paths::Kp::new(
930                                        |root: &#name| root.#field_ident.as_ref(),
931                                        |root: &mut #name| root.#field_ident.as_mut(),
932                                    )
933                                }
934                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
935                                    rust_key_paths::lock::LockKp::new(
936                                        rust_key_paths::Kp::new(
937                                            |root: &#name| root.#field_ident.as_ref(),
938                                            |root: &mut #name| root.#field_ident.as_mut(),
939                                        ),
940                                        rust_key_paths::lock::ArcRwLockAccess::new(),
941                                        rust_key_paths::Kp::new(
942                                            |v: &#inner_ty| Some(v),
943                                            |v: &mut #inner_ty| Some(v),
944                                        ),
945                                    )
946                                }
947                            });
948                        }
949                        (WrapperKind::OptionStdMutex, Some(inner_ty))
950                        | (WrapperKind::OptionMutex, Some(inner_ty)) => {
951                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
952                            tokens.extend(quote! {
953                                #[inline]
954                                    #[inline]
955                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
956                                    rust_key_paths::Kp::new(
957                                        |root: &#name| Some(&root.#field_ident),
958                                        |root: &mut #name| Some(&mut root.#field_ident),
959                                    )
960                                }
961                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
962                                    rust_key_paths::Kp::new(
963                                        |root: &#name| root.#field_ident.as_ref(),
964                                        |root: &mut #name| root.#field_ident.as_mut(),
965                                    )
966                                }
967                            });
968                        }
969                        (WrapperKind::OptionStdRwLock, Some(inner_ty))
970                        | (WrapperKind::OptionRwLock, Some(inner_ty)) => {
971                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
972                            tokens.extend(quote! {
973                                #[inline]
974                                    #[inline]
975                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
976                                    rust_key_paths::Kp::new(
977                                        |root: &#name| Some(&root.#field_ident),
978                                        |root: &mut #name| Some(&mut root.#field_ident),
979                                    )
980                                }
981                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
982                                    rust_key_paths::Kp::new(
983                                        |root: &#name| root.#field_ident.as_ref(),
984                                        |root: &mut #name| root.#field_ident.as_mut(),
985                                    )
986                                }
987                            });
988                        }
989                        (WrapperKind::Weak, Some(_inner_ty)) => {
990                            // For Weak<T>, return keypath to container
991                            tokens.extend(quote! {
992                                #[inline]
993                                    #[inline]
994                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
995                                    rust_key_paths::Kp::new(
996                                        |root: &#name| Some(&root.#field_ident),
997                                        |_root: &mut #name| None, // Weak doesn't support mutable access
998                                    )
999                                }
1000                            });
1001                        }
1002                        (WrapperKind::None, None) => {
1003                            // For basic types, direct access
1004                            tokens.extend(quote! {
1005                                #[inline]
1006                                    #[inline]
1007                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1008                                    rust_key_paths::Kp::new(
1009                                        |root: &#name| Some(&root.#field_ident),
1010                                        |root: &mut #name| Some(&mut root.#field_ident),
1011                                    )
1012                                }
1013                            });
1014                        }
1015                        _ => {
1016                            // For unknown/complex nested types, return keypath to field itself
1017                            tokens.extend(quote! {
1018                                #[inline]
1019                                    #[inline]
1020                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1021                            rust_key_paths::Kp::new(
1022                                |root: &#name| Some(&root.#field_ident),
1023                                |root: &mut #name| Some(&mut root.#field_ident),
1024                            )
1025                        }
1026                            });
1027                        }
1028                    }
1029                }
1030                
1031                tokens
1032            }
1033            Fields::Unnamed(unnamed) => {
1034                let mut tokens = proc_macro2::TokenStream::new();
1035
1036                // Generate identity methods for the tuple struct
1037                tokens.extend(quote! {
1038                    /// Returns a generic identity keypath for this type
1039                    #[inline]
1040                    pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
1041                        #name,
1042                        #name,
1043                        Root,
1044                        Root,
1045                        MutRoot,
1046                        MutRoot,
1047                        fn(Root) -> Option<Root>,
1048                        fn(MutRoot) -> Option<MutRoot>,
1049                    >
1050                    where
1051                        Root: std::borrow::Borrow<#name>,
1052                        MutRoot: std::borrow::BorrowMut<#name>,
1053                    {
1054                        rust_key_paths::Kp::new(
1055                            |r: Root| Some(r),
1056                            |r: MutRoot| Some(r)
1057                        )
1058                    }
1059
1060                    /// Returns a simple identity keypath for this type
1061                    #[inline]
1062                    pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
1063                        rust_key_paths::Kp::new(
1064                            |r: &#name| Some(r),
1065                            |r: &mut #name| Some(r)
1066                        )
1067                    }
1068                });
1069
1070                for (idx, field) in unnamed.unnamed.iter().enumerate() {
1071                    let idx_lit = syn::Index::from(idx);
1072                    let ty = &field.ty;
1073                    // Centralized keypath method names for tuple fields – change here to adjust for all types
1074                    let kp_fn = format_ident!("f{}", idx);
1075                    let kp_at_fn = format_ident!("f{}_at", idx);
1076
1077                    let (kind, inner_ty) = extract_wrapper_inner_type(ty);
1078
1079                    match (kind, inner_ty.clone()) {
1080                        (WrapperKind::Option, Some(inner_ty)) => {
1081                            tokens.extend(quote! {
1082                                #[inline]
1083                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1084                                    rust_key_paths::Kp::new(
1085                                        |root: &#name| root.#idx_lit.as_ref(),
1086                                        |root: &mut #name| root.#idx_lit.as_mut(),
1087                                    )
1088                                }
1089                            });
1090                        }
1091                        (WrapperKind::Vec, Some(inner_ty)) => {
1092                            tokens.extend(quote! {
1093                                #[inline]
1094                                    #[inline]
1095                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1096                                    rust_key_paths::Kp::new(
1097                                        |root: &#name| Some(&root.#idx_lit),
1098                                        |root: &mut #name| Some(&mut root.#idx_lit),
1099                                    )
1100                                }
1101                                #[inline]
1102                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1103                                    rust_key_paths::Kp::new(
1104                                        Box::new(move |root: &#name| root.#idx_lit.get(index)),
1105                                        Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
1106                                    )
1107                                }
1108                            });
1109                        }
1110                        (WrapperKind::HashMap, Some(inner_ty)) => {
1111                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
1112                                tokens.extend(quote! {
1113                                    #[inline]
1114                                    #[inline]
1115                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1116                                        rust_key_paths::Kp::new(
1117                                            |root: &#name| Some(&root.#idx_lit),
1118                                            |root: &mut #name| Some(&mut root.#idx_lit),
1119                                        )
1120                                    }
1121                                    #[inline]
1122                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1123                                    where
1124                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
1125                                    {
1126                                        let key2 = key.clone();
1127                                        rust_key_paths::Kp::new(
1128                                            Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1129                                            Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
1130                                        )
1131                                    }
1132                                });
1133                            } else {
1134                                tokens.extend(quote! {
1135                                    #[inline]
1136                                    #[inline]
1137                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1138                                        rust_key_paths::Kp::new(
1139                                            |root: &#name| Some(&root.#idx_lit),
1140                                            |root: &mut #name| Some(&mut root.#idx_lit),
1141                                        )
1142                                    }
1143                                });
1144                            }
1145                        }
1146                        (WrapperKind::BTreeMap, Some(inner_ty)) => {
1147                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
1148                                tokens.extend(quote! {
1149                                    #[inline]
1150                                    #[inline]
1151                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1152                                        rust_key_paths::Kp::new(
1153                                            |root: &#name| Some(&root.#idx_lit),
1154                                            |root: &mut #name| Some(&mut root.#idx_lit),
1155                                        )
1156                                    }
1157                                    #[inline]
1158                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1159                                    where
1160                                        #key_ty: Clone + Ord + 'static,
1161                                    {
1162                                        let key2 = key.clone();
1163                                        rust_key_paths::Kp::new(
1164                                            Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1165                                            Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
1166                                        )
1167                                    }
1168                                });
1169                            } else {
1170                                tokens.extend(quote! {
1171                                    #[inline]
1172                                    #[inline]
1173                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1174                                        rust_key_paths::Kp::new(
1175                                            |root: &#name| Some(&root.#idx_lit),
1176                                            |root: &mut #name| Some(&mut root.#idx_lit),
1177                                        )
1178                                    }
1179                                });
1180                            }
1181                        }
1182                        (WrapperKind::Box, Some(inner_ty)) => {
1183                            // Box: deref to inner (returns &T / &mut T)
1184                            tokens.extend(quote! {
1185                                #[inline]
1186                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1187                                    rust_key_paths::Kp::new(
1188                                        |root: &#name| Some(&*root.#idx_lit),
1189                                        |root: &mut #name| Some(&mut *root.#idx_lit),
1190                                    )
1191                                }
1192                            });
1193                        }
1194                        (WrapperKind::Rc, Some(inner_ty)) => {
1195                            tokens.extend(quote! {
1196                                #[inline]
1197                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1198                                    rust_key_paths::Kp::new(
1199                                        |root: &#name| Some(root.#idx_lit.as_ref()),
1200                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#idx_lit),
1201                                    )
1202                                }
1203                            });
1204                        }
1205                        (WrapperKind::Arc, Some(inner_ty)) => {
1206                            tokens.extend(quote! {
1207                                #[inline]
1208                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1209                                    rust_key_paths::Kp::new(
1210                                        |root: &#name| Some(root.#idx_lit.as_ref()),
1211                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#idx_lit),
1212                                    )
1213                                }
1214                            });
1215                        }
1216                        
1217                        (WrapperKind::Cow, Some(inner_ty)) => {
1218                            tokens.extend(quote! {
1219                                #[inline]
1220                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1221                                    rust_key_paths::Kp::new(
1222                                        |root: &#name| Some(root.#idx_lit.as_ref()),
1223                                        |root: &mut #name| Some(root.#idx_lit.to_mut()),
1224                                    )
1225                                }
1226                            });
1227                        }
1228                        
1229                        (WrapperKind::OptionCow, Some(inner_ty)) => {
1230                            tokens.extend(quote! {
1231                                #[inline]
1232                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1233                                    rust_key_paths::Kp::new(
1234                                        |root: &#name| root.#idx_lit.as_ref().map(|c| c.as_ref()),
1235                                        |root: &mut #name| root.#idx_lit.as_mut().map(|c| c.to_mut()),
1236                                    )
1237                                }
1238                            });
1239                        }
1240                        (WrapperKind::HashSet, Some(_inner_ty)) => {
1241                            tokens.extend(quote! {
1242                                #[inline]
1243                                    #[inline]
1244                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1245                                    rust_key_paths::Kp::new(
1246                                        |root: &#name| Some(&root.#idx_lit),
1247                                        |root: &mut #name| Some(&mut root.#idx_lit),
1248                                    )
1249                                }
1250                            });
1251                        }
1252                        (WrapperKind::BTreeSet, Some(_inner_ty)) => {
1253                            tokens.extend(quote! {
1254                                #[inline]
1255                                    #[inline]
1256                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1257                                    rust_key_paths::Kp::new(
1258                                        |root: &#name| Some(&root.#idx_lit),
1259                                        |root: &mut #name| Some(&mut root.#idx_lit),
1260                                    )
1261                                }
1262                            });
1263                        }
1264                        (WrapperKind::VecDeque, Some(inner_ty)) => {
1265                            tokens.extend(quote! {
1266                                #[inline]
1267                                    #[inline]
1268                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1269                                    rust_key_paths::Kp::new(
1270                                        |root: &#name| Some(&root.#idx_lit),
1271                                        |root: &mut #name| Some(&mut root.#idx_lit),
1272                                    )
1273                                }
1274                                #[inline]
1275                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1276                                    rust_key_paths::Kp::new(
1277                                        Box::new(move |root: &#name| root.#idx_lit.get(index)),
1278                                        Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
1279                                    )
1280                                }
1281                            });
1282                        }
1283                        (WrapperKind::LinkedList, Some(_inner_ty)) => {
1284                            tokens.extend(quote! {
1285                                #[inline]
1286                                    #[inline]
1287                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1288                                    rust_key_paths::Kp::new(
1289                                        |root: &#name| Some(&root.#idx_lit),
1290                                        |root: &mut #name| Some(&mut root.#idx_lit),
1291                                    )
1292                                }
1293                            });
1294                        }
1295                        (WrapperKind::BinaryHeap, Some(_inner_ty)) => {
1296                            tokens.extend(quote! {
1297                                #[inline]
1298                                    #[inline]
1299                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1300                                    rust_key_paths::Kp::new(
1301                                        |root: &#name| Some(&root.#idx_lit),
1302                                        |root: &mut #name| Some(&mut root.#idx_lit),
1303                                    )
1304                                }
1305                            });
1306                        }
1307                        (WrapperKind::Result, Some(inner_ty)) => {
1308                            tokens.extend(quote! {
1309                                #[inline]
1310                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1311                                    rust_key_paths::Kp::new(
1312                                        |root: &#name| root.#idx_lit.as_ref().ok(),
1313                                        |root: &mut #name| root.#idx_lit.as_mut().ok(),
1314                                    )
1315                                }
1316                            });
1317                        }
1318                        (WrapperKind::Mutex, Some(_inner_ty))
1319                        | (WrapperKind::StdMutex, Some(_inner_ty)) => {
1320                            tokens.extend(quote! {
1321                                #[inline]
1322                                    #[inline]
1323                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1324                                    rust_key_paths::Kp::new(
1325                                        |root: &#name| Some(&root.#idx_lit),
1326                                        |root: &mut #name| Some(&mut root.#idx_lit),
1327                                    )
1328                                }
1329                            });
1330                        }
1331                        (WrapperKind::RwLock, Some(_inner_ty))
1332                        | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
1333                            tokens.extend(quote! {
1334                                #[inline]
1335                                    #[inline]
1336                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1337                                    rust_key_paths::Kp::new(
1338                                        |root: &#name| Some(&root.#idx_lit),
1339                                        |root: &mut #name| Some(&mut root.#idx_lit),
1340                                    )
1341                                }
1342                            });
1343                        }
1344                        (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
1345                            let kp_async_fn = format_ident!("f{}_async", idx);
1346                            tokens.extend(quote! {
1347                                #[inline]
1348                                    #[inline]
1349                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1350                                    rust_key_paths::Kp::new(
1351                                        |root: &#name| Some(&root.#idx_lit),
1352                                        |root: &mut #name| Some(&mut root.#idx_lit),
1353                                    )
1354                                }
1355                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
1356                                    rust_key_paths::async_lock::AsyncLockKp::new(
1357                                        rust_key_paths::Kp::new(
1358                                            |root: &#name| Some(&root.#idx_lit),
1359                                            |root: &mut #name| Some(&mut root.#idx_lit),
1360                                        ),
1361                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
1362                                        rust_key_paths::Kp::new(
1363                                            |v: &#inner_ty| Some(v),
1364                                            |v: &mut #inner_ty| Some(v),
1365                                        ),
1366                                    )
1367                                }
1368                            });
1369                        }
1370                        (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
1371                            let kp_async_fn = format_ident!("f{}_async", idx);
1372                            tokens.extend(quote! {
1373                                #[inline]
1374                                    #[inline]
1375                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1376                                    rust_key_paths::Kp::new(
1377                                        |root: &#name| Some(&root.#idx_lit),
1378                                        |root: &mut #name| Some(&mut root.#idx_lit),
1379                                    )
1380                                }
1381                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
1382                                    rust_key_paths::async_lock::AsyncLockKp::new(
1383                                        rust_key_paths::Kp::new(
1384                                            |root: &#name| Some(&root.#idx_lit),
1385                                            |root: &mut #name| Some(&mut root.#idx_lit),
1386                                        ),
1387                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
1388                                        rust_key_paths::Kp::new(
1389                                            |v: &#inner_ty| Some(v),
1390                                            |v: &mut #inner_ty| Some(v),
1391                                        ),
1392                                    )
1393                                }
1394                            });
1395                        }
1396                        (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
1397                            let kp_async_fn = format_ident!("f{}_async", idx);
1398                            tokens.extend(quote! {
1399                                #[inline]
1400                                    #[inline]
1401                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1402                                    rust_key_paths::Kp::new(
1403                                        |root: &#name| Some(&root.#idx_lit),
1404                                        |root: &mut #name| Some(&mut root.#idx_lit),
1405                                    )
1406                                }
1407                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
1408                                    rust_key_paths::async_lock::AsyncLockKp::new(
1409                                        rust_key_paths::Kp::new(
1410                                            |root: &#name| root.#idx_lit.as_ref(),
1411                                            |root: &mut #name| root.#idx_lit.as_mut(),
1412                                        ),
1413                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
1414                                        rust_key_paths::Kp::new(
1415                                            |v: &#inner_ty| Some(v),
1416                                            |v: &mut #inner_ty| Some(v),
1417                                        ),
1418                                    )
1419                                }
1420                            });
1421                        }
1422                        (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
1423                            let kp_async_fn = format_ident!("f{}_async", idx);
1424                            tokens.extend(quote! {
1425                                #[inline]
1426                                    #[inline]
1427                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1428                                    rust_key_paths::Kp::new(
1429                                        |root: &#name| Some(&root.#idx_lit),
1430                                        |root: &mut #name| Some(&mut root.#idx_lit),
1431                                    )
1432                                }
1433                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
1434                                    rust_key_paths::async_lock::AsyncLockKp::new(
1435                                        rust_key_paths::Kp::new(
1436                                            |root: &#name| root.#idx_lit.as_ref(),
1437                                            |root: &mut #name| root.#idx_lit.as_mut(),
1438                                        ),
1439                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
1440                                        rust_key_paths::Kp::new(
1441                                            |v: &#inner_ty| Some(v),
1442                                            |v: &mut #inner_ty| Some(v),
1443                                        ),
1444                                    )
1445                                }
1446                            });
1447                        }
1448                        (WrapperKind::OptionStdArcMutex, Some(inner_ty))
1449                        | (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
1450                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1451                            tokens.extend(quote! {
1452                                #[inline]
1453                                    #[inline]
1454                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1455                                    rust_key_paths::Kp::new(
1456                                        |root: &#name| Some(&root.#idx_lit),
1457                                        |root: &mut #name| Some(&mut root.#idx_lit),
1458                                    )
1459                                }
1460                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
1461                                    rust_key_paths::Kp::new(
1462                                        |root: &#name| root.#idx_lit.as_ref(),
1463                                        |root: &mut #name| root.#idx_lit.as_mut(),
1464                                    )
1465                                }
1466                            });
1467                        }
1468                        (WrapperKind::OptionStdArcRwLock, Some(inner_ty))
1469                        | (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
1470                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1471                            tokens.extend(quote! {
1472                                #[inline]
1473                                    #[inline]
1474                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1475                                    rust_key_paths::Kp::new(
1476                                        |root: &#name| Some(&root.#idx_lit),
1477                                        |root: &mut #name| Some(&mut root.#idx_lit),
1478                                    )
1479                                }
1480                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
1481                                    rust_key_paths::Kp::new(
1482                                        |root: &#name| root.#idx_lit.as_ref(),
1483                                        |root: &mut #name| root.#idx_lit.as_mut(),
1484                                    )
1485                                }
1486                            });
1487                        }
1488                        (WrapperKind::OptionStdMutex, Some(inner_ty))
1489                        | (WrapperKind::OptionMutex, Some(inner_ty)) => {
1490                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1491                            tokens.extend(quote! {
1492                                #[inline]
1493                                    #[inline]
1494                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1495                                    rust_key_paths::Kp::new(
1496                                        |root: &#name| Some(&root.#idx_lit),
1497                                        |root: &mut #name| Some(&mut root.#idx_lit),
1498                                    )
1499                                }
1500                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
1501                                    rust_key_paths::Kp::new(
1502                                        |root: &#name| root.#idx_lit.as_ref(),
1503                                        |root: &mut #name| root.#idx_lit.as_mut(),
1504                                    )
1505                                }
1506                            });
1507                        }
1508                        (WrapperKind::OptionStdRwLock, Some(inner_ty))
1509                        | (WrapperKind::OptionRwLock, Some(inner_ty)) => {
1510                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1511                            tokens.extend(quote! {
1512                                #[inline]
1513                                    #[inline]
1514                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1515                                    rust_key_paths::Kp::new(
1516                                        |root: &#name| Some(&root.#idx_lit),
1517                                        |root: &mut #name| Some(&mut root.#idx_lit),
1518                                    )
1519                                }
1520                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
1521                                    rust_key_paths::Kp::new(
1522                                        |root: &#name| root.#idx_lit.as_ref(),
1523                                        |root: &mut #name| root.#idx_lit.as_mut(),
1524                                    )
1525                                }
1526                            });
1527                        }
1528                        (WrapperKind::Weak, Some(_inner_ty)) => {
1529                            tokens.extend(quote! {
1530                                #[inline]
1531                                    #[inline]
1532                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1533                                    rust_key_paths::Kp::new(
1534                                        |root: &#name| Some(&root.#idx_lit),
1535                                        |_root: &mut #name| None,
1536                                    )
1537                                }
1538                            });
1539                        }
1540                        (WrapperKind::None, None) => {
1541                            tokens.extend(quote! {
1542                                #[inline]
1543                                    #[inline]
1544                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1545                                    rust_key_paths::Kp::new(
1546                                        |root: &#name| Some(&root.#idx_lit),
1547                                        |root: &mut #name| Some(&mut root.#idx_lit),
1548                                    )
1549                                }
1550                            });
1551                        }
1552                        _ => {
1553                            tokens.extend(quote! {
1554                                #[inline]
1555                                    #[inline]
1556                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1557                                    rust_key_paths::Kp::new(
1558                                        |root: &#name| Some(&root.#idx_lit),
1559                                        |root: &mut #name| Some(&mut root.#idx_lit),
1560                                    )
1561                                }
1562                            });
1563                        }
1564                    }
1565                }
1566
1567                tokens
1568            }
1569            Fields::Unit => {
1570                return syn::Error::new(input_span, "Kp derive does not support unit structs")
1571                .to_compile_error()
1572                .into();
1573            }
1574        },
1575        Data::Enum(data_enum) => {
1576            let mut tokens = proc_macro2::TokenStream::new();
1577
1578            // Generate identity methods for the enum
1579            tokens.extend(quote! {
1580                /// Returns a generic identity keypath for this type
1581                #[inline]
1582                pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
1583                    #name,
1584                    #name,
1585                    Root,
1586                    Root,
1587                    MutRoot,
1588                    MutRoot,
1589                    fn(Root) -> Option<Root>,
1590                    fn(MutRoot) -> Option<MutRoot>,
1591                >
1592                where
1593                    Root: std::borrow::Borrow<#name>,
1594                    MutRoot: std::borrow::BorrowMut<#name>,
1595                {
1596                    rust_key_paths::Kp::new(
1597                        |r: Root| Some(r),
1598                        |r: MutRoot| Some(r)
1599                    )
1600                }
1601
1602                /// Returns a simple identity keypath for this type
1603                #[inline]
1604                pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
1605                    rust_key_paths::Kp::new(
1606                        |r: &#name| Some(r),
1607                        |r: &mut #name| Some(r)
1608                    )
1609                }
1610            });
1611
1612            for variant in data_enum.variants.iter() {
1613                let v_ident = &variant.ident;
1614                let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
1615
1616                match &variant.fields {
1617                    Fields::Unit => {
1618                        // Unit variant - return keypath that checks if enum matches variant
1619                        tokens.extend(quote! {
1620                            #[inline]
1621                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, ()> {
1622                                rust_key_paths::Kp::new(
1623                                    |root: &#name| match root {
1624                                        #name::#v_ident => {
1625                                            static UNIT: () = ();
1626                                            Some(&UNIT)
1627                                        },
1628                                        _ => None,
1629                                    },
1630                                    |_root: &mut #name| None, // Can't mutate unit variant
1631                                )
1632                            }
1633                        });
1634                    }
1635                    Fields::Unnamed(unnamed) => {
1636                        if unnamed.unnamed.len() == 1 {
1637                            // Single-field tuple variant
1638                            let field_ty = &unnamed.unnamed[0].ty;
1639                            let (kind, inner_ty) = extract_wrapper_inner_type(field_ty);
1640
1641                            match (kind, inner_ty.clone()) {
1642                                (WrapperKind::Option, Some(inner_ty)) => {
1643                                    tokens.extend(quote! {
1644                                        #[inline]
1645                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1646                                            rust_key_paths::Kp::new(
1647                                                |root: &#name| match root {
1648                                                    #name::#v_ident(inner) => inner.as_ref(),
1649                                                    _ => None,
1650                                                },
1651                                                |root: &mut #name| match root {
1652                                                    #name::#v_ident(inner) => inner.as_mut(),
1653                                                    _ => None,
1654                                                },
1655                                            )
1656                                        }
1657                                    });
1658                                }
1659                                (WrapperKind::Vec, Some(inner_ty)) => {
1660                                    tokens.extend(quote! {
1661                                        #[inline]
1662                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1663                                            rust_key_paths::Kp::new(
1664                                                |root: &#name| match root {
1665                                                    #name::#v_ident(inner) => inner.first(),
1666                                                    _ => None,
1667                                                },
1668                                                |root: &mut #name| match root {
1669                                                    #name::#v_ident(inner) => inner.first_mut(),
1670                                                    _ => None,
1671                                                },
1672                                            )
1673                                        }
1674                                    });
1675                                }
1676                                (WrapperKind::Box, Some(inner_ty)) => {
1677                                    // Box in enum: deref to inner (&T / &mut T)
1678                                    tokens.extend(quote! {
1679                                        #[inline]
1680                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1681                                            rust_key_paths::Kp::new(
1682                                                |root: &#name| match root {
1683                                                    #name::#v_ident(inner) => Some(&**inner),
1684                                                    _ => None,
1685                                                },
1686                                                |root: &mut #name| match root {
1687                                                    #name::#v_ident(inner) => Some(&mut **inner),
1688                                                    _ => None,
1689                                                },
1690                                            )
1691                                        }
1692                                    });
1693                                }
1694                                (WrapperKind::Rc, Some(inner_ty)) => {
1695                                    tokens.extend(quote! {
1696                                        #[inline]
1697                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1698                                            rust_key_paths::Kp::new(
1699                                                |root: &#name| match root {
1700                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
1701                                                    _ => None,
1702                                                },
1703                                                |root: &mut #name| match root {
1704                                                    #name::#v_ident(inner) => std::rc::Rc::get_mut(inner),
1705                                                    _ => None,
1706                                                },
1707                                            )
1708                                        }
1709                                    });
1710                                }
1711                                (WrapperKind::Arc, Some(inner_ty)) => {
1712                                    tokens.extend(quote! {
1713                                        #[inline]
1714                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1715                                            rust_key_paths::Kp::new(
1716                                                |root: &#name| match root {
1717                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
1718                                                    _ => None,
1719                                                },
1720                                                |root: &mut #name| match root {
1721                                                    #name::#v_ident(inner) => std::sync::Arc::get_mut(inner),
1722                                                    _ => None,
1723                                                },
1724                                            )
1725                                        }
1726                                    });
1727                                }
1728                                (WrapperKind::Cow, Some(inner_ty)) => {
1729                                    tokens.extend(quote! {
1730                                        #[inline]
1731                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1732                                            rust_key_paths::Kp::new(
1733                                                |root: &#name| match root {
1734                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
1735                                                    _ => None,
1736                                                },
1737                                                |root: &mut #name| match root {
1738                                                    #name::#v_ident(inner) => Some(inner.to_mut()),
1739                                                    _ => None,
1740                                                },
1741                                            )
1742                                        }
1743                                    });
1744                                }
1745                                (WrapperKind::OptionCow, Some(inner_ty)) => {
1746                                    tokens.extend(quote! {
1747                                        #[inline]
1748                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1749                                            rust_key_paths::Kp::new(
1750                                                |root: &#name| match root {
1751                                                    #name::#v_ident(inner) => inner.as_ref().map(|c| c.as_ref()),
1752                                                    _ => None,
1753                                                },
1754                                                |root: &mut #name| match root {
1755                                                    #name::#v_ident(inner) => inner.as_mut().map(|c| c.to_mut()),
1756                                                    _ => None,
1757                                                },
1758                                            )
1759                                        }
1760                                    });
1761                                }
1762                                (WrapperKind::None, None) => {
1763                                    // Basic type
1764                                    tokens.extend(quote! {
1765                                        #[inline]
1766                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
1767                                            rust_key_paths::Kp::new(
1768                                                |root: &#name| match root {
1769                                                    #name::#v_ident(inner) => Some(inner),
1770                                                    _ => None,
1771                                                },
1772                                                |root: &mut #name| match root {
1773                                                    #name::#v_ident(inner) => Some(inner),
1774                                                    _ => None,
1775                                                },
1776                                            )
1777                                        }
1778                                    });
1779                                }
1780                                _ => {
1781                                    // Other wrapper types - return keypath to field
1782                                    tokens.extend(quote! {
1783                                        #[inline]
1784                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
1785                                            rust_key_paths::Kp::new(
1786                                                |root: &#name| match root {
1787                                                    #name::#v_ident(inner) => Some(inner),
1788                                                    _ => None,
1789                                                },
1790                                                |root: &mut #name| match root {
1791                                                    #name::#v_ident(inner) => Some(inner),
1792                                                    _ => None,
1793                                                },
1794                                            )
1795                                        }
1796                                    });
1797                                }
1798                            }
1799                        } else {
1800                            // Multi-field tuple variant - return keypath to variant itself
1801                            tokens.extend(quote! {
1802                                #[inline]
1803                                pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
1804                                    rust_key_paths::Kp::new(
1805                                        |root: &#name| match root {
1806                                            #name::#v_ident(..) => Some(root),
1807                                            _ => None,
1808                                        },
1809                                        |root: &mut #name| match root {
1810                                            #name::#v_ident(..) => Some(root),
1811                                            _ => None,
1812                                        },
1813                                    )
1814                                }
1815                            });
1816                        }
1817                    }
1818                    Fields::Named(_) => {
1819                        // Named field variant - return keypath to variant itself
1820                        tokens.extend(quote! {
1821                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
1822                                rust_key_paths::Kp::new(
1823                                    |root: &#name| match root {
1824                                        #name::#v_ident { .. } => Some(root),
1825                                        _ => None,
1826                                    },
1827                                    |root: &mut #name| match root {
1828                                        #name::#v_ident { .. } => Some(root),
1829                                        _ => None,
1830                                    },
1831                                )
1832                            }
1833                        });
1834                    }
1835                }
1836            }
1837
1838            tokens
1839        }
1840        Data::Union(_) => {
1841            return syn::Error::new(input_span, "Kp derive does not support unions")
1842            .to_compile_error()
1843            .into();
1844        }
1845    };
1846
1847    let expanded = quote! {
1848        impl #name {
1849            #methods
1850        }
1851    };
1852
1853    TokenStream::from(expanded)
1854}
1855
1856/// Derive macro that generates `partial_kps() -> Vec<PKp<Self>>` returning all field/variant keypaths.
1857/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
1858///
1859/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
1860/// (using the same methods Kp generates, e.g. `some_variant()`).
1861///
1862/// # Example
1863/// ```
1864/// use key_paths_derive::{Kp, Pkp};
1865/// use rust_key_paths::PKp;
1866///
1867/// #[derive(Kp, Pkp)]
1868/// struct Person {
1869///     name: String,
1870///     age: i32,
1871/// }
1872///
1873/// let kps = Person::partial_kps();
1874/// assert_eq!(kps.len(), 2);
1875/// ```
1876#[proc_macro_derive(Pkp)]
1877pub fn derive_partial_keypaths(input: TokenStream) -> TokenStream {
1878    let input = parse_macro_input!(input as DeriveInput);
1879    let name = &input.ident;
1880
1881    let kp_calls = match &input.data {
1882        Data::Struct(data_struct) => match &data_struct.fields {
1883            Fields::Named(fields_named) => {
1884                let calls: Vec<_> = fields_named
1885                    .named
1886                    .iter()
1887                    .filter_map(|f| f.ident.as_ref())
1888                    .map(|field_ident| {
1889                        quote! { rust_key_paths::PKp::new(Self::#field_ident()) }
1890                    })
1891                    .collect();
1892                quote! { #(#calls),* }
1893            }
1894            Fields::Unnamed(unnamed) => {
1895                let calls: Vec<_> = (0..unnamed.unnamed.len())
1896                    .map(|idx| {
1897                        let kp_fn = format_ident!("f{}", idx);
1898                        quote! { rust_key_paths::PKp::new(Self::#kp_fn()) }
1899                    })
1900                    .collect();
1901                quote! { #(#calls),* }
1902            }
1903            Fields::Unit => quote! {},
1904        },
1905        Data::Enum(data_enum) => {
1906            let calls: Vec<_> = data_enum
1907                .variants
1908                .iter()
1909                .map(|variant| {
1910                    let v_ident = &variant.ident;
1911                    let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
1912                    quote! { rust_key_paths::PKp::new(Self::#snake()) }
1913                })
1914                .collect();
1915            quote! { #(#calls),* }
1916        }
1917        Data::Union(_) => {
1918            return syn::Error::new(
1919                input.ident.span(),
1920                "Pkp derive does not support unions",
1921            )
1922            .to_compile_error()
1923            .into();
1924        }
1925    };
1926
1927    let expanded = quote! {
1928        impl #name {
1929            /// Returns a vec of all field keypaths as partial keypaths (type-erased).
1930            #[inline]
1931            pub fn partial_kps() -> Vec<rust_key_paths::PKp<#name>> {
1932                vec![#kp_calls]
1933            }
1934        }
1935    };
1936
1937    TokenStream::from(expanded)
1938}
1939
1940/// Derive macro that generates `any_kps() -> Vec<AKp>` returning all field/variant keypaths as any keypaths.
1941/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
1942/// AKp type-erases both Root and Value, enabling heterogeneous collections of keypaths.
1943///
1944/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
1945/// (using the same methods Kp generates, e.g. `some_variant()`).
1946///
1947/// # Example
1948/// ```
1949/// use key_paths_derive::{Kp, Akp};
1950/// use rust_key_paths::AKp;
1951///
1952/// #[derive(Kp, Akp)]
1953/// struct Person {
1954///     name: String,
1955///     age: i32,
1956/// }
1957///
1958/// let kps = Person::any_kps();
1959/// assert_eq!(kps.len(), 2);
1960/// let person = Person { name: "Alice".into(), age: 30 };
1961/// let name: Option<&String> = kps[0].get(&person as &dyn std::any::Any).and_then(|v| v.downcast_ref());
1962/// assert_eq!(name, Some(&"Alice".to_string()));
1963/// ```
1964#[proc_macro_derive(Akp)]
1965pub fn derive_any_keypaths(input: TokenStream) -> TokenStream {
1966    let input = parse_macro_input!(input as DeriveInput);
1967    let name = &input.ident;
1968
1969    let kp_calls = match &input.data {
1970        Data::Struct(data_struct) => match &data_struct.fields {
1971            Fields::Named(fields_named) => {
1972                let calls: Vec<_> = fields_named
1973                    .named
1974                    .iter()
1975                    .filter_map(|f| f.ident.as_ref())
1976                    .map(|field_ident| {
1977                        quote! { rust_key_paths::AKp::new(Self::#field_ident()) }
1978                    })
1979                    .collect();
1980                quote! { #(#calls),* }
1981            }
1982            Fields::Unnamed(unnamed) => {
1983                let calls: Vec<_> = (0..unnamed.unnamed.len())
1984                    .map(|idx| {
1985                        let kp_fn = format_ident!("f{}", idx);
1986                        quote! { rust_key_paths::AKp::new(Self::#kp_fn()) }
1987                    })
1988                    .collect();
1989                quote! { #(#calls),* }
1990            }
1991            Fields::Unit => quote! {},
1992        },
1993        Data::Enum(data_enum) => {
1994            let calls: Vec<_> = data_enum
1995                .variants
1996                .iter()
1997                .map(|variant| {
1998                    let v_ident = &variant.ident;
1999                    let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
2000                    quote! { rust_key_paths::AKp::new(Self::#snake()) }
2001                })
2002                .collect();
2003            quote! { #(#calls),* }
2004        }
2005        Data::Union(_) => {
2006            return syn::Error::new(
2007                input.ident.span(),
2008                "Akp derive does not support unions",
2009            )
2010            .to_compile_error()
2011            .into();
2012        }
2013    };
2014
2015    let expanded = quote! {
2016        impl #name {
2017            /// Returns a vec of all field keypaths as any keypaths (fully type-erased).
2018            #[inline]
2019            pub fn any_kps() -> Vec<rust_key_paths::AKp> {
2020                vec![#kp_calls]
2021            }
2022        }
2023    };
2024
2025    TokenStream::from(expanded)
2026}