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    OptionTagged,
70    // Clone-on-write (std::borrow::Cow)
71    Cow,
72    OptionCow,
73    // Reference types (&T, &str, &[T], etc.)
74    Reference,
75    OptionReference,
76    // Atomic types (std::sync::atomic::*)
77    Atomic,
78    OptionAtomic,
79    // Pin types
80    Pin,
81    PinBox,
82    /// Field marked with #[pin] - plain type (pin_project pattern)
83    PinnedField,
84    /// Field marked with #[pin] - Future type (pin_project pattern)
85    PinnedFuture,
86    /// Field marked with #[pin] - Box<dyn Future> (pin_project pattern)
87    PinnedBoxFuture,
88}
89
90/// Helper function to check if a type path includes std::sync module
91fn is_std_sync_type(path: &syn::Path) -> bool {
92    // Check for paths like std::sync::Mutex, std::sync::RwLock
93    let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
94    segments.len() >= 2
95        && segments.contains(&"std".to_string())
96        && segments.contains(&"sync".to_string())
97}
98
99/// Helper function to check if a type path includes tokio::sync module
100fn is_tokio_sync_type(path: &syn::Path) -> bool {
101    // Check for paths like tokio::sync::Mutex, tokio::sync::RwLock
102    let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
103    segments.len() >= 2
104        && segments.contains(&"tokio".to_string())
105        && segments.contains(&"sync".to_string())
106}
107
108/// Helper function to check if a type path includes std::sync::atomic module
109fn is_std_sync_atomic_type(path: &syn::Path) -> bool {
110    let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
111    segments.contains(&"std".to_string())
112        && segments.contains(&"sync".to_string())
113        && segments.contains(&"atomic".to_string())
114}
115
116/// Atomic type idents (no type params): AtomicBool, AtomicI8, etc.
117const ATOMIC_TYPE_IDENTS: &[&str] = &[
118    "AtomicBool", "AtomicI8", "AtomicI16", "AtomicI32", "AtomicI64", "AtomicI128", "AtomicIsize",
119    "AtomicU8", "AtomicU16", "AtomicU32", "AtomicU64", "AtomicU128", "AtomicUsize",
120];
121
122fn extract_wrapper_inner_type(ty: &Type) -> (WrapperKind, Option<Type>) {
123    use syn::{GenericArgument, PathArguments};
124
125    // Handle reference types: &T, &'a str, &[T], etc.
126    if let Type::Reference(tr) = ty {
127        return (WrapperKind::Reference, Some((*tr.elem).clone()));
128    }
129
130    if let Type::Path(tp) = ty {
131        // Check if this is explicitly a std::sync type
132        let is_std_sync = is_std_sync_type(&tp.path);
133        // Check if this is explicitly a tokio::sync type
134        let is_tokio_sync = is_tokio_sync_type(&tp.path);
135
136        if let Some(seg) = tp.path.segments.last() {
137            let ident_str = seg.ident.to_string();
138
139            if let PathArguments::AngleBracketed(ab) = &seg.arguments {
140                let args: Vec<_> = ab.args.iter().collect();
141
142                // Handle map types (HashMap, BTreeMap) - they have K, V parameters
143                if ident_str == "HashMap" || ident_str == "BTreeMap" {
144                    if let (Some(_key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
145                        if let GenericArgument::Type(inner) = value_arg {
146                            // Check for nested Option in map values
147                            let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
148                            match (ident_str.as_str(), inner_kind) {
149                                ("HashMap", WrapperKind::Option) => {
150                                    return (WrapperKind::HashMapOption, inner_inner);
151                                }
152                                _ => {
153                                    return match ident_str.as_str() {
154                                        "HashMap" => (WrapperKind::HashMap, Some(inner.clone())),
155                                        "BTreeMap" => (WrapperKind::BTreeMap, Some(inner.clone())),
156                                        _ => (WrapperKind::None, None),
157                                    };
158                                }
159                            }
160                        }
161                    }
162                }
163                // Handle Cow<'a, B> - has lifetime then type parameter
164                else if ident_str == "Cow" {
165                    if let Some(inner) = args.iter().find_map(|arg| {
166                        if let GenericArgument::Type(t) = arg {
167                            Some(t.clone())
168                        } else {
169                            None
170                        }
171                    }) {
172                        return (WrapperKind::Cow, Some(inner));
173                    }
174                }
175                // Handle single-parameter container types
176                else if let Some(arg) = args.get(0) {
177                    if let GenericArgument::Type(inner) = arg {
178                        // Check for nested containers first
179                        let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
180
181                        // Handle nested combinations
182                        match (ident_str.as_str(), inner_kind) {
183                            ("Option", WrapperKind::Box) => {
184                                return (WrapperKind::OptionBox, inner_inner);
185                            }
186                            ("Option", WrapperKind::Rc) => {
187                                return (WrapperKind::OptionRc, inner_inner);
188                            }
189                            ("Option", WrapperKind::Arc) => {
190                                return (WrapperKind::OptionArc, inner_inner);
191                            }
192                            ("Option", WrapperKind::Vec) => {
193                                return (WrapperKind::OptionVec, inner_inner);
194                            }
195                            ("Option", WrapperKind::HashMap) => {
196                                return (WrapperKind::OptionHashMap, inner_inner);
197                            }
198                            ("Option", WrapperKind::StdArcMutex) => {
199                                return (WrapperKind::OptionStdArcMutex, inner_inner);
200                            }
201                            ("Option", WrapperKind::StdArcRwLock) => {
202                                return (WrapperKind::OptionStdArcRwLock, inner_inner);
203                            }
204                            ("Option", WrapperKind::ArcMutex) => {
205                                return (WrapperKind::OptionArcMutex, inner_inner);
206                            }
207                            ("Option", WrapperKind::ArcRwLock) => {
208                                return (WrapperKind::OptionArcRwLock, inner_inner);
209                            }
210                            ("Option", WrapperKind::StdMutex) => {
211                                return (WrapperKind::OptionStdMutex, inner_inner);
212                            }
213                            ("Option", WrapperKind::StdRwLock) => {
214                                return (WrapperKind::OptionStdRwLock, inner_inner);
215                            }
216                            ("Option", WrapperKind::Mutex) => {
217                                return (WrapperKind::OptionMutex, inner_inner);
218                            }
219                            ("Option", WrapperKind::RwLock) => {
220                                return (WrapperKind::OptionRwLock, inner_inner);
221                            }
222                            ("Option", WrapperKind::TokioArcMutex) => {
223                                return (WrapperKind::OptionTokioArcMutex, inner_inner);
224                            }
225                            ("Option", WrapperKind::TokioArcRwLock) => {
226                                return (WrapperKind::OptionTokioArcRwLock, inner_inner);
227                            }
228                            ("Option", WrapperKind::Cow) => {
229                                return (WrapperKind::OptionCow, inner_inner);
230                            }
231                            ("Option", WrapperKind::Tagged) => {
232                                return (WrapperKind::OptionTagged, inner_inner);
233                            }
234                            ("Option", WrapperKind::Reference) => {
235                                return (WrapperKind::OptionReference, Some(inner.clone()));
236                            }
237                            ("Option", WrapperKind::Atomic) => {
238                                return (WrapperKind::OptionAtomic, Some(inner.clone()));
239                            }
240                            ("Pin", WrapperKind::Box) => {
241                                return (WrapperKind::PinBox, inner_inner);
242                            }
243                            ("Box", WrapperKind::Option) => {
244                                return (WrapperKind::BoxOption, inner_inner);
245                            }
246                            ("Rc", WrapperKind::Option) => {
247                                return (WrapperKind::RcOption, inner_inner);
248                            }
249                            ("Arc", WrapperKind::Option) => {
250                                return (WrapperKind::ArcOption, inner_inner);
251                            }
252                            ("Vec", WrapperKind::Option) => {
253                                return (WrapperKind::VecOption, inner_inner);
254                            }
255                            ("HashMap", WrapperKind::Option) => {
256                                return (WrapperKind::HashMapOption, inner_inner);
257                            }
258                            // std::sync variants (when inner is StdMutex/StdRwLock)
259                            ("Arc", WrapperKind::StdMutex) => {
260                                return (WrapperKind::StdArcMutex, inner_inner);
261                            }
262                            ("Arc", WrapperKind::StdRwLock) => {
263                                return (WrapperKind::StdArcRwLock, inner_inner);
264                            }
265                            // parking_lot variants (default - when inner is Mutex/RwLock without std::sync prefix)
266                            ("Arc", WrapperKind::Mutex) => {
267                                return (WrapperKind::ArcMutex, inner_inner);
268                            }
269                            ("Arc", WrapperKind::RwLock) => {
270                                return (WrapperKind::ArcRwLock, inner_inner);
271                            }
272                            // tokio::sync variants (when inner is TokioMutex/TokioRwLock)
273                            ("Arc", WrapperKind::TokioMutex) => {
274                                return (WrapperKind::TokioArcMutex, inner_inner);
275                            }
276                            ("Arc", WrapperKind::TokioRwLock) => {
277                                return (WrapperKind::TokioArcRwLock, inner_inner);
278                            }
279                            _ => {
280                                // Handle single-level containers
281                                // For Mutex and RwLock:
282                                // - If path contains std::sync, it's std::sync (StdMutex/StdRwLock)
283                                // - Otherwise, default to parking_lot (Mutex/RwLock)
284                                return match ident_str.as_str() {
285                                    "Option" => (WrapperKind::Option, Some(inner.clone())),
286                                    "Box" => (WrapperKind::Box, Some(inner.clone())),
287                                    "Rc" => (WrapperKind::Rc, Some(inner.clone())),
288                                    "Arc" => (WrapperKind::Arc, Some(inner.clone())),
289                                    "Vec" => (WrapperKind::Vec, Some(inner.clone())),
290                                    "HashSet" => (WrapperKind::HashSet, Some(inner.clone())),
291                                    "BTreeSet" => (WrapperKind::BTreeSet, Some(inner.clone())),
292                                    "VecDeque" => (WrapperKind::VecDeque, Some(inner.clone())),
293                                    "LinkedList" => (WrapperKind::LinkedList, Some(inner.clone())),
294                                    "BinaryHeap" => (WrapperKind::BinaryHeap, Some(inner.clone())),
295                                    "Result" => (WrapperKind::Result, Some(inner.clone())),
296                                    // For std::sync::Mutex and std::sync::RwLock, use Std variants
297                                    "Mutex" if is_std_sync => {
298                                        (WrapperKind::StdMutex, Some(inner.clone()))
299                                    }
300                                    "RwLock" if is_std_sync => {
301                                        (WrapperKind::StdRwLock, Some(inner.clone()))
302                                    }
303                                    // For tokio::sync::Mutex and tokio::sync::RwLock, use Tokio variants
304                                    "Mutex" if is_tokio_sync => {
305                                        (WrapperKind::TokioMutex, Some(inner.clone()))
306                                    }
307                                    "RwLock" if is_tokio_sync => {
308                                        (WrapperKind::TokioRwLock, Some(inner.clone()))
309                                    }
310                                    // Default: parking_lot (no std::sync or tokio::sync prefix)
311                                    "Mutex" => (WrapperKind::Mutex, Some(inner.clone())),
312                                    "RwLock" => (WrapperKind::RwLock, Some(inner.clone())),
313                                    "Weak" => (WrapperKind::Weak, Some(inner.clone())),
314                                    "Tagged" => (WrapperKind::Tagged, Some(inner.clone())),
315                                    "Cow" => (WrapperKind::Cow, Some(inner.clone())),
316                                    "AtomicPtr" if is_std_sync_atomic_type(&tp.path) => (WrapperKind::Atomic, None),
317                                    "Pin" => (WrapperKind::Pin, Some(inner.clone())),
318                                    _ => (WrapperKind::None, None),
319                                };
320                            }
321                        }
322                    }
323                }
324            }
325            // Handle atomic types with no angle bracket args (AtomicBool, AtomicI32, etc.)
326            if matches!(seg.arguments, PathArguments::None)
327                && is_std_sync_atomic_type(&tp.path)
328                && ATOMIC_TYPE_IDENTS.contains(&ident_str.as_str())
329            {
330                return (WrapperKind::Atomic, None);
331            }
332        }
333    }
334    (WrapperKind::None, None)
335}
336
337/// Check if a field has the #[pin] attribute (pin_project pattern).
338fn field_has_pin_attr(field: &syn::Field) -> bool {
339    field.attrs.iter().any(|attr| {
340        attr.path().get_ident().map(|i| i == "pin").unwrap_or(false)
341    })
342}
343
344/// Check if a type is a Future (dyn Future, impl Future, or Box<dyn Future>).
345fn is_future_type(ty: &Type) -> bool {
346    use syn::{GenericArgument, PathArguments, TypeParamBound};
347
348    match ty {
349        Type::TraitObject(trait_obj) => trait_obj.bounds.iter().any(|b| {
350            if let TypeParamBound::Trait(t) = b {
351                t.path.segments.last()
352                    .map(|s| s.ident == "Future")
353                    .unwrap_or(false)
354            } else {
355                false
356            }
357        }),
358        Type::ImplTrait(impl_trait) => impl_trait.bounds.iter().any(|b| {
359            if let TypeParamBound::Trait(t) = b {
360                t.path.segments.last()
361                    .map(|s| s.ident == "Future")
362                    .unwrap_or(false)
363            } else {
364                false
365            }
366        }),
367        Type::Path(tp) => {
368            if let Some(seg) = tp.path.segments.last() {
369                if seg.ident == "Box" {
370                    if let PathArguments::AngleBracketed(args) = &seg.arguments {
371                        if let Some(GenericArgument::Type(inner)) = args.args.first() {
372                            return is_future_type(inner);
373                        }
374                    }
375                }
376            }
377            false
378        }
379        _ => false,
380    }
381}
382
383/// Extract Output type from Future trait bound (dyn Future<Output = T>, impl Future<Output = T>, etc.).
384fn extract_future_output(ty: &Type) -> Option<Type> {
385    use syn::{GenericArgument, PathArguments, TypeParamBound};
386
387    let bounds = match ty {
388        Type::TraitObject(t) => &t.bounds,
389        Type::ImplTrait(t) => &t.bounds,
390        Type::Path(tp) => {
391            if let Some(seg) = tp.path.segments.last() {
392                if seg.ident == "Box" {
393                    if let PathArguments::AngleBracketed(args) = &seg.arguments {
394                        if let Some(GenericArgument::Type(inner)) = args.args.first() {
395                            return extract_future_output(inner);
396                        }
397                    }
398                }
399            }
400            return None;
401        }
402        _ => return None,
403    };
404
405    for bound in bounds {
406        if let TypeParamBound::Trait(trait_bound) = bound {
407            if let Some(seg) = trait_bound.path.segments.last() {
408                if seg.ident == "Future" {
409                    if let PathArguments::AngleBracketed(args) = &seg.arguments {
410                        for arg in &args.args {
411                            if let GenericArgument::AssocType(assoc) = arg {
412                                if assoc.ident == "Output" {
413                                    return Some(assoc.ty.clone());
414                                }
415                            }
416                        }
417                    }
418                }
419            }
420        }
421    }
422    None
423}
424
425/// For HashMap<K,V> or BTreeMap<K,V>, returns Some((key_ty, value_ty)).
426fn extract_map_key_value(ty: &Type) -> Option<(Type, Type)> {
427    use syn::{GenericArgument, PathArguments};
428
429    if let Type::Path(tp) = ty {
430        if let Some(seg) = tp.path.segments.last() {
431            let ident_str = seg.ident.to_string();
432            if ident_str == "HashMap" || ident_str == "BTreeMap" {
433                if let PathArguments::AngleBracketed(ab) = &seg.arguments {
434                    let args: Vec<_> = ab.args.iter().collect();
435                    if let (Some(key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
436                        if let (GenericArgument::Type(key_ty), GenericArgument::Type(value_ty)) =
437                            (key_arg, value_arg)
438                        {
439                            return Some((key_ty.clone(), value_ty.clone()));
440                        }
441                    }
442                }
443            }
444        }
445    }
446    None
447}
448
449fn to_snake_case(name: &str) -> String {
450    let mut out = String::new();
451    for (i, c) in name.chars().enumerate() {
452        if c.is_uppercase() {
453            if i != 0 {
454                out.push('_');
455            }
456            out.push(c.to_ascii_lowercase());
457        } else {
458            out.push(c);
459        }
460    }
461    out
462}
463
464/// Derive macro for generating simple keypath methods.
465/// 
466/// Generates one method per field: `StructName::field_name()` that returns a `Kp`.
467/// Intelligently handles wrapper types (Option, Vec, Box, Arc, etc.) to generate appropriate keypaths.
468/// 
469/// # Example
470/// 
471/// ```ignore
472/// #[derive(Kp)]
473/// struct Person {
474///     name: String,
475///     age: i32,
476///     email: Option<String>,
477///     addresses: Vec<String>,
478/// }
479/// 
480/// // Generates:
481/// // impl Person {
482/// //     pub fn name() -> Kp<...> { ... }
483/// //     pub fn age() -> Kp<...> { ... }
484/// //     pub fn email() -> Kp<...> { ... } // unwraps Option
485/// //     pub fn addresses() -> Kp<...> { ... } // accesses first element
486/// // }
487/// ```
488#[proc_macro_derive(Kp)]
489pub fn derive_keypaths(input: TokenStream) -> TokenStream {
490    let input = parse_macro_input!(input as DeriveInput);
491    let name = &input.ident;
492    let input_span = input.span();
493
494    let methods = match input.data {
495        Data::Struct(data_struct) => match data_struct.fields {
496            Fields::Named(fields_named) => {
497                let mut tokens = proc_macro2::TokenStream::new();
498
499                // Generate identity methods for the struct
500                tokens.extend(quote! {
501                    /// Returns a generic identity keypath for this type
502                    #[inline(always)]
503                    pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
504                        #name,
505                        #name,
506                        Root,
507                        Root,
508                        MutRoot,
509                        MutRoot,
510                        fn(Root) -> Option<Root>,
511                        fn(MutRoot) -> Option<MutRoot>,
512                    >
513                    where
514                        Root: std::borrow::Borrow<#name>,
515                        MutRoot: std::borrow::BorrowMut<#name>,
516                    {
517                        rust_key_paths::Kp::new(
518                            |r: Root| Some(r),
519                            |r: MutRoot| Some(r)
520                        )
521                    }
522
523                    /// Returns a simple identity keypath for this type
524                    #[inline(always)]
525                    pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
526                        rust_key_paths::Kp::new(
527                            |r: &#name| Some(r),
528                            |r: &mut #name| Some(r)
529                        )
530                    }
531                });
532                
533                // When struct has #[pin] fields, generated code calls this.project() which must
534                // be provided by #[pin_project]. If missing, user gets: no method named `project`.
535
536                for field in fields_named.named.iter() {
537                    let field_ident = field.ident.as_ref().unwrap();
538                    let ty = &field.ty;
539                    // Centralized keypath method names – change here to adjust for all types
540                    let kp_fn = format_ident!("{}", field_ident);
541                    let kp_at_fn = format_ident!("{}_at", field_ident);
542
543                    let (kind, inner_ty) = extract_wrapper_inner_type(ty);
544
545                    // Override kind when field has #[pin] (pin_project pattern)
546                    let (kind, inner_ty) = if field_has_pin_attr(field) {
547                        let pinned_kind = if let Some(output_ty) = extract_future_output(ty) {
548                            if matches!(kind, WrapperKind::Box) {
549                                (WrapperKind::PinnedBoxFuture, Some(output_ty))
550                            } else {
551                                (WrapperKind::PinnedFuture, Some(output_ty))
552                            }
553                        } else if is_future_type(ty) {
554                            (WrapperKind::PinnedFuture, inner_ty.clone())
555                        } else {
556                            (WrapperKind::PinnedField, inner_ty.clone())
557                        };
558                        pinned_kind
559                    } else {
560                        (kind, inner_ty.clone())
561                    };
562
563                    match (kind, inner_ty) {
564                        (WrapperKind::Option, Some(inner_ty)) => {
565                            // For Option<T>, unwrap and access inner type
566                            tokens.extend(quote! {
567                                #[inline(always)]
568                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
569                                    rust_key_paths::Kp::new(
570                                        |root: &#name| root.#field_ident.as_ref(),
571                                        |root: &mut #name| root.#field_ident.as_mut(),
572                                    )
573                                }
574                            });
575                        }
576                        (WrapperKind::Vec, Some(inner_ty)) => {
577                            tokens.extend(quote! {
578                                #[inline(always)]
579                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
580                                    rust_key_paths::Kp::new(
581                                        |root: &#name| Some(&root.#field_ident),
582                                        |root: &mut #name| Some(&mut root.#field_ident),
583                                    )
584                                }
585                                #[inline(always)]
586                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
587                                    rust_key_paths::Kp::new(
588                                        Box::new(move |root: &#name| root.#field_ident.get(index)),
589                                        Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
590                                    )
591                                }
592                            });
593                        }
594                        (WrapperKind::HashMap, Some(inner_ty)) => {
595                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
596                                tokens.extend(quote! {
597                                    #[inline(always)]
598                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
599                                        rust_key_paths::Kp::new(
600                                            |root: &#name| Some(&root.#field_ident),
601                                            |root: &mut #name| Some(&mut root.#field_ident),
602                                        )
603                                    }
604                                    #[inline(always)]
605                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
606                                    where
607                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
608                                    {
609                                        let key2 = key.clone();
610                                        rust_key_paths::Kp::new(
611                                            Box::new(move |root: &#name| root.#field_ident.get(&key)),
612                                            Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
613                                        )
614                                    }
615                                });
616                            } else {
617                                tokens.extend(quote! {
618                                    #[inline(always)]
619                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
620                                        rust_key_paths::Kp::new(
621                                            |root: &#name| Some(&root.#field_ident),
622                                            |root: &mut #name| Some(&mut root.#field_ident),
623                                        )
624                                    }
625                                });
626                            }
627                        }
628                        (WrapperKind::BTreeMap, Some(inner_ty)) => {
629                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
630                                tokens.extend(quote! {
631                                    #[inline(always)]
632                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
633                                        rust_key_paths::Kp::new(
634                                            |root: &#name| Some(&root.#field_ident),
635                                            |root: &mut #name| Some(&mut root.#field_ident),
636                                        )
637                                    }
638                                    #[inline(always)]
639                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
640                                    where
641                                        #key_ty: Clone + Ord + 'static,
642                                    {
643                                        let key2 = key.clone();
644                                        rust_key_paths::Kp::new(
645                                            Box::new(move |root: &#name| root.#field_ident.get(&key)),
646                                            Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
647                                        )
648                                    }
649                                });
650                            } else {
651                                tokens.extend(quote! {
652                                    #[inline(always)]
653                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
654                                        rust_key_paths::Kp::new(
655                                            |root: &#name| Some(&root.#field_ident),
656                                            |root: &mut #name| Some(&mut root.#field_ident),
657                                        )
658                                    }
659                                });
660                            }
661                        }
662                        (WrapperKind::Box, Some(inner_ty)) => {
663                            // For Box<T>, deref to inner type (returns &T / &mut T, not &Box<T>)
664                            tokens.extend(quote! {
665                                #[inline(always)]
666                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
667                                    rust_key_paths::Kp::new(
668                                        |root: &#name| Some(&*root.#field_ident),
669                                        |root: &mut #name| Some(&mut *root.#field_ident),
670                                    )
671                                }
672                            });
673                        }
674                        (WrapperKind::Pin, Some(inner_ty)) => {
675                            let kp_inner_fn = format_ident!("{}_inner", field_ident);
676                            tokens.extend(quote! {
677                                #[inline(always)]
678                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
679                                    rust_key_paths::Kp::new(
680                                        |root: &#name| Some(&root.#field_ident),
681                                        |root: &mut #name| Some(&mut root.#field_ident),
682                                    )
683                                }
684                                #[inline(always)]
685                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
686                                where #inner_ty: std::marker::Unpin
687                                {
688                                    rust_key_paths::Kp::new(
689                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#field_ident).get_ref()),
690                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#field_ident).get_mut()),
691                                    )
692                                }
693                            });
694                        }
695                        (WrapperKind::PinBox, Some(inner_ty)) => {
696                            let kp_inner_fn = format_ident!("{}_inner", field_ident);
697                            tokens.extend(quote! {
698                                #[inline(always)]
699                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
700                                    rust_key_paths::Kp::new(
701                                        |root: &#name| Some(&root.#field_ident),
702                                        |root: &mut #name| Some(&mut root.#field_ident),
703                                    )
704                                }
705                                #[inline(always)]
706                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
707                                where #inner_ty: std::marker::Unpin
708                                {
709                                    // Pin::as_ref on Pin<Box<T>> returns Pin<&T> (Box Deref target), so get_ref() already gives &T
710                                    rust_key_paths::Kp::new(
711                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#field_ident).get_ref()),
712                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#field_ident).get_mut()),
713                                    )
714                                }
715                            });
716                        }
717                        (WrapperKind::PinnedField, _) => {
718                            let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
719                            tokens.extend(quote! {
720                                #[inline(always)]
721                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
722                                    rust_key_paths::Kp::new(
723                                        |root: &#name| Some(&root.#field_ident),
724                                        |root: &mut #name| Some(&mut root.#field_ident),
725                                    )
726                                }
727                                /// Pinned projection for #[pin] field. Requires #[pin_project] on struct.
728                                #[inline(always)]
729                                pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
730                                    this.project().#field_ident
731                                }
732                            });
733                        }
734                        (WrapperKind::PinnedFuture, _) => {
735                            let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
736                            let kp_await_fn = format_ident!("{}_await", field_ident);
737                            tokens.extend(quote! {
738                                #[inline(always)]
739                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
740                                    rust_key_paths::Kp::new(
741                                        |root: &#name| Some(&root.#field_ident),
742                                        |root: &mut #name| Some(&mut root.#field_ident),
743                                    )
744                                }
745                                /// Pinned projection for #[pin] Future field. Requires #[pin_project] on struct.
746                                #[inline(always)]
747                                pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
748                                    this.project().#field_ident
749                                }
750                                /// Poll the pinned future. Requires #[pin_project] on struct.
751                                pub async fn #kp_await_fn(this: std::pin::Pin<&mut #name>) -> Option<<#ty as std::future::Future>::Output>
752                                where #ty: std::future::Future
753                                {
754                                    use std::future::Future;
755                                    Some(this.project().#field_ident.await)
756                                }
757                            });
758                        }
759                        (WrapperKind::PinnedBoxFuture, Some(output_ty)) => {
760                            let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
761                            let kp_await_fn = format_ident!("{}_await", field_ident);
762                            tokens.extend(quote! {
763                                #[inline(always)]
764                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
765                                    rust_key_paths::Kp::new(
766                                        |root: &#name| Some(&root.#field_ident),
767                                        |root: &mut #name| Some(&mut root.#field_ident),
768                                    )
769                                }
770                                /// Pinned projection for #[pin] Box<dyn Future> field. Requires #[pin_project] on struct.
771                                #[inline(always)]
772                                pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
773                                    this.project().#field_ident
774                                }
775                                /// Poll the pinned boxed future. Requires #[pin_project] on struct.
776                                pub async fn #kp_await_fn(this: std::pin::Pin<&mut #name>) -> Option<#output_ty> {
777                                    Some(this.project().#field_ident.await)
778                                }
779                            });
780                        }
781                        (WrapperKind::Rc, Some(inner_ty)) => {
782                            // For Rc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
783                            tokens.extend(quote! {
784                                #[inline(always)]
785                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
786                                    rust_key_paths::Kp::new(
787                                        |root: &#name| Some(root.#field_ident.as_ref()),
788                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#field_ident),
789                                    )
790                                }
791                            });
792                        }
793                        (WrapperKind::Arc, Some(inner_ty)) => {
794                            // For Arc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
795                            tokens.extend(quote! {
796                                #[inline(always)]
797                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
798                                    rust_key_paths::Kp::new(
799                                        |root: &#name| Some(root.#field_ident.as_ref()),
800                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#field_ident),
801                                    )
802                                }
803                            });
804                        }
805                        (WrapperKind::Cow, Some(inner_ty)) => {
806                            // For Cow<'_, B>, deref to inner type (as_ref/to_mut)
807                            tokens.extend(quote! {
808                                #[inline(always)]
809                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
810                                    rust_key_paths::Kp::new(
811                                        |root: &#name| Some(root.#field_ident.as_ref()),
812                                        |root: &mut #name| Some(root.#field_ident.to_mut()),
813                                    )
814                                }
815                            });
816                        }
817                        
818                        (WrapperKind::OptionCow, Some(inner_ty)) => {
819                            // For Option<Cow<'_, B>>
820                            tokens.extend(quote! {
821                                #[inline(always)]
822                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
823                                    rust_key_paths::Kp::new(
824                                        |root: &#name| root.#field_ident.as_ref().map(|c| c.as_ref()),
825                                        |root: &mut #name| root.#field_ident.as_mut().map(|c| c.to_mut()),
826                                    )
827                                }
828                            });
829                        }
830                        (WrapperKind::OptionTagged, Some(inner_ty)) => {
831                            // For Option<Tagged<Tag, T>> - Tagged implements Deref/DerefMut
832                            tokens.extend(quote! {
833                                #[inline(always)]
834                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
835                                    rust_key_paths::Kp::new(
836                                        |root: &#name| root.#field_ident.as_ref().map(|t| std::ops::Deref::deref(t)),
837                                        |root: &mut #name| root.#field_ident.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
838                                    )
839                                }
840                            });
841                        }
842                        (WrapperKind::OptionReference, Some(inner_ty)) => {
843                            // For Option<&T>, Option<&str>, Option<&[T]> - read-only, setter returns None
844                            tokens.extend(quote! {
845                                #[inline(always)]
846                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
847                                    rust_key_paths::Kp::new(
848                                        |root: &#name| root.#field_ident.as_ref(),
849                                        |_root: &mut #name| None,
850                                    )
851                                }
852                            });
853                        }
854                        (WrapperKind::HashSet, Some(inner_ty)) => {
855                            let kp_at_fn = format_ident!("{}_at", field_ident);
856
857                            tokens.extend(quote! {
858                                #[inline(always)]
859                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
860                                    rust_key_paths::Kp::new(
861                                        |root: &#name| Some(&root.#field_ident),
862                                        |root: &mut #name| Some(&mut root.#field_ident),
863                                    )
864                                }
865
866                                /// _at: check if element exists and get reference.
867                                /// HashSet does not allow mutable element access (would break hash invariant).
868                                #[inline(always)]
869                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
870                                where
871                                    #inner_ty: Clone + std::hash::Hash + Eq + 'static,
872                                {
873                                    rust_key_paths::Kp::new(
874                                        Box::new(move |root: &#name| root.#field_ident.get(&key)),
875                                        Box::new(move |_root: &mut #name| None),
876                                    )
877                                }
878                            });
879                        }
880                        (WrapperKind::BTreeSet, Some(inner_ty)) => {
881                            let kp_at_fn = format_ident!("{}_at", field_ident);
882
883                            tokens.extend(quote! {
884                                #[inline(always)]
885                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
886                                    rust_key_paths::Kp::new(
887                                        |root: &#name| Some(&root.#field_ident),
888                                        |root: &mut #name| Some(&mut root.#field_ident),
889                                    )
890                                }
891
892                                /// _at: check if element exists and get reference.
893                                /// BTreeSet does not allow mutable element access (would break ordering invariant).
894                                #[inline(always)]
895                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
896                                where
897                                    #inner_ty: Clone + Ord + 'static,
898                                {
899                                    rust_key_paths::Kp::new(
900                                        Box::new(move |root: &#name| root.#field_ident.get(&key)),
901                                        Box::new(move |_root: &mut #name| None),
902                                    )
903                                }
904                            });
905                        }
906                        (WrapperKind::VecDeque, Some(inner_ty)) => {
907                            tokens.extend(quote! {
908                                #[inline(always)]
909                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
910                                    rust_key_paths::Kp::new(
911                                        |root: &#name| Some(&root.#field_ident),
912                                        |root: &mut #name| Some(&mut root.#field_ident),
913                                    )
914                                }
915                                #[inline(always)]
916                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
917                                    rust_key_paths::Kp::new(
918                                        Box::new(move |root: &#name| root.#field_ident.get(index)),
919                                        Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
920                                    )
921                                }
922                            });
923                        }
924                        (WrapperKind::LinkedList, Some(_inner_ty)) => {
925                            tokens.extend(quote! {
926                                #[inline(always)]
927                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
928                                    rust_key_paths::Kp::new(
929                                        |root: &#name| Some(&root.#field_ident),
930                                        |root: &mut #name| Some(&mut root.#field_ident),
931                                    )
932                                }
933                            });
934                        }
935                        (WrapperKind::BinaryHeap, Some(_inner_ty)) => {
936                            tokens.extend(quote! {
937                                #[inline(always)]
938                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
939                                    rust_key_paths::Kp::new(
940                                        |root: &#name| Some(&root.#field_ident),
941                                        |root: &mut #name| Some(&mut root.#field_ident),
942                                    )
943                                }
944                            });
945                        }
946                        (WrapperKind::Result, Some(inner_ty)) => {
947                            // For Result<T, E>, access Ok value
948                            tokens.extend(quote! {
949                                #[inline(always)]
950                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
951                                    rust_key_paths::Kp::new(
952                                        |root: &#name| root.#field_ident.as_ref().ok(),
953                                        |root: &mut #name| root.#field_ident.as_mut().ok(),
954                                    )
955                                }
956                            });
957                        }
958                        (WrapperKind::StdArcMutex, Some(inner_ty)) => {
959                            // For Arc<std::sync::Mutex<T>>
960                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
961                            tokens.extend(quote! {
962                                #[inline(always)]
963                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
964                                    rust_key_paths::Kp::new(
965                                        |root: &#name| Some(&root.#field_ident),
966                                        |root: &mut #name| Some(&mut root.#field_ident),
967                                    )
968                                }
969                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #ty, #inner_ty> {
970                                    rust_key_paths::lock::LockKp::new(
971                                        rust_key_paths::Kp::new(
972                                            |root: &#name| Some(&root.#field_ident),
973                                            |root: &mut #name| Some(&mut root.#field_ident),
974                                        ),
975                                        rust_key_paths::lock::ArcMutexAccess::new(),
976                                        rust_key_paths::Kp::new(
977                                            |v: &#inner_ty| Some(v),
978                                            |v: &mut #inner_ty| Some(v),
979                                        ),
980                                    )
981                                }
982                            });
983                        }
984                        (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
985                            // For Arc<std::sync::RwLock<T>>
986                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
987                            tokens.extend(quote! {
988                                #[inline(always)]
989                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
990                                    rust_key_paths::Kp::new(
991                                        |root: &#name| Some(&root.#field_ident),
992                                        |root: &mut #name| Some(&mut root.#field_ident),
993                                    )
994                                }
995                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #ty, #inner_ty> {
996                                    rust_key_paths::lock::LockKp::new(
997                                        rust_key_paths::Kp::new(
998                                            |root: &#name| Some(&root.#field_ident),
999                                            |root: &mut #name| Some(&mut root.#field_ident),
1000                                        ),
1001                                        rust_key_paths::lock::ArcRwLockAccess::new(),
1002                                        rust_key_paths::Kp::new(
1003                                            |v: &#inner_ty| Some(v),
1004                                            |v: &mut #inner_ty| Some(v),
1005                                        ),
1006                                    )
1007                                }
1008                            });
1009                        }
1010                        (WrapperKind::ArcRwLock, Some(inner_ty)) => {
1011                            // For Arc<parking_lot::RwLock<T>> (requires rust-key-paths "parking_lot" feature)
1012                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
1013                            tokens.extend(quote! {
1014                                #[inline(always)]
1015                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1016                                    rust_key_paths::Kp::new(
1017                                        |root: &#name| Some(&root.#field_ident),
1018                                        |root: &mut #name| Some(&mut root.#field_ident),
1019                                    )
1020                                }
1021                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #ty, #inner_ty> {
1022                                    rust_key_paths::lock::LockKp::new(
1023                                        rust_key_paths::Kp::new(
1024                                            |root: &#name| Some(&root.#field_ident),
1025                                            |root: &mut #name| Some(&mut root.#field_ident),
1026                                        ),
1027                                        rust_key_paths::lock::ParkingLotRwLockAccess::new(),
1028                                        rust_key_paths::Kp::new(
1029                                            |v: &#inner_ty| Some(v),
1030                                            |v: &mut #inner_ty| Some(v),
1031                                        ),
1032                                    )
1033                                }
1034                            });
1035                        }
1036                        (WrapperKind::ArcMutex, Some(inner_ty)) => {
1037                            // For Arc<parking_lot::Mutex<T>> (requires rust-key-paths "parking_lot" feature)
1038                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
1039                            tokens.extend(quote! {
1040                                #[inline(always)]
1041                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1042                                    rust_key_paths::Kp::new(
1043                                        |root: &#name| Some(&root.#field_ident),
1044                                        |root: &mut #name| Some(&mut root.#field_ident),
1045                                    )
1046                                }
1047                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #ty, #inner_ty> {
1048                                    rust_key_paths::lock::LockKp::new(
1049                                        rust_key_paths::Kp::new(
1050                                            |root: &#name| Some(&root.#field_ident),
1051                                            |root: &mut #name| Some(&mut root.#field_ident),
1052                                        ),
1053                                        rust_key_paths::lock::ParkingLotMutexAccess::new(),
1054                                        rust_key_paths::Kp::new(
1055                                            |v: &#inner_ty| Some(v),
1056                                            |v: &mut #inner_ty| Some(v),
1057                                        ),
1058                                    )
1059                                }
1060                            });
1061                        }
1062                        (WrapperKind::Mutex, Some(_inner_ty))
1063                        | (WrapperKind::StdMutex, Some(_inner_ty)) => {
1064                            // For Mutex<T>, return keypath to container
1065                            tokens.extend(quote! {
1066                                #[inline(always)]
1067                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1068                                    rust_key_paths::Kp::new(
1069                                        |root: &#name| Some(&root.#field_ident),
1070                                        |root: &mut #name| Some(&mut root.#field_ident),
1071                                    )
1072                                }
1073                            });
1074                        }
1075                        (WrapperKind::RwLock, Some(_inner_ty))
1076                        | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
1077                            // For RwLock<T>, return keypath to container
1078                            tokens.extend(quote! {
1079                                #[inline(always)]
1080                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1081                                    rust_key_paths::Kp::new(
1082                                        |root: &#name| Some(&root.#field_ident),
1083                                        |root: &mut #name| Some(&mut root.#field_ident),
1084                                    )
1085                                }
1086                            });
1087                        }
1088                        (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
1089                            let kp_async_fn = format_ident!("{}_async", field_ident);
1090                            tokens.extend(quote! {
1091                                #[inline(always)]
1092                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1093                                    rust_key_paths::Kp::new(
1094                                        |root: &#name| Some(&root.#field_ident),
1095                                        |root: &mut #name| Some(&mut root.#field_ident),
1096                                    )
1097                                }
1098                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
1099                                    rust_key_paths::async_lock::AsyncLockKp::new(
1100                                        rust_key_paths::Kp::new(
1101                                            |root: &#name| Some(&root.#field_ident),
1102                                            |root: &mut #name| Some(&mut root.#field_ident),
1103                                        ),
1104                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
1105                                        rust_key_paths::Kp::new(
1106                                            |v: &#inner_ty| Some(v),
1107                                            |v: &mut #inner_ty| Some(v),
1108                                        ),
1109                                    )
1110                                }
1111                            });
1112                        }
1113                        (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
1114                            let kp_async_fn = format_ident!("{}_async", field_ident);
1115                            tokens.extend(quote! {
1116                                #[inline(always)]
1117                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1118                                    rust_key_paths::Kp::new(
1119                                        |root: &#name| Some(&root.#field_ident),
1120                                        |root: &mut #name| Some(&mut root.#field_ident),
1121                                    )
1122                                }
1123                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
1124                                    rust_key_paths::async_lock::AsyncLockKp::new(
1125                                        rust_key_paths::Kp::new(
1126                                            |root: &#name| Some(&root.#field_ident),
1127                                            |root: &mut #name| Some(&mut root.#field_ident),
1128                                        ),
1129                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
1130                                        rust_key_paths::Kp::new(
1131                                            |v: &#inner_ty| Some(v),
1132                                            |v: &mut #inner_ty| Some(v),
1133                                        ),
1134                                    )
1135                                }
1136                            });
1137                        }
1138                        (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
1139                            let kp_async_fn = format_ident!("{}_async", field_ident);
1140                            tokens.extend(quote! {
1141                                #[inline(always)]
1142                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1143                                    rust_key_paths::Kp::new(
1144                                        |root: &#name| Some(&root.#field_ident),
1145                                        |root: &mut #name| Some(&mut root.#field_ident),
1146                                    )
1147                                }
1148                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
1149                                    rust_key_paths::async_lock::AsyncLockKp::new(
1150                                        rust_key_paths::Kp::new(
1151                                            |root: &#name| root.#field_ident.as_ref(),
1152                                            |root: &mut #name| root.#field_ident.as_mut(),
1153                                        ),
1154                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
1155                                        rust_key_paths::Kp::new(
1156                                            |v: &#inner_ty| Some(v),
1157                                            |v: &mut #inner_ty| Some(v),
1158                                        ),
1159                                    )
1160                                }
1161                            });
1162                        }
1163                        (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
1164                            let kp_async_fn = format_ident!("{}_async", field_ident);
1165                            tokens.extend(quote! {
1166                                #[inline(always)]
1167                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1168                                    rust_key_paths::Kp::new(
1169                                        |root: &#name| Some(&root.#field_ident),
1170                                        |root: &mut #name| Some(&mut root.#field_ident),
1171                                    )
1172                                }
1173                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
1174                                    rust_key_paths::async_lock::AsyncLockKp::new(
1175                                        rust_key_paths::Kp::new(
1176                                            |root: &#name| root.#field_ident.as_ref(),
1177                                            |root: &mut #name| root.#field_ident.as_mut(),
1178                                        ),
1179                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
1180                                        rust_key_paths::Kp::new(
1181                                            |v: &#inner_ty| Some(v),
1182                                            |v: &mut #inner_ty| Some(v),
1183                                        ),
1184                                    )
1185                                }
1186                            });
1187                        }
1188                        (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
1189                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1190                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
1191                            tokens.extend(quote! {
1192                                #[inline(always)]
1193                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1194                                    rust_key_paths::Kp::new(
1195                                        |root: &#name| Some(&root.#field_ident),
1196                                        |root: &mut #name| Some(&mut root.#field_ident),
1197                                    )
1198                                }
1199                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
1200                                    rust_key_paths::Kp::new(
1201                                        |root: &#name| root.#field_ident.as_ref(),
1202                                        |root: &mut #name| root.#field_ident.as_mut(),
1203                                    )
1204                                }
1205                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
1206                                    rust_key_paths::lock::LockKp::new(
1207                                        rust_key_paths::Kp::new(
1208                                            |root: &#name| root.#field_ident.as_ref(),
1209                                            |root: &mut #name| root.#field_ident.as_mut(),
1210                                        ),
1211                                        rust_key_paths::lock::ArcMutexAccess::new(),
1212                                        rust_key_paths::Kp::new(
1213                                            |v: &#inner_ty| Some(v),
1214                                            |v: &mut #inner_ty| Some(v),
1215                                        ),
1216                                    )
1217                                }
1218                            });
1219                        }
1220                        (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
1221                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1222                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
1223                            tokens.extend(quote! {
1224                                #[inline(always)]
1225                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1226                                    rust_key_paths::Kp::new(
1227                                        |root: &#name| Some(&root.#field_ident),
1228                                        |root: &mut #name| Some(&mut root.#field_ident),
1229                                    )
1230                                }
1231                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
1232                                    rust_key_paths::Kp::new(
1233                                        |root: &#name| root.#field_ident.as_ref(),
1234                                        |root: &mut #name| root.#field_ident.as_mut(),
1235                                    )
1236                                }
1237                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>, #inner_ty> {
1238                                    rust_key_paths::lock::LockKp::new(
1239                                        rust_key_paths::Kp::new(
1240                                            |root: &#name| root.#field_ident.as_ref(),
1241                                            |root: &mut #name| root.#field_ident.as_mut(),
1242                                        ),
1243                                        rust_key_paths::lock::ParkingLotMutexAccess::new(),
1244                                        rust_key_paths::Kp::new(
1245                                            |v: &#inner_ty| Some(v),
1246                                            |v: &mut #inner_ty| Some(v),
1247                                        ),
1248                                    )
1249                                }
1250                            });
1251                        }
1252                        (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
1253                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1254                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
1255                            tokens.extend(quote! {
1256                                #[inline(always)]
1257                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1258                                    rust_key_paths::Kp::new(
1259                                        |root: &#name| Some(&root.#field_ident),
1260                                        |root: &mut #name| Some(&mut root.#field_ident),
1261                                    )
1262                                }
1263                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
1264                                    rust_key_paths::Kp::new(
1265                                        |root: &#name| root.#field_ident.as_ref(),
1266                                        |root: &mut #name| root.#field_ident.as_mut(),
1267                                    )
1268                                }
1269                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
1270                                    rust_key_paths::lock::LockKp::new(
1271                                        rust_key_paths::Kp::new(
1272                                            |root: &#name| root.#field_ident.as_ref(),
1273                                            |root: &mut #name| root.#field_ident.as_mut(),
1274                                        ),
1275                                        rust_key_paths::lock::ArcRwLockAccess::new(),
1276                                        rust_key_paths::Kp::new(
1277                                            |v: &#inner_ty| Some(v),
1278                                            |v: &mut #inner_ty| Some(v),
1279                                        ),
1280                                    )
1281                                }
1282                            });
1283                        }
1284                        (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
1285                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1286                            let kp_lock_fn = format_ident!("{}_lock", field_ident);
1287                            tokens.extend(quote! {
1288                                #[inline(always)]
1289                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1290                                    rust_key_paths::Kp::new(
1291                                        |root: &#name| Some(&root.#field_ident),
1292                                        |root: &mut #name| Some(&mut root.#field_ident),
1293                                    )
1294                                }
1295                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
1296                                    rust_key_paths::Kp::new(
1297                                        |root: &#name| root.#field_ident.as_ref(),
1298                                        |root: &mut #name| root.#field_ident.as_mut(),
1299                                    )
1300                                }
1301                                pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>, #inner_ty> {
1302                                    rust_key_paths::lock::LockKp::new(
1303                                        rust_key_paths::Kp::new(
1304                                            |root: &#name| root.#field_ident.as_ref(),
1305                                            |root: &mut #name| root.#field_ident.as_mut(),
1306                                        ),
1307                                        rust_key_paths::lock::ParkingLotRwLockAccess::new(),
1308                                        rust_key_paths::Kp::new(
1309                                            |v: &#inner_ty| Some(v),
1310                                            |v: &mut #inner_ty| Some(v),
1311                                        ),
1312                                    )
1313                                }
1314                            });
1315                        }
1316                        (WrapperKind::OptionStdMutex, Some(inner_ty))
1317                        | (WrapperKind::OptionMutex, Some(inner_ty)) => {
1318                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1319                            tokens.extend(quote! {
1320                                #[inline(always)]
1321                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1322                                    rust_key_paths::Kp::new(
1323                                        |root: &#name| Some(&root.#field_ident),
1324                                        |root: &mut #name| Some(&mut root.#field_ident),
1325                                    )
1326                                }
1327                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
1328                                    rust_key_paths::Kp::new(
1329                                        |root: &#name| root.#field_ident.as_ref(),
1330                                        |root: &mut #name| root.#field_ident.as_mut(),
1331                                    )
1332                                }
1333                            });
1334                        }
1335                        (WrapperKind::OptionStdRwLock, Some(inner_ty))
1336                        | (WrapperKind::OptionRwLock, Some(inner_ty)) => {
1337                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1338                            tokens.extend(quote! {
1339                                #[inline(always)]
1340                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1341                                    rust_key_paths::Kp::new(
1342                                        |root: &#name| Some(&root.#field_ident),
1343                                        |root: &mut #name| Some(&mut root.#field_ident),
1344                                    )
1345                                }
1346                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
1347                                    rust_key_paths::Kp::new(
1348                                        |root: &#name| root.#field_ident.as_ref(),
1349                                        |root: &mut #name| root.#field_ident.as_mut(),
1350                                    )
1351                                }
1352                            });
1353                        }
1354                        (WrapperKind::Weak, Some(_inner_ty)) => {
1355                            // For Weak<T>, return keypath to container
1356                            tokens.extend(quote! {
1357                                #[inline(always)]
1358                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1359                                    rust_key_paths::Kp::new(
1360                                        |root: &#name| Some(&root.#field_ident),
1361                                        |_root: &mut #name| None, // Weak doesn't support mutable access
1362                                    )
1363                                }
1364                            });
1365                        }
1366                        (WrapperKind::Atomic, None | Some(_)) => {
1367                            // For atomic types: return keypath to the atomic (user calls .load()/.store())
1368                            tokens.extend(quote! {
1369                                #[inline(always)]
1370                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1371                                    rust_key_paths::Kp::new(
1372                                        |root: &#name| Some(&root.#field_ident),
1373                                        |root: &mut #name| Some(&mut root.#field_ident),
1374                                    )
1375                                }
1376                            });
1377                        }
1378                        (WrapperKind::OptionAtomic, Some(inner_ty)) => {
1379                            tokens.extend(quote! {
1380                                #[inline(always)]
1381                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1382                                    rust_key_paths::Kp::new(
1383                                        |root: &#name| root.#field_ident.as_ref(),
1384                                        |root: &mut #name| root.#field_ident.as_mut(),
1385                                    )
1386                                }
1387                            });
1388                        }
1389                        (WrapperKind::Reference, Some(_inner_ty)) => {
1390                            // For reference types (&T, &str, &[T]): read-only, setter returns None
1391                            tokens.extend(quote! {
1392                                #[inline(always)]
1393                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1394                                    rust_key_paths::Kp::new(
1395                                        |root: &#name| Some(&root.#field_ident),
1396                                        |_root: &mut #name| None, // references: read-only
1397                                    )
1398                                }
1399                            });
1400                        }
1401                        (WrapperKind::None, None) => {
1402                            // For basic types, direct access
1403                            tokens.extend(quote! {
1404                                #[inline(always)]
1405                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1406                                    rust_key_paths::Kp::new(
1407                                        |root: &#name| Some(&root.#field_ident),
1408                                        |root: &mut #name| Some(&mut root.#field_ident),
1409                                    )
1410                                }
1411                            });
1412                        }
1413                        _ => {
1414                            // For unknown/complex nested types, return keypath to field itself
1415                            tokens.extend(quote! {
1416                                #[inline(always)]
1417                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1418                            rust_key_paths::Kp::new(
1419                                |root: &#name| Some(&root.#field_ident),
1420                                |root: &mut #name| Some(&mut root.#field_ident),
1421                            )
1422                        }
1423                            });
1424                        }
1425                    }
1426                }
1427                
1428                tokens
1429            }
1430            Fields::Unnamed(unnamed) => {
1431                let mut tokens = proc_macro2::TokenStream::new();
1432
1433                // Generate identity methods for the tuple struct
1434                tokens.extend(quote! {
1435                    /// Returns a generic identity keypath for this type
1436                    #[inline(always)]
1437                    pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
1438                        #name,
1439                        #name,
1440                        Root,
1441                        Root,
1442                        MutRoot,
1443                        MutRoot,
1444                        fn(Root) -> Option<Root>,
1445                        fn(MutRoot) -> Option<MutRoot>,
1446                    >
1447                    where
1448                        Root: std::borrow::Borrow<#name>,
1449                        MutRoot: std::borrow::BorrowMut<#name>,
1450                    {
1451                        rust_key_paths::Kp::new(
1452                            |r: Root| Some(r),
1453                            |r: MutRoot| Some(r)
1454                        )
1455                    }
1456
1457                    /// Returns a simple identity keypath for this type
1458                    #[inline(always)]
1459                    pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
1460                        rust_key_paths::Kp::new(
1461                            |r: &#name| Some(r),
1462                            |r: &mut #name| Some(r)
1463                        )
1464                    }
1465                });
1466
1467                for (idx, field) in unnamed.unnamed.iter().enumerate() {
1468                    let idx_lit = syn::Index::from(idx);
1469                    let ty = &field.ty;
1470                    // Centralized keypath method names for tuple fields – change here to adjust for all types
1471                    let kp_fn = format_ident!("f{}", idx);
1472                    let kp_at_fn = format_ident!("f{}_at", idx);
1473
1474                    let (kind, inner_ty) = extract_wrapper_inner_type(ty);
1475
1476                    match (kind, inner_ty.clone()) {
1477                        (WrapperKind::Option, Some(inner_ty)) => {
1478                            tokens.extend(quote! {
1479                                #[inline(always)]
1480                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #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::Vec, Some(inner_ty)) => {
1489                            tokens.extend(quote! {
1490                                #[inline(always)]
1491                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1492                                    rust_key_paths::Kp::new(
1493                                        |root: &#name| Some(&root.#idx_lit),
1494                                        |root: &mut #name| Some(&mut root.#idx_lit),
1495                                    )
1496                                }
1497                                #[inline(always)]
1498                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1499                                    rust_key_paths::Kp::new(
1500                                        Box::new(move |root: &#name| root.#idx_lit.get(index)),
1501                                        Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
1502                                    )
1503                                }
1504                            });
1505                        }
1506                        (WrapperKind::HashMap, Some(inner_ty)) => {
1507                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
1508                                tokens.extend(quote! {
1509                                    #[inline(always)]
1510                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1511                                        rust_key_paths::Kp::new(
1512                                            |root: &#name| Some(&root.#idx_lit),
1513                                            |root: &mut #name| Some(&mut root.#idx_lit),
1514                                        )
1515                                    }
1516                                    #[inline(always)]
1517                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1518                                    where
1519                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
1520                                    {
1521                                        let key2 = key.clone();
1522                                        rust_key_paths::Kp::new(
1523                                            Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1524                                            Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
1525                                        )
1526                                    }
1527                                });
1528                            } else {
1529                                tokens.extend(quote! {
1530                                    #[inline(always)]
1531                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1532                                        rust_key_paths::Kp::new(
1533                                            |root: &#name| Some(&root.#idx_lit),
1534                                            |root: &mut #name| Some(&mut root.#idx_lit),
1535                                        )
1536                                    }
1537                                });
1538                            }
1539                        }
1540                        (WrapperKind::BTreeMap, Some(inner_ty)) => {
1541                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
1542                                tokens.extend(quote! {
1543                                    #[inline(always)]
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                                    #[inline(always)]
1551                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1552                                    where
1553                                        #key_ty: Clone + Ord + 'static,
1554                                    {
1555                                        let key2 = key.clone();
1556                                        rust_key_paths::Kp::new(
1557                                            Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1558                                            Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
1559                                        )
1560                                    }
1561                                });
1562                            } else {
1563                                tokens.extend(quote! {
1564                                    #[inline(always)]
1565                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1566                                        rust_key_paths::Kp::new(
1567                                            |root: &#name| Some(&root.#idx_lit),
1568                                            |root: &mut #name| Some(&mut root.#idx_lit),
1569                                        )
1570                                    }
1571                                });
1572                            }
1573                        }
1574                        (WrapperKind::Box, Some(inner_ty)) => {
1575                            // Box: deref to inner (returns &T / &mut T)
1576                            tokens.extend(quote! {
1577                                #[inline(always)]
1578                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1579                                    rust_key_paths::Kp::new(
1580                                        |root: &#name| Some(&*root.#idx_lit),
1581                                        |root: &mut #name| Some(&mut *root.#idx_lit),
1582                                    )
1583                                }
1584                            });
1585                        }
1586                        (WrapperKind::Pin, Some(inner_ty)) => {
1587                            let kp_inner_fn = format_ident!("{}_inner", kp_fn);
1588                            tokens.extend(quote! {
1589                                #[inline(always)]
1590                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1591                                    rust_key_paths::Kp::new(
1592                                        |root: &#name| Some(&root.#idx_lit),
1593                                        |root: &mut #name| Some(&mut root.#idx_lit),
1594                                    )
1595                                }
1596                                #[inline(always)]
1597                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
1598                                where #inner_ty: std::marker::Unpin
1599                                {
1600                                    rust_key_paths::Kp::new(
1601                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#idx_lit).get_ref()),
1602                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#idx_lit).get_mut()),
1603                                    )
1604                                }
1605                            });
1606                        }
1607                        (WrapperKind::PinBox, Some(inner_ty)) => {
1608                            let kp_inner_fn = format_ident!("{}_inner", kp_fn);
1609                            tokens.extend(quote! {
1610                                #[inline(always)]
1611                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1612                                    rust_key_paths::Kp::new(
1613                                        |root: &#name| Some(&root.#idx_lit),
1614                                        |root: &mut #name| Some(&mut root.#idx_lit),
1615                                    )
1616                                }
1617                                #[inline(always)]
1618                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
1619                                where #inner_ty: std::marker::Unpin
1620                                {
1621                                    rust_key_paths::Kp::new(
1622                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#idx_lit).get_ref()),
1623                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#idx_lit).get_mut()),
1624                                    )
1625                                }
1626                            });
1627                        }
1628                        (WrapperKind::Rc, Some(inner_ty)) => {
1629                            tokens.extend(quote! {
1630                                #[inline(always)]
1631                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1632                                    rust_key_paths::Kp::new(
1633                                        |root: &#name| Some(root.#idx_lit.as_ref()),
1634                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#idx_lit),
1635                                    )
1636                                }
1637                            });
1638                        }
1639                        (WrapperKind::Arc, Some(inner_ty)) => {
1640                            tokens.extend(quote! {
1641                                #[inline(always)]
1642                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1643                                    rust_key_paths::Kp::new(
1644                                        |root: &#name| Some(root.#idx_lit.as_ref()),
1645                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#idx_lit),
1646                                    )
1647                                }
1648                            });
1649                        }
1650                        
1651                        (WrapperKind::Cow, Some(inner_ty)) => {
1652                            tokens.extend(quote! {
1653                                #[inline(always)]
1654                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1655                                    rust_key_paths::Kp::new(
1656                                        |root: &#name| Some(root.#idx_lit.as_ref()),
1657                                        |root: &mut #name| Some(root.#idx_lit.to_mut()),
1658                                    )
1659                                }
1660                            });
1661                        }
1662                        
1663                        (WrapperKind::OptionCow, Some(inner_ty)) => {
1664                            tokens.extend(quote! {
1665                                #[inline(always)]
1666                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1667                                    rust_key_paths::Kp::new(
1668                                        |root: &#name| root.#idx_lit.as_ref().map(|c| c.as_ref()),
1669                                        |root: &mut #name| root.#idx_lit.as_mut().map(|c| c.to_mut()),
1670                                    )
1671                                }
1672                            });
1673                        }
1674                        (WrapperKind::OptionTagged, Some(inner_ty)) => {
1675                            tokens.extend(quote! {
1676                                #[inline(always)]
1677                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1678                                    rust_key_paths::Kp::new(
1679                                        |root: &#name| root.#idx_lit.as_ref().map(|t| std::ops::Deref::deref(t)),
1680                                        |root: &mut #name| root.#idx_lit.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
1681                                    )
1682                                }
1683                            });
1684                        }
1685                        (WrapperKind::OptionReference, Some(inner_ty)) => {
1686                            tokens.extend(quote! {
1687                                #[inline(always)]
1688                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1689                                    rust_key_paths::Kp::new(
1690                                        |root: &#name| root.#idx_lit.as_ref(),
1691                                        |_root: &mut #name| None,
1692                                    )
1693                                }
1694                            });
1695                        }
1696                        (WrapperKind::HashSet, Some(inner_ty)) => {
1697                            let kp_at_fn = format_ident!("f{}_at", idx);
1698
1699                            tokens.extend(quote! {
1700                                #[inline(always)]
1701                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1702                                    rust_key_paths::Kp::new(
1703                                        |root: &#name| Some(&root.#idx_lit),
1704                                        |root: &mut #name| Some(&mut root.#idx_lit),
1705                                    )
1706                                }
1707
1708                                /// _at: check if element exists and get reference.
1709                                /// HashSet does not allow mutable element access (would break hash invariant).
1710                                #[inline(always)]
1711                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1712                                where
1713                                    #inner_ty: Clone + std::hash::Hash + Eq + 'static,
1714                                {
1715                                    rust_key_paths::Kp::new(
1716                                        Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1717                                        Box::new(move |_root: &mut #name| None),
1718                                    )
1719                                }
1720                            });
1721                        }
1722                        (WrapperKind::BTreeSet, Some(inner_ty)) => {
1723                            let kp_at_fn = format_ident!("f{}_at", idx);
1724
1725                            tokens.extend(quote! {
1726                                #[inline(always)]
1727                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1728                                    rust_key_paths::Kp::new(
1729                                        |root: &#name| Some(&root.#idx_lit),
1730                                        |root: &mut #name| Some(&mut root.#idx_lit),
1731                                    )
1732                                }
1733
1734                                /// _at: check if element exists and get reference.
1735                                /// BTreeSet does not allow mutable element access (would break ordering invariant).
1736                                #[inline(always)]
1737                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1738                                where
1739                                    #inner_ty: Clone + Ord + 'static,
1740                                {
1741                                    rust_key_paths::Kp::new(
1742                                        Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1743                                        Box::new(move |_root: &mut #name| None),
1744                                    )
1745                                }
1746                            });
1747                        }
1748                        (WrapperKind::VecDeque, Some(inner_ty)) => {
1749                            tokens.extend(quote! {
1750                                #[inline(always)]
1751                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1752                                    rust_key_paths::Kp::new(
1753                                        |root: &#name| Some(&root.#idx_lit),
1754                                        |root: &mut #name| Some(&mut root.#idx_lit),
1755                                    )
1756                                }
1757                                #[inline(always)]
1758                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1759                                    rust_key_paths::Kp::new(
1760                                        Box::new(move |root: &#name| root.#idx_lit.get(index)),
1761                                        Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
1762                                    )
1763                                }
1764                            });
1765                        }
1766                        (WrapperKind::LinkedList, Some(_inner_ty)) => {
1767                            tokens.extend(quote! {
1768                                #[inline(always)]
1769                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1770                                    rust_key_paths::Kp::new(
1771                                        |root: &#name| Some(&root.#idx_lit),
1772                                        |root: &mut #name| Some(&mut root.#idx_lit),
1773                                    )
1774                                }
1775                            });
1776                        }
1777                        (WrapperKind::BinaryHeap, Some(_inner_ty)) => {
1778                            tokens.extend(quote! {
1779                                #[inline(always)]
1780                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1781                                    rust_key_paths::Kp::new(
1782                                        |root: &#name| Some(&root.#idx_lit),
1783                                        |root: &mut #name| Some(&mut root.#idx_lit),
1784                                    )
1785                                }
1786                            });
1787                        }
1788                        (WrapperKind::Result, Some(inner_ty)) => {
1789                            tokens.extend(quote! {
1790                                #[inline(always)]
1791                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1792                                    rust_key_paths::Kp::new(
1793                                        |root: &#name| root.#idx_lit.as_ref().ok(),
1794                                        |root: &mut #name| root.#idx_lit.as_mut().ok(),
1795                                    )
1796                                }
1797                            });
1798                        }
1799                        (WrapperKind::Mutex, Some(_inner_ty))
1800                        | (WrapperKind::StdMutex, Some(_inner_ty)) => {
1801                            tokens.extend(quote! {
1802                                #[inline(always)]
1803                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1804                                    rust_key_paths::Kp::new(
1805                                        |root: &#name| Some(&root.#idx_lit),
1806                                        |root: &mut #name| Some(&mut root.#idx_lit),
1807                                    )
1808                                }
1809                            });
1810                        }
1811                        (WrapperKind::RwLock, Some(_inner_ty))
1812                        | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
1813                            tokens.extend(quote! {
1814                                #[inline(always)]
1815                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1816                                    rust_key_paths::Kp::new(
1817                                        |root: &#name| Some(&root.#idx_lit),
1818                                        |root: &mut #name| Some(&mut root.#idx_lit),
1819                                    )
1820                                }
1821                            });
1822                        }
1823                        (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
1824                            let kp_async_fn = format_ident!("f{}_async", idx);
1825                            tokens.extend(quote! {
1826                                #[inline(always)]
1827                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1828                                    rust_key_paths::Kp::new(
1829                                        |root: &#name| Some(&root.#idx_lit),
1830                                        |root: &mut #name| Some(&mut root.#idx_lit),
1831                                    )
1832                                }
1833                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
1834                                    rust_key_paths::async_lock::AsyncLockKp::new(
1835                                        rust_key_paths::Kp::new(
1836                                            |root: &#name| Some(&root.#idx_lit),
1837                                            |root: &mut #name| Some(&mut root.#idx_lit),
1838                                        ),
1839                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
1840                                        rust_key_paths::Kp::new(
1841                                            |v: &#inner_ty| Some(v),
1842                                            |v: &mut #inner_ty| Some(v),
1843                                        ),
1844                                    )
1845                                }
1846                            });
1847                        }
1848                        (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
1849                            let kp_async_fn = format_ident!("f{}_async", idx);
1850                            tokens.extend(quote! {
1851                                #[inline(always)]
1852                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1853                                    rust_key_paths::Kp::new(
1854                                        |root: &#name| Some(&root.#idx_lit),
1855                                        |root: &mut #name| Some(&mut root.#idx_lit),
1856                                    )
1857                                }
1858                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
1859                                    rust_key_paths::async_lock::AsyncLockKp::new(
1860                                        rust_key_paths::Kp::new(
1861                                            |root: &#name| Some(&root.#idx_lit),
1862                                            |root: &mut #name| Some(&mut root.#idx_lit),
1863                                        ),
1864                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
1865                                        rust_key_paths::Kp::new(
1866                                            |v: &#inner_ty| Some(v),
1867                                            |v: &mut #inner_ty| Some(v),
1868                                        ),
1869                                    )
1870                                }
1871                            });
1872                        }
1873                        (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
1874                            let kp_async_fn = format_ident!("f{}_async", idx);
1875                            tokens.extend(quote! {
1876                                #[inline(always)]
1877                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1878                                    rust_key_paths::Kp::new(
1879                                        |root: &#name| Some(&root.#idx_lit),
1880                                        |root: &mut #name| Some(&mut root.#idx_lit),
1881                                    )
1882                                }
1883                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
1884                                    rust_key_paths::async_lock::AsyncLockKp::new(
1885                                        rust_key_paths::Kp::new(
1886                                            |root: &#name| root.#idx_lit.as_ref(),
1887                                            |root: &mut #name| root.#idx_lit.as_mut(),
1888                                        ),
1889                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
1890                                        rust_key_paths::Kp::new(
1891                                            |v: &#inner_ty| Some(v),
1892                                            |v: &mut #inner_ty| Some(v),
1893                                        ),
1894                                    )
1895                                }
1896                            });
1897                        }
1898                        (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
1899                            let kp_async_fn = format_ident!("f{}_async", idx);
1900                            tokens.extend(quote! {
1901                                #[inline(always)]
1902                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1903                                    rust_key_paths::Kp::new(
1904                                        |root: &#name| Some(&root.#idx_lit),
1905                                        |root: &mut #name| Some(&mut root.#idx_lit),
1906                                    )
1907                                }
1908                                pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
1909                                    rust_key_paths::async_lock::AsyncLockKp::new(
1910                                        rust_key_paths::Kp::new(
1911                                            |root: &#name| root.#idx_lit.as_ref(),
1912                                            |root: &mut #name| root.#idx_lit.as_mut(),
1913                                        ),
1914                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
1915                                        rust_key_paths::Kp::new(
1916                                            |v: &#inner_ty| Some(v),
1917                                            |v: &mut #inner_ty| Some(v),
1918                                        ),
1919                                    )
1920                                }
1921                            });
1922                        }
1923                        (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
1924                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1925                            tokens.extend(quote! {
1926                                #[inline(always)]
1927                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1928                                    rust_key_paths::Kp::new(
1929                                        |root: &#name| Some(&root.#idx_lit),
1930                                        |root: &mut #name| Some(&mut root.#idx_lit),
1931                                    )
1932                                }
1933                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
1934                                    rust_key_paths::Kp::new(
1935                                        |root: &#name| root.#idx_lit.as_ref(),
1936                                        |root: &mut #name| root.#idx_lit.as_mut(),
1937                                    )
1938                                }
1939                            });
1940                        }
1941                        (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
1942                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1943                            tokens.extend(quote! {
1944                                #[inline(always)]
1945                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1946                                    rust_key_paths::Kp::new(
1947                                        |root: &#name| Some(&root.#idx_lit),
1948                                        |root: &mut #name| Some(&mut root.#idx_lit),
1949                                    )
1950                                }
1951                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
1952                                    rust_key_paths::Kp::new(
1953                                        |root: &#name| root.#idx_lit.as_ref(),
1954                                        |root: &mut #name| root.#idx_lit.as_mut(),
1955                                    )
1956                                }
1957                            });
1958                        }
1959                        (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
1960                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1961                            tokens.extend(quote! {
1962                                #[inline(always)]
1963                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1964                                    rust_key_paths::Kp::new(
1965                                        |root: &#name| Some(&root.#idx_lit),
1966                                        |root: &mut #name| Some(&mut root.#idx_lit),
1967                                    )
1968                                }
1969                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
1970                                    rust_key_paths::Kp::new(
1971                                        |root: &#name| root.#idx_lit.as_ref(),
1972                                        |root: &mut #name| root.#idx_lit.as_mut(),
1973                                    )
1974                                }
1975                            });
1976                        }
1977                        (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
1978                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1979                            tokens.extend(quote! {
1980                                #[inline(always)]
1981                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1982                                    rust_key_paths::Kp::new(
1983                                        |root: &#name| Some(&root.#idx_lit),
1984                                        |root: &mut #name| Some(&mut root.#idx_lit),
1985                                    )
1986                                }
1987                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
1988                                    rust_key_paths::Kp::new(
1989                                        |root: &#name| root.#idx_lit.as_ref(),
1990                                        |root: &mut #name| root.#idx_lit.as_mut(),
1991                                    )
1992                                }
1993                            });
1994                        }
1995                        (WrapperKind::OptionStdMutex, Some(inner_ty))
1996                        | (WrapperKind::OptionMutex, Some(inner_ty)) => {
1997                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1998                            tokens.extend(quote! {
1999                                #[inline(always)]
2000                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2001                                    rust_key_paths::Kp::new(
2002                                        |root: &#name| Some(&root.#idx_lit),
2003                                        |root: &mut #name| Some(&mut root.#idx_lit),
2004                                    )
2005                                }
2006                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
2007                                    rust_key_paths::Kp::new(
2008                                        |root: &#name| root.#idx_lit.as_ref(),
2009                                        |root: &mut #name| root.#idx_lit.as_mut(),
2010                                    )
2011                                }
2012                            });
2013                        }
2014                        (WrapperKind::OptionStdRwLock, Some(inner_ty))
2015                        | (WrapperKind::OptionRwLock, Some(inner_ty)) => {
2016                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2017                            tokens.extend(quote! {
2018                                #[inline(always)]
2019                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2020                                    rust_key_paths::Kp::new(
2021                                        |root: &#name| Some(&root.#idx_lit),
2022                                        |root: &mut #name| Some(&mut root.#idx_lit),
2023                                    )
2024                                }
2025                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
2026                                    rust_key_paths::Kp::new(
2027                                        |root: &#name| root.#idx_lit.as_ref(),
2028                                        |root: &mut #name| root.#idx_lit.as_mut(),
2029                                    )
2030                                }
2031                            });
2032                        }
2033                        (WrapperKind::Weak, Some(_inner_ty)) => {
2034                            tokens.extend(quote! {
2035                                #[inline(always)]
2036                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2037                                    rust_key_paths::Kp::new(
2038                                        |root: &#name| Some(&root.#idx_lit),
2039                                        |_root: &mut #name| None,
2040                                    )
2041                                }
2042                            });
2043                        }
2044                        (WrapperKind::Atomic, None | Some(_)) => {
2045                            tokens.extend(quote! {
2046                                #[inline(always)]
2047                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2048                                    rust_key_paths::Kp::new(
2049                                        |root: &#name| Some(&root.#idx_lit),
2050                                        |root: &mut #name| Some(&mut root.#idx_lit),
2051                                    )
2052                                }
2053                            });
2054                        }
2055                        (WrapperKind::OptionAtomic, Some(inner_ty)) => {
2056                            tokens.extend(quote! {
2057                                #[inline(always)]
2058                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2059                                    rust_key_paths::Kp::new(
2060                                        |root: &#name| root.#idx_lit.as_ref(),
2061                                        |root: &mut #name| root.#idx_lit.as_mut(),
2062                                    )
2063                                }
2064                            });
2065                        }
2066                        (WrapperKind::Reference, Some(_inner_ty)) => {
2067                            tokens.extend(quote! {
2068                                #[inline(always)]
2069                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2070                                    rust_key_paths::Kp::new(
2071                                        |root: &#name| Some(&root.#idx_lit),
2072                                        |_root: &mut #name| None,
2073                                    )
2074                                }
2075                            });
2076                        }
2077                        (WrapperKind::None, None) => {
2078                            tokens.extend(quote! {
2079                                #[inline(always)]
2080                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2081                                    rust_key_paths::Kp::new(
2082                                        |root: &#name| Some(&root.#idx_lit),
2083                                        |root: &mut #name| Some(&mut root.#idx_lit),
2084                                    )
2085                                }
2086                            });
2087                        }
2088                        _ => {
2089                            tokens.extend(quote! {
2090                                #[inline(always)]
2091                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2092                                    rust_key_paths::Kp::new(
2093                                        |root: &#name| Some(&root.#idx_lit),
2094                                        |root: &mut #name| Some(&mut root.#idx_lit),
2095                                    )
2096                                }
2097                            });
2098                        }
2099                    }
2100                }
2101
2102                tokens
2103            }
2104            Fields::Unit => {
2105                return syn::Error::new(input_span, "Kp derive does not support unit structs")
2106                .to_compile_error()
2107                .into();
2108            }
2109        },
2110        Data::Enum(data_enum) => {
2111            let mut tokens = proc_macro2::TokenStream::new();
2112
2113            // Generate identity methods for the enum
2114            tokens.extend(quote! {
2115                /// Returns a generic identity keypath for this type
2116                #[inline(always)]
2117                pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
2118                    #name,
2119                    #name,
2120                    Root,
2121                    Root,
2122                    MutRoot,
2123                    MutRoot,
2124                    fn(Root) -> Option<Root>,
2125                    fn(MutRoot) -> Option<MutRoot>,
2126                >
2127                where
2128                    Root: std::borrow::Borrow<#name>,
2129                    MutRoot: std::borrow::BorrowMut<#name>,
2130                {
2131                    rust_key_paths::Kp::new(
2132                        |r: Root| Some(r),
2133                        |r: MutRoot| Some(r)
2134                    )
2135                }
2136
2137                /// Returns a simple identity keypath for this type
2138                #[inline(always)]
2139                pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
2140                    rust_key_paths::Kp::new(
2141                        |r: &#name| Some(r),
2142                        |r: &mut #name| Some(r)
2143                    )
2144                }
2145            });
2146
2147            for variant in data_enum.variants.iter() {
2148                let v_ident = &variant.ident;
2149                let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
2150
2151                match &variant.fields {
2152                    Fields::Unit => {
2153                        // Unit variant - return keypath that checks if enum matches variant
2154                        tokens.extend(quote! {
2155                            #[inline(always)]
2156                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, ()> {
2157                                rust_key_paths::Kp::new(
2158                                    |root: &#name| match root {
2159                                        #name::#v_ident => {
2160                                            static UNIT: () = ();
2161                                            Some(&UNIT)
2162                                        },
2163                                        _ => None,
2164                                    },
2165                                    |_root: &mut #name| None, // Can't mutate unit variant
2166                                )
2167                            }
2168                        });
2169                    }
2170                    Fields::Unnamed(unnamed) => {
2171                        if unnamed.unnamed.len() == 1 {
2172                            // Single-field tuple variant
2173                            let field_ty = &unnamed.unnamed[0].ty;
2174                            let (kind, inner_ty) = extract_wrapper_inner_type(field_ty);
2175
2176                            match (kind, inner_ty.clone()) {
2177                                (WrapperKind::Option, Some(inner_ty)) => {
2178                                    tokens.extend(quote! {
2179                                        #[inline(always)]
2180                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2181                                            rust_key_paths::Kp::new(
2182                                                |root: &#name| match root {
2183                                                    #name::#v_ident(inner) => inner.as_ref(),
2184                                                    _ => None,
2185                                                },
2186                                                |root: &mut #name| match root {
2187                                                    #name::#v_ident(inner) => inner.as_mut(),
2188                                                    _ => None,
2189                                                },
2190                                            )
2191                                        }
2192                                    });
2193                                }
2194                                (WrapperKind::Vec, Some(inner_ty)) => {
2195                                    tokens.extend(quote! {
2196                                        #[inline(always)]
2197                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2198                                            rust_key_paths::Kp::new(
2199                                                |root: &#name| match root {
2200                                                    #name::#v_ident(inner) => inner.first(),
2201                                                    _ => None,
2202                                                },
2203                                                |root: &mut #name| match root {
2204                                                    #name::#v_ident(inner) => inner.first_mut(),
2205                                                    _ => None,
2206                                                },
2207                                            )
2208                                        }
2209                                    });
2210                                }
2211                                (WrapperKind::Box, Some(inner_ty)) => {
2212                                    // Box in enum: deref to inner (&T / &mut T)
2213                                    tokens.extend(quote! {
2214                                        #[inline(always)]
2215                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2216                                            rust_key_paths::Kp::new(
2217                                                |root: &#name| match root {
2218                                                    #name::#v_ident(inner) => Some(&**inner),
2219                                                    _ => None,
2220                                                },
2221                                                |root: &mut #name| match root {
2222                                                    #name::#v_ident(inner) => Some(&mut **inner),
2223                                                    _ => None,
2224                                                },
2225                                            )
2226                                        }
2227                                    });
2228                                }
2229                                (WrapperKind::Pin, Some(inner_ty)) => {
2230                                    let snake_inner = format_ident!("{}_inner", snake);
2231                                    tokens.extend(quote! {
2232                                        #[inline(always)]
2233                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2234                                            rust_key_paths::Kp::new(
2235                                                |root: &#name| match root {
2236                                                    #name::#v_ident(inner) => Some(inner),
2237                                                    _ => None,
2238                                                },
2239                                                |root: &mut #name| match root {
2240                                                    #name::#v_ident(inner) => Some(inner),
2241                                                    _ => None,
2242                                                },
2243                                            )
2244                                        }
2245                                        #[inline(always)]
2246                                        pub fn #snake_inner() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2247                                        where #inner_ty: std::marker::Unpin
2248                                        {
2249                                            rust_key_paths::Kp::new(
2250                                                |root: &#name| match root {
2251                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_ref(inner).get_ref()),
2252                                                    _ => None,
2253                                                },
2254                                                |root: &mut #name| match root {
2255                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_mut(inner).get_mut()),
2256                                                    _ => None,
2257                                                },
2258                                            )
2259                                        }
2260                                    });
2261                                }
2262                                (WrapperKind::PinBox, Some(inner_ty)) => {
2263                                    let snake_inner = format_ident!("{}_inner", snake);
2264                                    tokens.extend(quote! {
2265                                        #[inline(always)]
2266                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2267                                            rust_key_paths::Kp::new(
2268                                                |root: &#name| match root {
2269                                                    #name::#v_ident(inner) => Some(inner),
2270                                                    _ => None,
2271                                                },
2272                                                |root: &mut #name| match root {
2273                                                    #name::#v_ident(inner) => Some(inner),
2274                                                    _ => None,
2275                                                },
2276                                            )
2277                                        }
2278                                        #[inline(always)]
2279                                        pub fn #snake_inner() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2280                                        where #inner_ty: std::marker::Unpin
2281                                        {
2282                                            rust_key_paths::Kp::new(
2283                                                |root: &#name| match root {
2284                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_ref(inner).get_ref()),
2285                                                    _ => None,
2286                                                },
2287                                                |root: &mut #name| match root {
2288                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_mut(inner).get_mut()),
2289                                                    _ => None,
2290                                                },
2291                                            )
2292                                        }
2293                                    });
2294                                }
2295                                (WrapperKind::Rc, Some(inner_ty)) => {
2296                                    tokens.extend(quote! {
2297                                        #[inline(always)]
2298                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2299                                            rust_key_paths::Kp::new(
2300                                                |root: &#name| match root {
2301                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
2302                                                    _ => None,
2303                                                },
2304                                                |root: &mut #name| match root {
2305                                                    #name::#v_ident(inner) => std::rc::Rc::get_mut(inner),
2306                                                    _ => None,
2307                                                },
2308                                            )
2309                                        }
2310                                    });
2311                                }
2312                                (WrapperKind::Arc, Some(inner_ty)) => {
2313                                    tokens.extend(quote! {
2314                                        #[inline(always)]
2315                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2316                                            rust_key_paths::Kp::new(
2317                                                |root: &#name| match root {
2318                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
2319                                                    _ => None,
2320                                                },
2321                                                |root: &mut #name| match root {
2322                                                    #name::#v_ident(inner) => std::sync::Arc::get_mut(inner),
2323                                                    _ => None,
2324                                                },
2325                                            )
2326                                        }
2327                                    });
2328                                }
2329                                (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
2330                                    let snake_lock = format_ident!("{}_lock", snake);
2331                                    tokens.extend(quote! {
2332                                        #[inline(always)]
2333                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2334                                            rust_key_paths::Kp::new(
2335                                                |root: &#name| match root {
2336                                                    #name::#v_ident(inner) => Some(inner),
2337                                                    _ => None,
2338                                                },
2339                                                |root: &mut #name| match root {
2340                                                    #name::#v_ident(inner) => Some(inner),
2341                                                    _ => None,
2342                                                },
2343                                            )
2344                                        }
2345                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #field_ty, #inner_ty> {
2346                                            rust_key_paths::lock::LockKp::new(
2347                                                rust_key_paths::Kp::new(
2348                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2349                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2350                                                ),
2351                                                rust_key_paths::lock::ArcRwLockAccess::new(),
2352                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2353                                            )
2354                                        }
2355                                    });
2356                                }
2357                                (WrapperKind::StdArcMutex, Some(inner_ty)) => {
2358                                    let snake_lock = format_ident!("{}_lock", snake);
2359                                    tokens.extend(quote! {
2360                                        #[inline(always)]
2361                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2362                                            rust_key_paths::Kp::new(
2363                                                |root: &#name| match root {
2364                                                    #name::#v_ident(inner) => Some(inner),
2365                                                    _ => None,
2366                                                },
2367                                                |root: &mut #name| match root {
2368                                                    #name::#v_ident(inner) => Some(inner),
2369                                                    _ => None,
2370                                                },
2371                                            )
2372                                        }
2373                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #field_ty, #inner_ty> {
2374                                            rust_key_paths::lock::LockKp::new(
2375                                                rust_key_paths::Kp::new(
2376                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2377                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2378                                                ),
2379                                                rust_key_paths::lock::ArcMutexAccess::new(),
2380                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2381                                            )
2382                                        }
2383                                    });
2384                                }
2385                                (WrapperKind::ArcRwLock, Some(inner_ty)) => {
2386                                    let snake_lock = format_ident!("{}_lock", snake);
2387                                    tokens.extend(quote! {
2388                                        #[inline(always)]
2389                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2390                                            rust_key_paths::Kp::new(
2391                                                |root: &#name| match root {
2392                                                    #name::#v_ident(inner) => Some(inner),
2393                                                    _ => None,
2394                                                },
2395                                                |root: &mut #name| match root {
2396                                                    #name::#v_ident(inner) => Some(inner),
2397                                                    _ => None,
2398                                                },
2399                                            )
2400                                        }
2401                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #field_ty, #inner_ty> {
2402                                            rust_key_paths::lock::LockKp::new(
2403                                                rust_key_paths::Kp::new(
2404                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2405                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2406                                                ),
2407                                                rust_key_paths::lock::ParkingLotRwLockAccess::new(),
2408                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2409                                            )
2410                                        }
2411                                    });
2412                                }
2413                                (WrapperKind::ArcMutex, Some(inner_ty)) => {
2414                                    let snake_lock = format_ident!("{}_lock", snake);
2415                                    tokens.extend(quote! {
2416                                        #[inline(always)]
2417                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2418                                            rust_key_paths::Kp::new(
2419                                                |root: &#name| match root {
2420                                                    #name::#v_ident(inner) => Some(inner),
2421                                                    _ => None,
2422                                                },
2423                                                |root: &mut #name| match root {
2424                                                    #name::#v_ident(inner) => Some(inner),
2425                                                    _ => None,
2426                                                },
2427                                            )
2428                                        }
2429                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #field_ty, #inner_ty> {
2430                                            rust_key_paths::lock::LockKp::new(
2431                                                rust_key_paths::Kp::new(
2432                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2433                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2434                                                ),
2435                                                rust_key_paths::lock::ParkingLotMutexAccess::new(),
2436                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2437                                            )
2438                                        }
2439                                    });
2440                                }
2441                                (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
2442                                    let snake_async = format_ident!("{}_async", snake);
2443                                    tokens.extend(quote! {
2444                                        #[inline(always)]
2445                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2446                                            rust_key_paths::Kp::new(
2447                                                |root: &#name| match root {
2448                                                    #name::#v_ident(inner) => Some(inner),
2449                                                    _ => None,
2450                                                },
2451                                                |root: &mut #name| match root {
2452                                                    #name::#v_ident(inner) => Some(inner),
2453                                                    _ => None,
2454                                                },
2455                                            )
2456                                        }
2457                                        pub fn #snake_async() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #field_ty, #inner_ty> {
2458                                            rust_key_paths::async_lock::AsyncLockKp::new(
2459                                                rust_key_paths::Kp::new(
2460                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2461                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2462                                                ),
2463                                                rust_key_paths::async_lock::TokioMutexAccess::new(),
2464                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2465                                            )
2466                                        }
2467                                    });
2468                                }
2469                                (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
2470                                    let snake_async = format_ident!("{}_async", snake);
2471                                    tokens.extend(quote! {
2472                                        #[inline(always)]
2473                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2474                                            rust_key_paths::Kp::new(
2475                                                |root: &#name| match root {
2476                                                    #name::#v_ident(inner) => Some(inner),
2477                                                    _ => None,
2478                                                },
2479                                                |root: &mut #name| match root {
2480                                                    #name::#v_ident(inner) => Some(inner),
2481                                                    _ => None,
2482                                                },
2483                                            )
2484                                        }
2485                                        pub fn #snake_async() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #field_ty, #inner_ty> {
2486                                            rust_key_paths::async_lock::AsyncLockKp::new(
2487                                                rust_key_paths::Kp::new(
2488                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2489                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2490                                                ),
2491                                                rust_key_paths::async_lock::TokioRwLockAccess::new(),
2492                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2493                                            )
2494                                        }
2495                                    });
2496                                }
2497                                (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
2498                                    let snake_async = format_ident!("{}_async", snake);
2499                                    tokens.extend(quote! {
2500                                        #[inline(always)]
2501                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2502                                            rust_key_paths::Kp::new(
2503                                                |root: &#name| match root {
2504                                                    #name::#v_ident(inner) => Some(inner),
2505                                                    _ => None,
2506                                                },
2507                                                |root: &mut #name| match root {
2508                                                    #name::#v_ident(inner) => Some(inner),
2509                                                    _ => None,
2510                                                },
2511                                            )
2512                                        }
2513                                        pub fn #snake_async() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
2514                                            rust_key_paths::async_lock::AsyncLockKp::new(
2515                                                rust_key_paths::Kp::new(
2516                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2517                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2518                                                ),
2519                                                rust_key_paths::async_lock::TokioMutexAccess::new(),
2520                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2521                                            )
2522                                        }
2523                                    });
2524                                }
2525                                (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
2526                                    let snake_async = format_ident!("{}_async", snake);
2527                                    tokens.extend(quote! {
2528                                        #[inline(always)]
2529                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2530                                            rust_key_paths::Kp::new(
2531                                                |root: &#name| match root {
2532                                                    #name::#v_ident(inner) => Some(inner),
2533                                                    _ => None,
2534                                                },
2535                                                |root: &mut #name| match root {
2536                                                    #name::#v_ident(inner) => Some(inner),
2537                                                    _ => None,
2538                                                },
2539                                            )
2540                                        }
2541                                        pub fn #snake_async() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
2542                                            rust_key_paths::async_lock::AsyncLockKp::new(
2543                                                rust_key_paths::Kp::new(
2544                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2545                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2546                                                ),
2547                                                rust_key_paths::async_lock::TokioRwLockAccess::new(),
2548                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2549                                            )
2550                                        }
2551                                    });
2552                                }
2553                                (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
2554                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
2555                                    let snake_lock = format_ident!("{}_lock", snake);
2556                                    tokens.extend(quote! {
2557                                        #[inline(always)]
2558                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2559                                            rust_key_paths::Kp::new(
2560                                                |root: &#name| match root {
2561                                                    #name::#v_ident(inner) => Some(inner),
2562                                                    _ => None,
2563                                                },
2564                                                |root: &mut #name| match root {
2565                                                    #name::#v_ident(inner) => Some(inner),
2566                                                    _ => None,
2567                                                },
2568                                            )
2569                                        }
2570                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
2571                                            rust_key_paths::Kp::new(
2572                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2573                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2574                                            )
2575                                        }
2576                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
2577                                            rust_key_paths::lock::LockKp::new(
2578                                                rust_key_paths::Kp::new(
2579                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2580                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2581                                                ),
2582                                                rust_key_paths::lock::ArcMutexAccess::new(),
2583                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2584                                            )
2585                                        }
2586                                    });
2587                                }
2588                                (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
2589                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
2590                                    let snake_lock = format_ident!("{}_lock", snake);
2591                                    tokens.extend(quote! {
2592                                        #[inline(always)]
2593                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2594                                            rust_key_paths::Kp::new(
2595                                                |root: &#name| match root {
2596                                                    #name::#v_ident(inner) => Some(inner),
2597                                                    _ => None,
2598                                                },
2599                                                |root: &mut #name| match root {
2600                                                    #name::#v_ident(inner) => Some(inner),
2601                                                    _ => None,
2602                                                },
2603                                            )
2604                                        }
2605                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
2606                                            rust_key_paths::Kp::new(
2607                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2608                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2609                                            )
2610                                        }
2611                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>, #inner_ty> {
2612                                            rust_key_paths::lock::LockKp::new(
2613                                                rust_key_paths::Kp::new(
2614                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2615                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2616                                                ),
2617                                                rust_key_paths::lock::ParkingLotMutexAccess::new(),
2618                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2619                                            )
2620                                        }
2621                                    });
2622                                }
2623                                (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
2624                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
2625                                    let snake_lock = format_ident!("{}_lock", snake);
2626                                    tokens.extend(quote! {
2627                                        #[inline(always)]
2628                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2629                                            rust_key_paths::Kp::new(
2630                                                |root: &#name| match root {
2631                                                    #name::#v_ident(inner) => Some(inner),
2632                                                    _ => None,
2633                                                },
2634                                                |root: &mut #name| match root {
2635                                                    #name::#v_ident(inner) => Some(inner),
2636                                                    _ => None,
2637                                                },
2638                                            )
2639                                        }
2640                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
2641                                            rust_key_paths::Kp::new(
2642                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2643                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2644                                            )
2645                                        }
2646                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
2647                                            rust_key_paths::lock::LockKp::new(
2648                                                rust_key_paths::Kp::new(
2649                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2650                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2651                                                ),
2652                                                rust_key_paths::lock::ArcRwLockAccess::new(),
2653                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2654                                            )
2655                                        }
2656                                    });
2657                                }
2658                                (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
2659                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
2660                                    let snake_lock = format_ident!("{}_lock", snake);
2661                                    tokens.extend(quote! {
2662                                        #[inline(always)]
2663                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2664                                            rust_key_paths::Kp::new(
2665                                                |root: &#name| match root {
2666                                                    #name::#v_ident(inner) => Some(inner),
2667                                                    _ => None,
2668                                                },
2669                                                |root: &mut #name| match root {
2670                                                    #name::#v_ident(inner) => Some(inner),
2671                                                    _ => None,
2672                                                },
2673                                            )
2674                                        }
2675                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
2676                                            rust_key_paths::Kp::new(
2677                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2678                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2679                                            )
2680                                        }
2681                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>, #inner_ty> {
2682                                            rust_key_paths::lock::LockKp::new(
2683                                                rust_key_paths::Kp::new(
2684                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2685                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2686                                                ),
2687                                                rust_key_paths::lock::ParkingLotRwLockAccess::new(),
2688                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2689                                            )
2690                                        }
2691                                    });
2692                                }
2693                                (WrapperKind::StdMutex, Some(_inner_ty))
2694                                | (WrapperKind::Mutex, Some(_inner_ty))
2695                                | (WrapperKind::StdRwLock, Some(_inner_ty))
2696                                | (WrapperKind::RwLock, Some(_inner_ty)) => {
2697                                    tokens.extend(quote! {
2698                                        #[inline(always)]
2699                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2700                                            rust_key_paths::Kp::new(
2701                                                |root: &#name| match root {
2702                                                    #name::#v_ident(inner) => Some(inner),
2703                                                    _ => None,
2704                                                },
2705                                                |root: &mut #name| match root {
2706                                                    #name::#v_ident(inner) => Some(inner),
2707                                                    _ => None,
2708                                                },
2709                                            )
2710                                        }
2711                                    });
2712                                }
2713                                (WrapperKind::Tagged, Some(inner_ty)) => {
2714                                    tokens.extend(quote! {
2715                                        #[inline(always)]
2716                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2717                                            rust_key_paths::Kp::new(
2718                                                |root: &#name| match root {
2719                                                    #name::#v_ident(inner) => Some(std::ops::Deref::deref(inner)),
2720                                                    _ => None,
2721                                                },
2722                                                |root: &mut #name| match root {
2723                                                    #name::#v_ident(inner) => Some(std::ops::DerefMut::deref_mut(inner)),
2724                                                    _ => None,
2725                                                },
2726                                            )
2727                                        }
2728                                    });
2729                                }
2730                                (WrapperKind::Atomic, None | Some(_)) => {
2731                                    tokens.extend(quote! {
2732                                        #[inline(always)]
2733                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2734                                            rust_key_paths::Kp::new(
2735                                                |root: &#name| match root {
2736                                                    #name::#v_ident(inner) => Some(inner),
2737                                                    _ => None,
2738                                                },
2739                                                |root: &mut #name| match root {
2740                                                    #name::#v_ident(inner) => Some(inner),
2741                                                    _ => None,
2742                                                },
2743                                            )
2744                                        }
2745                                    });
2746                                }
2747                                (WrapperKind::OptionAtomic, Some(inner_ty)) => {
2748                                    tokens.extend(quote! {
2749                                        #[inline(always)]
2750                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2751                                            rust_key_paths::Kp::new(
2752                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2753                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2754                                            )
2755                                        }
2756                                    });
2757                                }
2758                                (WrapperKind::Reference, Some(_inner_ty)) => {
2759                                    tokens.extend(quote! {
2760                                        #[inline(always)]
2761                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2762                                            rust_key_paths::Kp::new(
2763                                                |root: &#name| match root {
2764                                                    #name::#v_ident(inner) => Some(inner),
2765                                                    _ => None,
2766                                                },
2767                                                |_root: &mut #name| None,
2768                                            )
2769                                        }
2770                                    });
2771                                }
2772                                (WrapperKind::Weak, Some(_inner_ty)) => {
2773                                    tokens.extend(quote! {
2774                                        #[inline(always)]
2775                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2776                                            rust_key_paths::Kp::new(
2777                                                |root: &#name| match root {
2778                                                    #name::#v_ident(inner) => Some(inner),
2779                                                    _ => None,
2780                                                },
2781                                                |_root: &mut #name| None,
2782                                            )
2783                                        }
2784                                    });
2785                                }
2786                                (WrapperKind::Cow, Some(inner_ty)) => {
2787                                    tokens.extend(quote! {
2788                                        #[inline(always)]
2789                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2790                                            rust_key_paths::Kp::new(
2791                                                |root: &#name| match root {
2792                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
2793                                                    _ => None,
2794                                                },
2795                                                |root: &mut #name| match root {
2796                                                    #name::#v_ident(inner) => Some(inner.to_mut()),
2797                                                    _ => None,
2798                                                },
2799                                            )
2800                                        }
2801                                    });
2802                                }
2803                                (WrapperKind::OptionCow, Some(inner_ty)) => {
2804                                    tokens.extend(quote! {
2805                                        #[inline(always)]
2806                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2807                                            rust_key_paths::Kp::new(
2808                                                |root: &#name| match root {
2809                                                    #name::#v_ident(inner) => inner.as_ref().map(|c| c.as_ref()),
2810                                                    _ => None,
2811                                                },
2812                                                |root: &mut #name| match root {
2813                                                    #name::#v_ident(inner) => inner.as_mut().map(|c| c.to_mut()),
2814                                                    _ => None,
2815                                                },
2816                                            )
2817                                        }
2818                                    });
2819                                }
2820                                (WrapperKind::OptionTagged, Some(inner_ty)) => {
2821                                    tokens.extend(quote! {
2822                                        #[inline(always)]
2823                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2824                                            rust_key_paths::Kp::new(
2825                                                |root: &#name| match root {
2826                                                    #name::#v_ident(inner) => inner.as_ref().map(|t| std::ops::Deref::deref(t)),
2827                                                    _ => None,
2828                                                },
2829                                                |root: &mut #name| match root {
2830                                                    #name::#v_ident(inner) => inner.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
2831                                                    _ => None,
2832                                                },
2833                                            )
2834                                        }
2835                                    });
2836                                }
2837                                (WrapperKind::OptionReference, Some(inner_ty)) => {
2838                                    tokens.extend(quote! {
2839                                        #[inline(always)]
2840                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2841                                            rust_key_paths::Kp::new(
2842                                                |root: &#name| match root {
2843                                                    #name::#v_ident(inner) => inner.as_ref(),
2844                                                    _ => None,
2845                                                },
2846                                                |_root: &mut #name| None,
2847                                            )
2848                                        }
2849                                    });
2850                                }
2851                                (WrapperKind::None, None) => {
2852                                    // Basic type
2853                                    tokens.extend(quote! {
2854                                        #[inline(always)]
2855                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2856                                            rust_key_paths::Kp::new(
2857                                                |root: &#name| match root {
2858                                                    #name::#v_ident(inner) => Some(inner),
2859                                                    _ => None,
2860                                                },
2861                                                |root: &mut #name| match root {
2862                                                    #name::#v_ident(inner) => Some(inner),
2863                                                    _ => None,
2864                                                },
2865                                            )
2866                                        }
2867                                    });
2868                                }
2869                                _ => {
2870                                    // Other wrapper types - return keypath to field
2871                                    tokens.extend(quote! {
2872                                        #[inline(always)]
2873                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2874                                            rust_key_paths::Kp::new(
2875                                                |root: &#name| match root {
2876                                                    #name::#v_ident(inner) => Some(inner),
2877                                                    _ => None,
2878                                                },
2879                                                |root: &mut #name| match root {
2880                                                    #name::#v_ident(inner) => Some(inner),
2881                                                    _ => None,
2882                                                },
2883                                            )
2884                                        }
2885                                    });
2886                                }
2887                            }
2888                        } else {
2889                            // Multi-field tuple variant - return keypath to variant itself
2890                            tokens.extend(quote! {
2891                                #[inline(always)]
2892                                pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
2893                                    rust_key_paths::Kp::new(
2894                                        |root: &#name| match root {
2895                                            #name::#v_ident(..) => Some(root),
2896                                            _ => None,
2897                                        },
2898                                        |root: &mut #name| match root {
2899                                            #name::#v_ident(..) => Some(root),
2900                                            _ => None,
2901                                        },
2902                                    )
2903                                }
2904                            });
2905                        }
2906                    }
2907                    Fields::Named(_) => {
2908                        // Named field variant - return keypath to variant itself
2909                        tokens.extend(quote! {
2910                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
2911                                rust_key_paths::Kp::new(
2912                                    |root: &#name| match root {
2913                                        #name::#v_ident { .. } => Some(root),
2914                                        _ => None,
2915                                    },
2916                                    |root: &mut #name| match root {
2917                                        #name::#v_ident { .. } => Some(root),
2918                                        _ => None,
2919                                    },
2920                                )
2921                            }
2922                        });
2923                    }
2924                }
2925            }
2926
2927            tokens
2928        }
2929        Data::Union(_) => {
2930            return syn::Error::new(input_span, "Kp derive does not support unions")
2931            .to_compile_error()
2932            .into();
2933        }
2934    };
2935
2936    let expanded = quote! {
2937        impl #name {
2938            #methods
2939        }
2940    };
2941
2942    TokenStream::from(expanded)
2943}
2944
2945/// Derive macro that generates `partial_kps() -> Vec<PKp<Self>>` returning all field/variant keypaths.
2946/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
2947///
2948/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
2949/// (using the same methods Kp generates, e.g. `some_variant()`).
2950///
2951/// # Example
2952/// ```
2953/// use key_paths_derive::{Kp, Pkp};
2954/// use rust_key_paths::PKp;
2955///
2956/// #[derive(Kp, Pkp)]
2957/// struct Person {
2958///     name: String,
2959///     age: i32,
2960/// }
2961///
2962/// let kps = Person::partial_kps();
2963/// assert_eq!(kps.len(), 2);
2964/// ```
2965#[proc_macro_derive(Pkp)]
2966pub fn derive_partial_keypaths(input: TokenStream) -> TokenStream {
2967    let input = parse_macro_input!(input as DeriveInput);
2968    let name = &input.ident;
2969
2970    let kp_calls = match &input.data {
2971        Data::Struct(data_struct) => match &data_struct.fields {
2972            Fields::Named(fields_named) => {
2973                let calls: Vec<_> = fields_named
2974                    .named
2975                    .iter()
2976                    .filter_map(|f| f.ident.as_ref())
2977                    .map(|field_ident| {
2978                        quote! { rust_key_paths::PKp::new(Self::#field_ident()) }
2979                    })
2980                    .collect();
2981                quote! { #(#calls),* }
2982            }
2983            Fields::Unnamed(unnamed) => {
2984                let calls: Vec<_> = (0..unnamed.unnamed.len())
2985                    .map(|idx| {
2986                        let kp_fn = format_ident!("f{}", idx);
2987                        quote! { rust_key_paths::PKp::new(Self::#kp_fn()) }
2988                    })
2989                    .collect();
2990                quote! { #(#calls),* }
2991            }
2992            Fields::Unit => quote! {},
2993        },
2994        Data::Enum(data_enum) => {
2995            let calls: Vec<_> = data_enum
2996                .variants
2997                .iter()
2998                .map(|variant| {
2999                    let v_ident = &variant.ident;
3000                    let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
3001                    quote! { rust_key_paths::PKp::new(Self::#snake()) }
3002                })
3003                .collect();
3004            quote! { #(#calls),* }
3005        }
3006        Data::Union(_) => {
3007            return syn::Error::new(
3008                input.ident.span(),
3009                "Pkp derive does not support unions",
3010            )
3011            .to_compile_error()
3012            .into();
3013        }
3014    };
3015
3016    let expanded = quote! {
3017        impl #name {
3018            /// Returns a vec of all field keypaths as partial keypaths (type-erased).
3019            #[inline(always)]
3020            pub fn partial_kps() -> Vec<rust_key_paths::PKp<#name>> {
3021                vec![#kp_calls]
3022            }
3023        }
3024    };
3025
3026    TokenStream::from(expanded)
3027}
3028
3029/// Derive macro that generates `any_kps() -> Vec<AKp>` returning all field/variant keypaths as any keypaths.
3030/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
3031/// AKp type-erases both Root and Value, enabling heterogeneous collections of keypaths.
3032///
3033/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
3034/// (using the same methods Kp generates, e.g. `some_variant()`).
3035///
3036/// # Example
3037/// ```
3038/// use key_paths_derive::{Kp, Akp};
3039/// use rust_key_paths::AKp;
3040///
3041/// #[derive(Kp, Akp)]
3042/// struct Person {
3043///     name: String,
3044///     age: i32,
3045/// }
3046///
3047/// let kps = Person::any_kps();
3048/// assert_eq!(kps.len(), 2);
3049/// let person = Person { name: "Alice".into(), age: 30 };
3050/// let name: Option<&String> = kps[0].get(&person as &dyn std::any::Any).and_then(|v| v.downcast_ref());
3051/// assert_eq!(name, Some(&"Alice".to_string()));
3052/// ```
3053#[proc_macro_derive(Akp)]
3054pub fn derive_any_keypaths(input: TokenStream) -> TokenStream {
3055    let input = parse_macro_input!(input as DeriveInput);
3056    let name = &input.ident;
3057
3058    let kp_calls = match &input.data {
3059        Data::Struct(data_struct) => match &data_struct.fields {
3060            Fields::Named(fields_named) => {
3061                let calls: Vec<_> = fields_named
3062                    .named
3063                    .iter()
3064                    .filter_map(|f| f.ident.as_ref())
3065                    .map(|field_ident| {
3066                        quote! { rust_key_paths::AKp::new(Self::#field_ident()) }
3067                    })
3068                    .collect();
3069                quote! { #(#calls),* }
3070            }
3071            Fields::Unnamed(unnamed) => {
3072                let calls: Vec<_> = (0..unnamed.unnamed.len())
3073                    .map(|idx| {
3074                        let kp_fn = format_ident!("f{}", idx);
3075                        quote! { rust_key_paths::AKp::new(Self::#kp_fn()) }
3076                    })
3077                    .collect();
3078                quote! { #(#calls),* }
3079            }
3080            Fields::Unit => quote! {},
3081        },
3082        Data::Enum(data_enum) => {
3083            let calls: Vec<_> = data_enum
3084                .variants
3085                .iter()
3086                .map(|variant| {
3087                    let v_ident = &variant.ident;
3088                    let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
3089                    quote! { rust_key_paths::AKp::new(Self::#snake()) }
3090                })
3091                .collect();
3092            quote! { #(#calls),* }
3093        }
3094        Data::Union(_) => {
3095            return syn::Error::new(
3096                input.ident.span(),
3097                "Akp derive does not support unions",
3098            )
3099            .to_compile_error()
3100            .into();
3101        }
3102    };
3103
3104    let expanded = quote! {
3105        impl #name {
3106            /// Returns a vec of all field keypaths as any keypaths (fully type-erased).
3107            #[inline(always)]
3108            pub fn any_kps() -> Vec<rust_key_paths::AKp> {
3109                vec![#kp_calls]
3110            }
3111        }
3112    };
3113
3114    TokenStream::from(expanded)
3115}