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