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 and owned text
25    String,
26    OptionString,
27    // Interior mutability (std::cell)
28    Cell,
29    RefCell,
30    OptionCell,
31    OptionRefCell,
32    // Lazy init (once_cell, std::sync::OnceLock, std::sync::LazyLock)
33    OnceCell,
34    Lazy,
35    OptionOnceCell,
36    OptionLazy,
37    // Marker / zero-size
38    PhantomData,
39    OptionPhantomData,
40    // Range iterators (std::ops::Range, RangeInclusive)
41    Range,
42    OptionRange,
43    // Nested container support
44    OptionBox,
45    OptionRc,
46    OptionArc,
47    BoxOption,
48    RcOption,
49    ArcOption,
50    VecOption,
51    OptionVec,
52    VecDequeOption,
53    OptionVecDeque,
54    LinkedListOption,
55    OptionLinkedList,
56    BinaryHeapOption,
57    OptionBinaryHeap,
58    HashSetOption,
59    OptionHashSet,
60    BTreeSetOption,
61    OptionBTreeSet,
62    ResultOption,
63    OptionResult,
64    HashMapOption,
65    OptionHashMap,
66    BTreeMapOption,
67    OptionBTreeMap,
68    // Arc with synchronization primitives (default)
69    StdArcMutex,
70    StdArcRwLock,
71    StdArcMutexOption,
72    StdArcRwLockOption,
73    OptionStdArcMutex,
74    OptionStdArcRwLock,
75    // Synchronization primitives default
76    StdMutex,
77    StdRwLock,
78    StdMutexOption,
79    StdRwLockOption,
80    OptionStdMutex,
81    OptionStdRwLock,
82    // Synchronization primitives (parking_lot)
83    Mutex,
84    RwLock,
85    OptionMutex,
86    OptionRwLock,
87    // Synchronization primitives (tokio::sync - requires tokio feature)
88    TokioMutex,
89    TokioRwLock,
90    // parking_lot
91    ArcMutex,
92    ArcRwLock,
93    ArcMutexOption,
94    ArcRwLockOption,
95    OptionArcMutex,
96    OptionArcRwLock,
97    MutexOption,
98    RwLockOption,
99    // Arc with synchronization primitives (tokio::sync - requires tokio feature)
100    TokioArcMutex,
101    TokioArcRwLock,
102    OptionTokioArcMutex,
103    OptionTokioArcRwLock,
104    // Tagged types
105    Tagged,
106    OptionTagged,
107    // Clone-on-write (std::borrow::Cow)
108    Cow,
109    OptionCow,
110    // Reference types (&T, &str, &[T], etc.)
111    Reference,
112    OptionReference,
113    // Atomic types (std::sync::atomic::*)
114    Atomic,
115    OptionAtomic,
116    // Pin types
117    Pin,
118    PinBox,
119    /// Field marked with #[pin] - plain type (pin_project pattern)
120    PinnedField,
121    /// Field marked with #[pin] - Future type (pin_project pattern)
122    PinnedFuture,
123    /// Field marked with #[pin] - Box<dyn Future> (pin_project pattern)
124    PinnedBoxFuture,
125}
126
127/// Helper function to check if a type path is exactly under std::sync (not lock_api or parking_lot).
128/// Requires the path to start with "std" then "sync" so we don't confuse with RwLock&lt;RawRwLock, T&gt; (lock_api).
129fn is_std_sync_type(path: &syn::Path) -> bool {
130    let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
131    segments.len() >= 2
132        && segments.get(0).map(|s| s.as_str()) == Some("std")
133        && segments.get(1).map(|s| s.as_str()) == Some("sync")
134}
135
136/// Helper function to check if a type path is exactly under tokio::sync.
137fn is_tokio_sync_type(path: &syn::Path) -> bool {
138    let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
139    segments.len() >= 2
140        && segments.get(0).map(|s| s.as_str()) == Some("tokio")
141        && segments.get(1).map(|s| s.as_str()) == Some("sync")
142}
143
144/// Helper function to check if a type path is under parking_lot (RwLock/Mutex from lock_api).
145/// Use so we never treat parking_lot::RwLock as std::sync::RwLock.
146fn is_parking_lot_type(path: &syn::Path) -> bool {
147    path.segments.first().map(|s| s.ident == "parking_lot") == Some(true)
148}
149
150/// Helper function to check if a type path is under std::sync::atomic (strict prefix).
151fn is_std_sync_atomic_type(path: &syn::Path) -> bool {
152    let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
153    segments.len() >= 3
154        && segments.get(0).map(|s| s.as_str()) == Some("std")
155        && segments.get(1).map(|s| s.as_str()) == Some("sync")
156        && segments.get(2).map(|s| s.as_str()) == Some("atomic")
157}
158
159/// Atomic type idents (no type params): AtomicBool, AtomicI8, etc.
160const ATOMIC_TYPE_IDENTS: &[&str] = &[
161    "AtomicBool",
162    "AtomicI8",
163    "AtomicI16",
164    "AtomicI32",
165    "AtomicI64",
166    "AtomicI128",
167    "AtomicIsize",
168    "AtomicU8",
169    "AtomicU16",
170    "AtomicU32",
171    "AtomicU64",
172    "AtomicU128",
173    "AtomicUsize",
174];
175
176fn extract_wrapper_inner_type(ty: &Type) -> (WrapperKind, Option<Type>) {
177    use syn::{GenericArgument, PathArguments};
178
179    // Handle reference types: &T, &'a str, &[T], etc.
180    if let Type::Reference(tr) = ty {
181        return (WrapperKind::Reference, Some((*tr.elem).clone()));
182    }
183
184    if let Type::Path(tp) = ty {
185        // Check if this is explicitly a std::sync type
186        let is_std_sync = is_std_sync_type(&tp.path);
187        // Check if this is explicitly a tokio::sync type
188        let is_tokio_sync = is_tokio_sync_type(&tp.path);
189
190        if let Some(seg) = tp.path.segments.last() {
191            let ident_str = seg.ident.to_string();
192
193            if let PathArguments::AngleBracketed(ab) = &seg.arguments {
194                let args: Vec<_> = ab.args.iter().collect();
195
196                // Handle map types (HashMap, BTreeMap) - they have K, V parameters
197                if ident_str == "HashMap" || ident_str == "BTreeMap" {
198                    if let (Some(_key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
199                        if let GenericArgument::Type(inner) = value_arg {
200                            // Check for nested Option in map values
201                            let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
202                            match (ident_str.as_str(), inner_kind) {
203                                ("HashMap", WrapperKind::Option) => {
204                                    return (WrapperKind::HashMapOption, inner_inner);
205                                }
206                                ("BTreeMap", WrapperKind::Option) => {
207                                    return (WrapperKind::BTreeMapOption, inner_inner);
208                                }
209                                _ => {
210                                    return match ident_str.as_str() {
211                                        "HashMap" => (WrapperKind::HashMap, Some(inner.clone())),
212                                        "BTreeMap" => (WrapperKind::BTreeMap, Some(inner.clone())),
213                                        _ => (WrapperKind::None, None),
214                                    };
215                                }
216                            }
217                        }
218                    }
219                }
220                // Handle Cow<'a, B> - has lifetime then type parameter
221                else if ident_str == "Cow" {
222                    if let Some(inner) = args.iter().find_map(|arg| {
223                        if let GenericArgument::Type(t) = arg {
224                            Some(t.clone())
225                        } else {
226                            None
227                        }
228                    }) {
229                        return (WrapperKind::Cow, Some(inner));
230                    }
231                }
232                // Handle single-parameter container types
233                else if let Some(arg) = args.get(0) {
234                    if let GenericArgument::Type(inner) = arg {
235                        // Check for nested containers first
236                        let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
237
238                        // Handle nested combinations
239                        match (ident_str.as_str(), inner_kind) {
240                            ("Option", WrapperKind::Box) => {
241                                return (WrapperKind::OptionBox, inner_inner);
242                            }
243                            ("Option", WrapperKind::Rc) => {
244                                return (WrapperKind::OptionRc, inner_inner);
245                            }
246                            ("Option", WrapperKind::Arc) => {
247                                return (WrapperKind::OptionArc, inner_inner);
248                            }
249                            ("Option", WrapperKind::Vec) => {
250                                return (WrapperKind::OptionVec, inner_inner);
251                            }
252                            ("Option", WrapperKind::HashMap) => {
253                                return (WrapperKind::OptionHashMap, inner_inner);
254                            }
255                            ("Option", WrapperKind::BTreeMap) => {
256                                return (WrapperKind::OptionBTreeMap, inner_inner);
257                            }
258                            ("Option", WrapperKind::VecDeque) => {
259                                return (WrapperKind::OptionVecDeque, inner_inner);
260                            }
261                            ("Option", WrapperKind::LinkedList) => {
262                                return (WrapperKind::OptionLinkedList, inner_inner);
263                            }
264                            ("Option", WrapperKind::BinaryHeap) => {
265                                return (WrapperKind::OptionBinaryHeap, inner_inner);
266                            }
267                            ("Option", WrapperKind::HashSet) => {
268                                return (WrapperKind::OptionHashSet, inner_inner);
269                            }
270                            ("Option", WrapperKind::BTreeSet) => {
271                                return (WrapperKind::OptionBTreeSet, inner_inner);
272                            }
273                            ("Option", WrapperKind::Result) => {
274                                return (WrapperKind::OptionResult, inner_inner);
275                            }
276                            ("Option", WrapperKind::StdArcMutex) => {
277                                return (WrapperKind::OptionStdArcMutex, inner_inner);
278                            }
279                            ("Option", WrapperKind::StdArcRwLock) => {
280                                return (WrapperKind::OptionStdArcRwLock, inner_inner);
281                            }
282                            ("Option", WrapperKind::ArcMutex) => {
283                                return (WrapperKind::OptionArcMutex, inner_inner);
284                            }
285                            ("Option", WrapperKind::ArcRwLock) => {
286                                return (WrapperKind::OptionArcRwLock, inner_inner);
287                            }
288                            ("Option", WrapperKind::StdMutex) => {
289                                return (WrapperKind::OptionStdMutex, inner_inner);
290                            }
291                            ("Option", WrapperKind::StdRwLock) => {
292                                return (WrapperKind::OptionStdRwLock, inner_inner);
293                            }
294                            ("Option", WrapperKind::Mutex) => {
295                                return (WrapperKind::OptionMutex, inner_inner);
296                            }
297                            ("Option", WrapperKind::RwLock) => {
298                                return (WrapperKind::OptionRwLock, inner_inner);
299                            }
300                            ("Option", WrapperKind::TokioArcMutex) => {
301                                return (WrapperKind::OptionTokioArcMutex, inner_inner);
302                            }
303                            ("Option", WrapperKind::TokioArcRwLock) => {
304                                return (WrapperKind::OptionTokioArcRwLock, inner_inner);
305                            }
306                            ("Option", WrapperKind::Cow) => {
307                                return (WrapperKind::OptionCow, inner_inner);
308                            }
309                            ("Option", WrapperKind::Tagged) => {
310                                return (WrapperKind::OptionTagged, inner_inner);
311                            }
312                            ("Option", WrapperKind::Reference) => {
313                                return (WrapperKind::OptionReference, Some(inner.clone()));
314                            }
315                            ("Option", WrapperKind::Atomic) => {
316                                return (WrapperKind::OptionAtomic, Some(inner.clone()));
317                            }
318                            ("Option", WrapperKind::String) => {
319                                return (WrapperKind::OptionString, None);
320                            }
321                            ("Option", WrapperKind::Cell) => {
322                                return (WrapperKind::OptionCell, inner_inner);
323                            }
324                            ("Option", WrapperKind::RefCell) => {
325                                return (WrapperKind::OptionRefCell, inner_inner);
326                            }
327                            ("Option", WrapperKind::OnceCell) => {
328                                return (WrapperKind::OptionOnceCell, inner_inner);
329                            }
330                            ("Option", WrapperKind::Lazy) => {
331                                return (WrapperKind::OptionLazy, inner_inner);
332                            }
333                            ("Option", WrapperKind::PhantomData) => {
334                                return (WrapperKind::OptionPhantomData, inner_inner);
335                            }
336                            ("Option", WrapperKind::Range) => {
337                                return (WrapperKind::OptionRange, inner_inner);
338                            }
339                            ("Pin", WrapperKind::Box) => {
340                                return (WrapperKind::PinBox, inner_inner);
341                            }
342                            ("Box", WrapperKind::Option) => {
343                                return (WrapperKind::BoxOption, inner_inner);
344                            }
345                            ("Rc", WrapperKind::Option) => {
346                                return (WrapperKind::RcOption, inner_inner);
347                            }
348                            ("Arc", WrapperKind::Option) => {
349                                return (WrapperKind::ArcOption, inner_inner);
350                            }
351                            ("Vec", WrapperKind::Option) => {
352                                return (WrapperKind::VecOption, inner_inner);
353                            }
354                            ("VecDeque", WrapperKind::Option) => {
355                                return (WrapperKind::VecDequeOption, inner_inner);
356                            }
357                            ("LinkedList", WrapperKind::Option) => {
358                                return (WrapperKind::LinkedListOption, inner_inner);
359                            }
360                            ("BinaryHeap", WrapperKind::Option) => {
361                                return (WrapperKind::BinaryHeapOption, inner_inner);
362                            }
363                            ("HashSet", WrapperKind::Option) => {
364                                return (WrapperKind::HashSetOption, inner_inner);
365                            }
366                            ("BTreeSet", WrapperKind::Option) => {
367                                return (WrapperKind::BTreeSetOption, inner_inner);
368                            }
369                            ("Result", WrapperKind::Option) => {
370                                return (WrapperKind::ResultOption, inner_inner);
371                            }
372                            ("HashMap", WrapperKind::Option) => {
373                                return (WrapperKind::HashMapOption, inner_inner);
374                            }
375                            // BTreeMapOption is handled in the map block (HashMap/BTreeMap)
376                            // Mutex<Option<T>> / RwLock<Option<T>> (yields LockKp value T)
377                            // std::sync::Mutex<Option<T>> / RwLock<Option<T>>
378                            ("Mutex", WrapperKind::Option) if is_std_sync_type(&tp.path) => {
379                                return (WrapperKind::StdMutexOption, inner_inner);
380                            }
381                            ("RwLock", WrapperKind::Option) if is_std_sync_type(&tp.path) => {
382                                return (WrapperKind::StdRwLockOption, inner_inner);
383                            }
384                            // parking_lot::Mutex<Option<T>> / RwLock<Option<T>>, and bare Mutex/RwLock assumed parking_lot
385                            ("Mutex", WrapperKind::Option) => {
386                                return (WrapperKind::MutexOption, inner_inner);
387                            }
388                            ("RwLock", WrapperKind::Option) => {
389                                return (WrapperKind::RwLockOption, inner_inner);
390                            }
391                            // std::sync variants (when inner is StdMutex/StdRwLock)
392                            ("Arc", WrapperKind::StdMutex) => {
393                                return (WrapperKind::StdArcMutex, inner_inner);
394                            }
395                            ("Arc", WrapperKind::StdRwLock) => {
396                                return (WrapperKind::StdArcRwLock, inner_inner);
397                            }
398                            ("Arc", WrapperKind::StdMutexOption) => {
399                                return (WrapperKind::StdArcMutexOption, inner_inner);
400                            }
401                            ("Arc", WrapperKind::StdRwLockOption) => {
402                                return (WrapperKind::StdArcRwLockOption, inner_inner);
403                            }
404                            // parking_lot variants (default - when inner is Mutex/RwLock without std::sync prefix)
405                            ("Arc", WrapperKind::Mutex) => {
406                                return (WrapperKind::ArcMutex, inner_inner);
407                            }
408                            ("Arc", WrapperKind::RwLock) => {
409                                return (WrapperKind::ArcRwLock, inner_inner);
410                            }
411                            ("Arc", WrapperKind::MutexOption) => {
412                                return (WrapperKind::ArcMutexOption, inner_inner);
413                            }
414                            ("Arc", WrapperKind::RwLockOption) => {
415                                return (WrapperKind::ArcRwLockOption, inner_inner);
416                            }
417                            // tokio::sync variants (when inner is TokioMutex/TokioRwLock)
418                            ("Arc", WrapperKind::TokioMutex) => {
419                                return (WrapperKind::TokioArcMutex, inner_inner);
420                            }
421                            ("Arc", WrapperKind::TokioRwLock) => {
422                                return (WrapperKind::TokioArcRwLock, inner_inner);
423                            }
424                            _ => {
425                                // Handle single-level containers
426                                // For Mutex and RwLock:
427                                // - If path contains std::sync, it's std::sync (StdMutex/StdRwLock)
428                                // - Otherwise, default to parking_lot (Mutex/RwLock)
429                                return match ident_str.as_str() {
430                                    "Option" => (WrapperKind::Option, Some(inner.clone())),
431                                    "Box" => (WrapperKind::Box, Some(inner.clone())),
432                                    "Rc" => (WrapperKind::Rc, Some(inner.clone())),
433                                    "Arc" => (WrapperKind::Arc, Some(inner.clone())),
434                                    "Vec" => (WrapperKind::Vec, Some(inner.clone())),
435                                    "HashSet" => (WrapperKind::HashSet, Some(inner.clone())),
436                                    "BTreeSet" => (WrapperKind::BTreeSet, Some(inner.clone())),
437                                    "VecDeque" => (WrapperKind::VecDeque, Some(inner.clone())),
438                                    "LinkedList" => (WrapperKind::LinkedList, Some(inner.clone())),
439                                    "BinaryHeap" => (WrapperKind::BinaryHeap, Some(inner.clone())),
440                                    "Result" => (WrapperKind::Result, Some(inner.clone())),
441                                    // Explicit parking_lot path (lock_api::RwLock) — never treat as std
442                                    "Mutex" if is_parking_lot_type(&tp.path) => {
443                                        (WrapperKind::Mutex, Some(inner.clone()))
444                                    }
445                                    "RwLock" if is_parking_lot_type(&tp.path) => {
446                                        (WrapperKind::RwLock, Some(inner.clone()))
447                                    }
448                                    // std::sync::Mutex and std::sync::RwLock only when path starts with std::sync
449                                    "Mutex" if is_std_sync => {
450                                        (WrapperKind::StdMutex, Some(inner.clone()))
451                                    }
452                                    "RwLock" if is_std_sync => {
453                                        (WrapperKind::StdRwLock, Some(inner.clone()))
454                                    }
455                                    // tokio::sync::Mutex and tokio::sync::RwLock
456                                    "Mutex" if is_tokio_sync => {
457                                        (WrapperKind::TokioMutex, Some(inner.clone()))
458                                    }
459                                    "RwLock" if is_tokio_sync => {
460                                        (WrapperKind::TokioRwLock, Some(inner.clone()))
461                                    }
462                                    // Default: parking_lot (bare Mutex/RwLock or unknown path)
463                                    "Mutex" => (WrapperKind::Mutex, Some(inner.clone())),
464                                    "RwLock" => (WrapperKind::RwLock, Some(inner.clone())),
465                                    "Weak" => (WrapperKind::Weak, Some(inner.clone())),
466                                    "Tagged" => (WrapperKind::Tagged, Some(inner.clone())),
467                                    "Cow" => (WrapperKind::Cow, Some(inner.clone())),
468                                    "AtomicPtr" if is_std_sync_atomic_type(&tp.path) => {
469                                        (WrapperKind::Atomic, None)
470                                    }
471                                    "Pin" => (WrapperKind::Pin, Some(inner.clone())),
472                                    "Cell" => (WrapperKind::Cell, Some(inner.clone())),
473                                    "RefCell" => (WrapperKind::RefCell, Some(inner.clone())),
474                                    "OnceCell" | "OnceLock" => {
475                                        (WrapperKind::OnceCell, Some(inner.clone()))
476                                    }
477                                    "Lazy" | "LazyLock" => (WrapperKind::Lazy, Some(inner.clone())),
478                                    "PhantomData" => {
479                                        (WrapperKind::PhantomData, Some(inner.clone()))
480                                    }
481                                    "Range" | "RangeInclusive" => {
482                                        (WrapperKind::Range, Some(inner.clone()))
483                                    }
484                                    _ => (WrapperKind::None, None),
485                                };
486                            }
487                        }
488                    }
489                }
490            }
491            // Handle atomic types with no angle bracket args (AtomicBool, AtomicI32, etc.)
492            if matches!(seg.arguments, PathArguments::None) {
493                if ident_str == "String" {
494                    return (WrapperKind::String, None);
495                }
496                if is_std_sync_atomic_type(&tp.path)
497                    && ATOMIC_TYPE_IDENTS.contains(&ident_str.as_str())
498                {
499                    return (WrapperKind::Atomic, None);
500                }
501            }
502        }
503    }
504    (WrapperKind::None, None)
505}
506
507/// Check if a field has the #[pin] attribute (pin_project pattern).
508fn field_has_pin_attr(field: &syn::Field) -> bool {
509    field
510        .attrs
511        .iter()
512        .any(|attr| attr.path().get_ident().map(|i| i == "pin").unwrap_or(false))
513}
514
515/// Check if a type is a Future (dyn Future, impl Future, or Box<dyn Future>).
516fn is_future_type(ty: &Type) -> bool {
517    use syn::{GenericArgument, PathArguments, TypeParamBound};
518
519    match ty {
520        Type::TraitObject(trait_obj) => trait_obj.bounds.iter().any(|b| {
521            if let TypeParamBound::Trait(t) = b {
522                t.path
523                    .segments
524                    .last()
525                    .map(|s| s.ident == "Future")
526                    .unwrap_or(false)
527            } else {
528                false
529            }
530        }),
531        Type::ImplTrait(impl_trait) => impl_trait.bounds.iter().any(|b| {
532            if let TypeParamBound::Trait(t) = b {
533                t.path
534                    .segments
535                    .last()
536                    .map(|s| s.ident == "Future")
537                    .unwrap_or(false)
538            } else {
539                false
540            }
541        }),
542        Type::Path(tp) => {
543            if let Some(seg) = tp.path.segments.last() {
544                match seg.ident.to_string().as_str() {
545                    "Box" | "Pin" => {
546                        if let PathArguments::AngleBracketed(args) = &seg.arguments {
547                            if let Some(GenericArgument::Type(inner)) = args.args.first() {
548                                return is_future_type(inner);
549                            }
550                        }
551                    }
552                    _ => {}
553                }
554            }
555            false
556        }
557        _ => false,
558    }
559}
560
561/// Extract Output type from Future trait bound (dyn Future<Output = T>, impl Future<Output = T>, etc.).
562fn extract_future_output(ty: &Type) -> Option<Type> {
563    use syn::{GenericArgument, PathArguments, TypeParamBound};
564
565    let bounds = match ty {
566        Type::TraitObject(t) => &t.bounds,
567        Type::ImplTrait(t) => &t.bounds,
568        Type::Path(tp) => {
569            if let Some(seg) = tp.path.segments.last() {
570                if matches!(seg.ident.to_string().as_str(), "Box" | "Pin") {
571                    if let PathArguments::AngleBracketed(args) = &seg.arguments {
572                        if let Some(GenericArgument::Type(inner)) = args.args.first() {
573                            return extract_future_output(inner);
574                        }
575                    }
576                }
577            }
578            return None;
579        }
580        _ => return None,
581    };
582
583    for bound in bounds {
584        if let TypeParamBound::Trait(trait_bound) = bound {
585            if let Some(seg) = trait_bound.path.segments.last() {
586                if seg.ident == "Future" {
587                    if let PathArguments::AngleBracketed(args) = &seg.arguments {
588                        for arg in &args.args {
589                            if let GenericArgument::AssocType(assoc) = arg {
590                                if assoc.ident == "Output" {
591                                    return Some(assoc.ty.clone());
592                                }
593                            }
594                        }
595                    }
596                }
597            }
598        }
599    }
600    None
601}
602
603/// For HashMap<K,V> or BTreeMap<K,V>, returns Some((key_ty, value_ty)).
604fn extract_map_key_value(ty: &Type) -> Option<(Type, Type)> {
605    use syn::{GenericArgument, PathArguments};
606
607    if let Type::Path(tp) = ty {
608        if let Some(seg) = tp.path.segments.last() {
609            let ident_str = seg.ident.to_string();
610            if ident_str == "HashMap" || ident_str == "BTreeMap" {
611                if let PathArguments::AngleBracketed(ab) = &seg.arguments {
612                    let args: Vec<_> = ab.args.iter().collect();
613                    if let (Some(key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
614                        if let (GenericArgument::Type(key_ty), GenericArgument::Type(value_ty)) =
615                            (key_arg, value_arg)
616                        {
617                            return Some((key_ty.clone(), value_ty.clone()));
618                        }
619                    }
620                }
621            }
622        }
623    }
624    None
625}
626
627/// For `Option<HashMap<K,V>>` / `Option<BTreeMap<K,V>>`, returns `Some((key_ty, value_ty))`.
628fn extract_map_key_value_through_option(ty: &Type) -> Option<(Type, Type)> {
629    use syn::{GenericArgument, PathArguments};
630
631    if let Type::Path(tp) = ty {
632        if let Some(seg) = tp.path.segments.last() {
633            if seg.ident == "Option" {
634                if let PathArguments::AngleBracketed(ab) = &seg.arguments {
635                    if let Some(GenericArgument::Type(inner)) = ab.args.first() {
636                        return extract_map_key_value(inner);
637                    }
638                }
639            }
640        }
641    }
642    None
643}
644
645fn to_snake_case(name: &str) -> String {
646    let mut out = String::new();
647    for (i, c) in name.chars().enumerate() {
648        if c.is_uppercase() {
649            if i != 0 {
650                out.push('_');
651            }
652            out.push(c.to_ascii_lowercase());
653        } else {
654            out.push(c);
655        }
656    }
657    out
658}
659
660/// Derive macro for generating simple keypath methods.
661///
662/// Generates one method per field: `StructName::field_name()` that returns a `Kp`.
663/// Intelligently handles wrapper types (Option, Vec, Box, Arc, etc.) to generate appropriate keypaths.
664///
665/// # Example
666///
667/// ```ignore
668/// #[derive(Kp)]
669/// struct Person {
670///     name: String,
671///     age: i32,
672///     email: Option<String>,
673///     addresses: Vec<String>,
674/// }
675///
676/// // Generates:
677/// // impl Person {
678/// //     pub fn name() -> Kp<...> { ... }
679/// //     pub fn age() -> Kp<...> { ... }
680/// //     pub fn email() -> Kp<...> { ... } // unwraps Option
681/// //     pub fn addresses() -> Kp<...> { ... } // accesses first element
682/// // }
683/// ```
684#[proc_macro_derive(Kp)]
685pub fn derive_keypaths(input: TokenStream) -> TokenStream {
686    let input = parse_macro_input!(input as DeriveInput);
687    let name = &input.ident;
688    let input_span = input.span();
689
690    let methods = match input.data {
691        Data::Struct(data_struct) => match data_struct.fields {
692            Fields::Named(fields_named) => {
693                let mut tokens = proc_macro2::TokenStream::new();
694
695                // Generate identity methods for the struct
696                tokens.extend(quote! {
697                    /// Returns a generic identity keypath for this type
698                    #[inline(always)]
699                    pub fn _identity<Root, MutRoot>() -> rust_key_paths::Kp<
700                        #name,
701                        #name,
702                        Root,
703                        Root,
704                        MutRoot,
705                        MutRoot,
706                        fn(Root) -> Option<Root>,
707                        fn(MutRoot) -> Option<MutRoot>,
708                    >
709                    where
710                        Root: std::borrow::Borrow<#name>,
711                        MutRoot: std::borrow::BorrowMut<#name>,
712                    {
713                        rust_key_paths::Kp::new(
714                            |r: Root| Some(r),
715                            |r: MutRoot| Some(r)
716                        )
717                    }
718
719                    // /// Returns a simple identity keypath for this type
720                    // #[inline(always)]
721                    // pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
722                    //     rust_key_paths::Kp::new(
723                    //         |r: &#name| Some(r),
724                    //         |r: &mut #name| Some(r)
725                    //     )
726                    // }
727                });
728
729                // When struct has #[pin] fields, generated code calls this.project() which must
730                // be provided by #[pin_project]. If missing, user gets: no method named `project`.
731
732                for field in fields_named.named.iter() {
733                    let field_ident = field.ident.as_ref().unwrap();
734                    let ty = &field.ty;
735                    // Centralized keypath method names – change here to adjust for all types
736                    let kp_fn = format_ident!("{}", field_ident);
737                    let kp_at_fn = format_ident!("{}_at", field_ident);
738
739                    let (kind, inner_ty) = extract_wrapper_inner_type(ty);
740
741                    // Override kind when field has #[pin] (pin_project pattern)
742                    let (kind, inner_ty) = if field_has_pin_attr(field) {
743                        let pinned_kind = if let Some(output_ty) = extract_future_output(ty) {
744                            if matches!(kind, WrapperKind::Box) {
745                                (WrapperKind::PinnedBoxFuture, Some(output_ty))
746                            } else {
747                                (WrapperKind::PinnedFuture, Some(output_ty))
748                            }
749                        } else if is_future_type(ty) {
750                            (WrapperKind::PinnedFuture, inner_ty.clone())
751                        } else {
752                            (WrapperKind::PinnedField, inner_ty.clone())
753                        };
754                        pinned_kind
755                    } else {
756                        (kind, inner_ty.clone())
757                    };
758
759                    match (kind, inner_ty) {
760                        (WrapperKind::Option, Some(inner_ty)) => {
761                            // For Option<T>, unwrap and access inner type
762                            tokens.extend(quote! {
763                                #[inline(always)]
764                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
765                                    rust_key_paths::Kp::new(
766                                        |root: &#name| root.#field_ident.as_ref(),
767                                        |root: &mut #name| root.#field_ident.as_mut(),
768                                    )
769                                }
770                            });
771                        }
772                        (WrapperKind::OptionBox, Some(inner_ty)) => {
773                            // For Option<Box<T>>, keypath to T: get returns Option<&T> via as_deref()
774                            tokens.extend(quote! {
775                                #[inline(always)]
776                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
777                                    rust_key_paths::Kp::new(
778                                        |root: &#name| root.#field_ident.as_deref(),
779                                        |root: &mut #name| root.#field_ident.as_deref_mut(),
780                                    )
781                                }
782                            });
783                        }
784                        (WrapperKind::OptionRc, Some(inner_ty)) => {
785                            // For Option<Rc<T>>, keypath to T: get returns Option<&T> via as_deref()
786                            // Setter: as_mut() gives Option<&mut Rc<T>>, and_then(Rc::get_mut) gives Option<&mut T>
787                            tokens.extend(quote! {
788                                #[inline(always)]
789                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
790                                    rust_key_paths::Kp::new(
791                                        |root: &#name| root.#field_ident.as_deref(),
792                                        |root: &mut #name| root.#field_ident.as_mut().and_then(std::rc::Rc::get_mut),
793                                    )
794                                }
795                            });
796                        }
797                        (WrapperKind::OptionArc, Some(inner_ty)) => {
798                            // For Option<Arc<T>>, keypath to T: get returns Option<&T> via as_deref()
799                            // Setter: as_mut() gives Option<&mut Arc<T>>, and_then(Arc::get_mut) gives Option<&mut T>
800                            tokens.extend(quote! {
801                                #[inline(always)]
802                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
803                                    rust_key_paths::Kp::new(
804                                        |root: &#name| root.#field_ident.as_deref(),
805                                        |root: &mut #name| root.#field_ident.as_mut().and_then(std::sync::Arc::get_mut),
806                                    )
807                                }
808                            });
809                        }
810                        (WrapperKind::OptionHashMap, Some(inner_ty)) => {
811                            if let Some((key_ty, _)) = extract_map_key_value_through_option(ty) {
812                                let type_name = name.to_string();
813                                let whole_fn = kp_fn.to_string();
814                                let at_fn = kp_at_fn.to_string();
815                                let whole_doc = format!(
816                                    "Keypath to the whole optional `HashMap` (`{type_name}::{whole_fn}`). For a value at one key when the map is `Some`, use `{type_name}::{at_fn}(key)`."
817                                );
818                                let at_doc = format!(
819                                    "Keyed access into the inner `HashMap` (`{type_name}::{at_fn}`). `get`/`get_mut` return `None` if the field is `None` or the key is missing. See also `{type_name}::{whole_fn}` for the full optional map."
820                                );
821                                tokens.extend(quote! {
822                                    #[doc = #whole_doc]
823                                    #[inline(always)]
824                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
825                                        rust_key_paths::Kp::new(
826                                            |root: &#name| Some(&root.#field_ident),
827                                            |root: &mut #name| Some(&mut root.#field_ident),
828                                        )
829                                    }
830                                    #[doc = #at_doc]
831                                    #[inline(always)]
832                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
833                                    where
834                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
835                                    {
836                                        let key2 = key.clone();
837                                        rust_key_paths::Kp::new(
838                                            Box::new(move |root: &#name| root.#field_ident.as_ref().and_then(|m| m.get(&key))),
839                                            Box::new(move |root: &mut #name| root.#field_ident.as_mut().and_then(|m| m.get_mut(&key2))),
840                                        )
841                                    }
842                                });
843                            } else {
844                                tokens.extend(quote! {
845                                    #[inline(always)]
846                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
847                                        rust_key_paths::Kp::new(
848                                            |root: &#name| Some(&root.#field_ident),
849                                            |root: &mut #name| Some(&mut root.#field_ident),
850                                        )
851                                    }
852                                });
853                            }
854                        }
855                        (WrapperKind::OptionBTreeMap, Some(inner_ty)) => {
856                            if let Some((key_ty, _)) = extract_map_key_value_through_option(ty) {
857                                let type_name = name.to_string();
858                                let whole_fn = kp_fn.to_string();
859                                let at_fn = kp_at_fn.to_string();
860                                let whole_doc = format!(
861                                    "Keypath to the whole optional `BTreeMap` (`{type_name}::{whole_fn}`). For a value at one key when the map is `Some`, use `{type_name}::{at_fn}(key)`."
862                                );
863                                let at_doc = format!(
864                                    "Keyed access into the inner `BTreeMap` (`{type_name}::{at_fn}`). `get`/`get_mut` return `None` if the field is `None` or the key is missing. See also `{type_name}::{whole_fn}` for the full optional map."
865                                );
866                                tokens.extend(quote! {
867                                    #[doc = #whole_doc]
868                                    #[inline(always)]
869                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
870                                        rust_key_paths::Kp::new(
871                                            |root: &#name| Some(&root.#field_ident),
872                                            |root: &mut #name| Some(&mut root.#field_ident),
873                                        )
874                                    }
875                                    #[doc = #at_doc]
876                                    #[inline(always)]
877                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
878                                    where
879                                        #key_ty: Clone + Ord + 'static,
880                                    {
881                                        let key2 = key.clone();
882                                        rust_key_paths::Kp::new(
883                                            Box::new(move |root: &#name| root.#field_ident.as_ref().and_then(|m| m.get(&key))),
884                                            Box::new(move |root: &mut #name| root.#field_ident.as_mut().and_then(|m| m.get_mut(&key2))),
885                                        )
886                                    }
887                                });
888                            } else {
889                                tokens.extend(quote! {
890                                    #[inline(always)]
891                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
892                                        rust_key_paths::Kp::new(
893                                            |root: &#name| Some(&root.#field_ident),
894                                            |root: &mut #name| Some(&mut root.#field_ident),
895                                        )
896                                    }
897                                });
898                            }
899                        }
900                        (WrapperKind::OptionHashSet, Some(inner_ty)) => {
901                            tokens.extend(quote! {
902                                #[inline(always)]
903                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
904                                    rust_key_paths::Kp::new(
905                                        |root: &#name| Some(&root.#field_ident),
906                                        |root: &mut #name| Some(&mut root.#field_ident),
907                                    )
908                                }
909
910                                /// _at: check if element exists and get reference.
911                                /// HashSet does not allow mutable element access (would break hash invariant).
912                                #[inline(always)]
913                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
914                                where
915                                    #inner_ty: Clone + std::hash::Hash + Eq + 'static,
916                                {
917                                    rust_key_paths::Kp::new(
918                                        Box::new(move |root: &#name| root.#field_ident.as_ref().and_then(|s| s.get(&key))),
919                                        Box::new(move |_root: &mut #name| None),
920                                    )
921                                }
922                            });
923                        }
924                        (WrapperKind::OptionBTreeSet, Some(inner_ty)) => {
925                            tokens.extend(quote! {
926                                #[inline(always)]
927                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
928                                    rust_key_paths::Kp::new(
929                                        |root: &#name| Some(&root.#field_ident),
930                                        |root: &mut #name| Some(&mut root.#field_ident),
931                                    )
932                                }
933
934                                /// _at: check if element exists and get reference.
935                                /// BTreeSet does not allow mutable element access (would break ordering invariant).
936                                #[inline(always)]
937                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
938                                where
939                                    #inner_ty: Clone + Ord + 'static,
940                                {
941                                    rust_key_paths::Kp::new(
942                                        Box::new(move |root: &#name| root.#field_ident.as_ref().and_then(|s| s.get(&key))),
943                                        Box::new(move |_root: &mut #name| None),
944                                    )
945                                }
946                            });
947                        }
948                        (WrapperKind::OptionVec, Some(inner_ty)) => {
949                            tokens.extend(quote! {
950                                #[inline(always)]
951                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
952                                    rust_key_paths::Kp::new(
953                                        |root: &#name| Some(&root.#field_ident),
954                                        |root: &mut #name| Some(&mut root.#field_ident),
955                                    )
956                                }
957                                #[inline(always)]
958                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
959                                    rust_key_paths::Kp::new(
960                                        Box::new(move |root: &#name| root.#field_ident.as_ref().and_then(|v| v.get(index))),
961                                        Box::new(move |root: &mut #name| root.#field_ident.as_mut().and_then(|v| v.get_mut(index))),
962                                    )
963                                }
964                            });
965                        }
966                        (WrapperKind::OptionVecDeque, Some(inner_ty)) => {
967                            tokens.extend(quote! {
968                                #[inline(always)]
969                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
970                                    rust_key_paths::Kp::new(
971                                        |root: &#name| Some(&root.#field_ident),
972                                        |root: &mut #name| Some(&mut root.#field_ident),
973                                    )
974                                }
975                                #[inline(always)]
976                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
977                                    rust_key_paths::Kp::new(
978                                        Box::new(move |root: &#name| root.#field_ident.as_ref().and_then(|v| v.get(index))),
979                                        Box::new(move |root: &mut #name| root.#field_ident.as_mut().and_then(|v| v.get_mut(index))),
980                                    )
981                                }
982                            });
983                        }
984                        (WrapperKind::OptionLinkedList, Some(_inner_ty))
985                        | (WrapperKind::OptionBinaryHeap, Some(_inner_ty))
986                        | (WrapperKind::OptionResult, Some(_inner_ty)) => {
987                            // Keypath to the Option container (reference), like Vec/HashSet
988                            tokens.extend(quote! {
989                                #[inline(always)]
990                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
991                                    rust_key_paths::Kp::new(
992                                        |root: &#name| Some(&root.#field_ident),
993                                        |root: &mut #name| Some(&mut root.#field_ident),
994                                    )
995                                }
996                            });
997                        }
998                        (WrapperKind::Vec, Some(inner_ty)) => {
999                            tokens.extend(quote! {
1000                                #[inline(always)]
1001                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1002                                    rust_key_paths::Kp::new(
1003                                        |root: &#name| Some(&root.#field_ident),
1004                                        |root: &mut #name| Some(&mut root.#field_ident),
1005                                    )
1006                                }
1007                                #[inline(always)]
1008                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1009                                    rust_key_paths::Kp::new(
1010                                        Box::new(move |root: &#name| root.#field_ident.get(index)),
1011                                        Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
1012                                    )
1013                                }
1014                            });
1015                        }
1016                        (WrapperKind::HashMap, Some(inner_ty)) => {
1017                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
1018                                tokens.extend(quote! {
1019                                    #[inline(always)]
1020                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1021                                        rust_key_paths::Kp::new(
1022                                            |root: &#name| Some(&root.#field_ident),
1023                                            |root: &mut #name| Some(&mut root.#field_ident),
1024                                        )
1025                                    }
1026                                    #[inline(always)]
1027                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1028                                    where
1029                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
1030                                    {
1031                                        let key2 = key.clone();
1032                                        rust_key_paths::Kp::new(
1033                                            Box::new(move |root: &#name| root.#field_ident.get(&key)),
1034                                            Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
1035                                        )
1036                                    }
1037                                });
1038                            } else {
1039                                tokens.extend(quote! {
1040                                    #[inline(always)]
1041                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1042                                        rust_key_paths::Kp::new(
1043                                            |root: &#name| Some(&root.#field_ident),
1044                                            |root: &mut #name| Some(&mut root.#field_ident),
1045                                        )
1046                                    }
1047                                });
1048                            }
1049                        }
1050                        (WrapperKind::BTreeMap, Some(inner_ty))
1051                        | (WrapperKind::BTreeMapOption, Some(inner_ty)) => {
1052                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
1053                                tokens.extend(quote! {
1054                                    #[inline(always)]
1055                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1056                                        rust_key_paths::Kp::new(
1057                                            |root: &#name| Some(&root.#field_ident),
1058                                            |root: &mut #name| Some(&mut root.#field_ident),
1059                                        )
1060                                    }
1061                                    #[inline(always)]
1062                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1063                                    where
1064                                        #key_ty: Clone + Ord + 'static,
1065                                    {
1066                                        let key2 = key.clone();
1067                                        rust_key_paths::Kp::new(
1068                                            Box::new(move |root: &#name| root.#field_ident.get(&key)),
1069                                            Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
1070                                        )
1071                                    }
1072                                });
1073                            } else {
1074                                tokens.extend(quote! {
1075                                    #[inline(always)]
1076                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1077                                        rust_key_paths::Kp::new(
1078                                            |root: &#name| Some(&root.#field_ident),
1079                                            |root: &mut #name| Some(&mut root.#field_ident),
1080                                        )
1081                                    }
1082                                });
1083                            }
1084                        }
1085                        (WrapperKind::Box, Some(inner_ty)) => {
1086                            // For Box<T>, deref to inner type (returns &T / &mut T, not &Box<T>)
1087                            tokens.extend(quote! {
1088                                #[inline(always)]
1089                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1090                                    rust_key_paths::Kp::new(
1091                                        |root: &#name| Some(&*root.#field_ident),
1092                                        |root: &mut #name| Some(&mut *root.#field_ident),
1093                                    )
1094                                }
1095                            });
1096                        }
1097                        (WrapperKind::BoxOption, Some(inner_ty)) => {
1098                            // For Box<Option<T>>, keypath to T: deref Box to Option<T>, then Option::as_ref/as_mut
1099                            tokens.extend(quote! {
1100                                #[inline(always)]
1101                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1102                                    rust_key_paths::Kp::new(
1103                                        |root: &#name| (&*root.#field_ident).as_ref(),
1104                                        |root: &mut #name| (&mut *root.#field_ident).as_mut(),
1105                                    )
1106                                }
1107                            });
1108                        }
1109                        (WrapperKind::RcOption, Some(inner_ty)) => {
1110                            // For Rc<Option<T>>, keypath to T: deref Rc to &Option<T>, then Option::as_ref; set = Rc::get_mut then as_mut
1111                            tokens.extend(quote! {
1112                                #[inline(always)]
1113                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1114                                    rust_key_paths::Kp::new(
1115                                        |root: &#name| (&*root.#field_ident).as_ref(),
1116                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#field_ident).and_then(std::option::Option::as_mut),
1117                                    )
1118                                }
1119                            });
1120                        }
1121                        (WrapperKind::ArcOption, Some(inner_ty)) => {
1122                            // For Arc<Option<T>>, keypath to T: deref Arc to &Option<T>, then Option::as_ref; set = Arc::get_mut then as_mut
1123                            tokens.extend(quote! {
1124                                #[inline(always)]
1125                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1126                                    rust_key_paths::Kp::new(
1127                                        |root: &#name| (&*root.#field_ident).as_ref(),
1128                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#field_ident).and_then(std::option::Option::as_mut),
1129                                    )
1130                                }
1131                            });
1132                        }
1133                        (WrapperKind::Pin, Some(inner_ty)) => {
1134                            let kp_inner_fn = format_ident!("{}_inner", field_ident);
1135                            tokens.extend(quote! {
1136                                #[inline(always)]
1137                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1138                                    rust_key_paths::Kp::new(
1139                                        |root: &#name| Some(&root.#field_ident),
1140                                        |root: &mut #name| Some(&mut root.#field_ident),
1141                                    )
1142                                }
1143                                #[inline(always)]
1144                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
1145                                where #inner_ty: std::marker::Unpin
1146                                {
1147                                    rust_key_paths::Kp::new(
1148                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#field_ident).get_ref()),
1149                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#field_ident).get_mut()),
1150                                    )
1151                                }
1152                            });
1153                        }
1154                        (WrapperKind::PinBox, Some(inner_ty)) => {
1155                            let kp_inner_fn = format_ident!("{}_inner", 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                                #[inline(always)]
1165                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
1166                                where #inner_ty: std::marker::Unpin
1167                                {
1168                                    // Pin::as_ref on Pin<Box<T>> returns Pin<&T> (Box Deref target), so get_ref() already gives &T
1169                                    rust_key_paths::Kp::new(
1170                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#field_ident).get_ref()),
1171                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#field_ident).get_mut()),
1172                                    )
1173                                }
1174                            });
1175                        }
1176                        (WrapperKind::PinnedField, _) => {
1177                            let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
1178                            tokens.extend(quote! {
1179                                #[inline(always)]
1180                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1181                                    rust_key_paths::Kp::new(
1182                                        |root: &#name| Some(&root.#field_ident),
1183                                        |root: &mut #name| Some(&mut root.#field_ident),
1184                                    )
1185                                }
1186                                /// Pinned projection for #[pin] field. Requires #[pin_project] on struct.
1187                                #[inline(always)]
1188                                pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
1189                                    this.project().#field_ident
1190                                }
1191                            });
1192                        }
1193                        (WrapperKind::PinnedFuture, _) => {
1194                            let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
1195                            let kp_await_fn = format_ident!("{}_await", field_ident);
1196                            let kp_pin_future_fn = format_ident!("{}_pin_future_kp", field_ident);
1197                            let output_ty = quote! { <#ty as std::future::Future>::Output };
1198                            tokens.extend(quote! {
1199                                #[inline(always)]
1200                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1201                                    rust_key_paths::Kp::new(
1202                                        |root: &#name| Some(&root.#field_ident),
1203                                        |root: &mut #name| Some(&mut root.#field_ident),
1204                                    )
1205                                }
1206                                /// Pinned projection for #[pin] Future field. Requires #[pin_project] on struct.
1207                                #[inline(always)]
1208                                pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
1209                                    this.project().#field_ident
1210                                }
1211                                /// Poll the pinned future. Requires #[pin_project] on struct.
1212                                pub async fn #kp_await_fn(this: std::pin::Pin<&mut #name>) -> Option<#output_ty>
1213                                where #ty: std::future::Future
1214                                {
1215                                    use std::future::Future;
1216                                    Some(this.project().#field_ident.await)
1217                                }
1218                                /// Keypath for [rust_key_paths::Kp::then_pin_future]. Composable pin future await.
1219                                #[inline(always)]
1220                                pub fn #kp_pin_future_fn() -> impl rust_key_paths::pin::PinFutureAwaitLike<#name, #output_ty> {
1221                                    rust_key_paths::pin_future_await_kp!(#name, #kp_await_fn -> #output_ty)
1222                                }
1223                            });
1224                        }
1225                        (WrapperKind::PinnedBoxFuture, Some(output_ty)) => {
1226                            let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
1227                            let kp_await_fn = format_ident!("{}_await", field_ident);
1228                            let kp_pin_future_fn = format_ident!("{}_pin_future_kp", field_ident);
1229                            tokens.extend(quote! {
1230                                #[inline(always)]
1231                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1232                                    rust_key_paths::Kp::new(
1233                                        |root: &#name| Some(&root.#field_ident),
1234                                        |root: &mut #name| Some(&mut root.#field_ident),
1235                                    )
1236                                }
1237                                /// Pinned projection for #[pin] Box<dyn Future> field. Requires #[pin_project] on struct.
1238                                #[inline(always)]
1239                                pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
1240                                    this.project().#field_ident
1241                                }
1242                                /// Poll the pinned boxed future. Requires #[pin_project] on struct.
1243                                pub async fn #kp_await_fn(this: std::pin::Pin<&mut #name>) -> Option<#output_ty> {
1244                                    Some(this.project().#field_ident.await)
1245                                }
1246                                /// Keypath for [rust_key_paths::Kp::then_pin_future]. Composable pin future await.
1247                                #[inline(always)]
1248                                pub fn #kp_pin_future_fn() -> impl rust_key_paths::pin::PinFutureAwaitLike<#name, #output_ty> {
1249                                    rust_key_paths::pin_future_await_kp!(#name, #kp_await_fn -> #output_ty)
1250                                }
1251                            });
1252                        }
1253                        (WrapperKind::Rc, Some(inner_ty)) => {
1254                            // For Rc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
1255                            tokens.extend(quote! {
1256                                #[inline(always)]
1257                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1258                                    rust_key_paths::Kp::new(
1259                                        |root: &#name| Some(root.#field_ident.as_ref()),
1260                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#field_ident),
1261                                    )
1262                                }
1263                            });
1264                        }
1265                        (WrapperKind::Arc, Some(inner_ty)) => {
1266                            // For Arc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
1267                            tokens.extend(quote! {
1268                                #[inline(always)]
1269                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1270                                    rust_key_paths::Kp::new(
1271                                        |root: &#name| Some(root.#field_ident.as_ref()),
1272                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#field_ident),
1273                                    )
1274                                }
1275                            });
1276                        }
1277                        (WrapperKind::Cow, Some(inner_ty)) => {
1278                            // For Cow<'_, B>, deref to inner type (as_ref/to_mut)
1279                            tokens.extend(quote! {
1280                                #[inline(always)]
1281                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1282                                    rust_key_paths::Kp::new(
1283                                        |root: &#name| Some(root.#field_ident.as_ref()),
1284                                        |root: &mut #name| Some(root.#field_ident.to_mut()),
1285                                    )
1286                                }
1287                            });
1288                        }
1289
1290                        (WrapperKind::OptionCow, Some(inner_ty)) => {
1291                            // For Option<Cow<'_, B>>
1292                            tokens.extend(quote! {
1293                                #[inline(always)]
1294                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1295                                    rust_key_paths::Kp::new(
1296                                        |root: &#name| root.#field_ident.as_ref().map(|c| c.as_ref()),
1297                                        |root: &mut #name| root.#field_ident.as_mut().map(|c| c.to_mut()),
1298                                    )
1299                                }
1300                            });
1301                        }
1302                        (WrapperKind::OptionTagged, Some(inner_ty)) => {
1303                            // For Option<Tagged<Tag, T>> - Tagged implements Deref/DerefMut
1304                            tokens.extend(quote! {
1305                                #[inline(always)]
1306                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1307                                    rust_key_paths::Kp::new(
1308                                        |root: &#name| root.#field_ident.as_ref().map(|t| std::ops::Deref::deref(t)),
1309                                        |root: &mut #name| root.#field_ident.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
1310                                    )
1311                                }
1312                            });
1313                        }
1314                        (WrapperKind::OptionReference, Some(inner_ty)) => {
1315                            // For Option<&T>, Option<&str>, Option<&[T]> - read-only, setter returns None
1316                            tokens.extend(quote! {
1317                                #[inline(always)]
1318                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1319                                    rust_key_paths::Kp::new(
1320                                        |root: &#name| root.#field_ident.as_ref(),
1321                                        |_root: &mut #name| None,
1322                                    )
1323                                }
1324                            });
1325                        }
1326                        (WrapperKind::HashSet, Some(inner_ty))
1327                        | (WrapperKind::HashSetOption, Some(inner_ty)) => {
1328                            let kp_at_fn = format_ident!("{}_at", field_ident);
1329
1330                            tokens.extend(quote! {
1331                                #[inline(always)]
1332                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1333                                    rust_key_paths::Kp::new(
1334                                        |root: &#name| Some(&root.#field_ident),
1335                                        |root: &mut #name| Some(&mut root.#field_ident),
1336                                    )
1337                                }
1338
1339                                /// _at: check if element exists and get reference.
1340                                /// HashSet does not allow mutable element access (would break hash invariant).
1341                                #[inline(always)]
1342                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1343                                where
1344                                    #inner_ty: Clone + std::hash::Hash + Eq + 'static,
1345                                {
1346                                    rust_key_paths::Kp::new(
1347                                        Box::new(move |root: &#name| root.#field_ident.get(&key)),
1348                                        Box::new(move |_root: &mut #name| None),
1349                                    )
1350                                }
1351                            });
1352                        }
1353                        (WrapperKind::BTreeSet, Some(inner_ty))
1354                        | (WrapperKind::BTreeSetOption, Some(inner_ty)) => {
1355                            let kp_at_fn = format_ident!("{}_at", field_ident);
1356
1357                            tokens.extend(quote! {
1358                                #[inline(always)]
1359                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1360                                    rust_key_paths::Kp::new(
1361                                        |root: &#name| Some(&root.#field_ident),
1362                                        |root: &mut #name| Some(&mut root.#field_ident),
1363                                    )
1364                                }
1365
1366                                /// _at: check if element exists and get reference.
1367                                /// BTreeSet does not allow mutable element access (would break ordering invariant).
1368                                #[inline(always)]
1369                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1370                                where
1371                                    #inner_ty: Clone + Ord + 'static,
1372                                {
1373                                    rust_key_paths::Kp::new(
1374                                        Box::new(move |root: &#name| root.#field_ident.get(&key)),
1375                                        Box::new(move |_root: &mut #name| None),
1376                                    )
1377                                }
1378                            });
1379                        }
1380                        (WrapperKind::VecDeque, Some(inner_ty))
1381                        | (WrapperKind::VecDequeOption, Some(inner_ty)) => {
1382                            tokens.extend(quote! {
1383                                #[inline(always)]
1384                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1385                                    rust_key_paths::Kp::new(
1386                                        |root: &#name| Some(&root.#field_ident),
1387                                        |root: &mut #name| Some(&mut root.#field_ident),
1388                                    )
1389                                }
1390                                #[inline(always)]
1391                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1392                                    rust_key_paths::Kp::new(
1393                                        Box::new(move |root: &#name| root.#field_ident.get(index)),
1394                                        Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
1395                                    )
1396                                }
1397                            });
1398                        }
1399                        (WrapperKind::LinkedList, Some(_inner_ty))
1400                        | (WrapperKind::LinkedListOption, Some(_inner_ty)) => {
1401                            tokens.extend(quote! {
1402                                #[inline(always)]
1403                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1404                                    rust_key_paths::Kp::new(
1405                                        |root: &#name| Some(&root.#field_ident),
1406                                        |root: &mut #name| Some(&mut root.#field_ident),
1407                                    )
1408                                }
1409                            });
1410                        }
1411                        (WrapperKind::BinaryHeap, Some(_inner_ty))
1412                        | (WrapperKind::BinaryHeapOption, Some(_inner_ty)) => {
1413                            tokens.extend(quote! {
1414                                #[inline(always)]
1415                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1416                                    rust_key_paths::Kp::new(
1417                                        |root: &#name| Some(&root.#field_ident),
1418                                        |root: &mut #name| Some(&mut root.#field_ident),
1419                                    )
1420                                }
1421                            });
1422                        }
1423                        (WrapperKind::Result, Some(inner_ty)) => {
1424                            // For Result<T, E>, access Ok value
1425                            tokens.extend(quote! {
1426                                #[inline(always)]
1427                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1428                                    rust_key_paths::Kp::new(
1429                                        |root: &#name| root.#field_ident.as_ref().ok(),
1430                                        |root: &mut #name| root.#field_ident.as_mut().ok(),
1431                                    )
1432                                }
1433                            });
1434                        }
1435                        (WrapperKind::StdArcMutex, Some(inner_ty)) => {
1436                            // For Arc<std::sync::Mutex<T>>
1437                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1438                            tokens.extend(quote! {
1439                                #[inline(always)]
1440                                    pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1441                                    rust_key_paths::Kp::new(
1442                                        |root: &#name| Some(&root.#field_ident),
1443                                        |root: &mut #name| Some(&mut root.#field_ident),
1444                                    )
1445                                }
1446                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #ty, #inner_ty> {
1447                                    rust_key_paths::lock::LockKp::new(
1448                                        rust_key_paths::Kp::new(
1449                                            |root: &#name| Some(&root.#field_ident),
1450                                            |root: &mut #name| Some(&mut root.#field_ident),
1451                                        ),
1452                                        rust_key_paths::lock::ArcMutexAccess::new(),
1453                                        rust_key_paths::Kp::new(
1454                                            |v: &#inner_ty| Some(v),
1455                                            |v: &mut #inner_ty| Some(v),
1456                                        ),
1457                                    )
1458                                }
1459                            });
1460                        }
1461                        (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
1462                            // For Arc<std::sync::RwLock<T>>
1463                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1464                            tokens.extend(quote! {
1465                                #[inline(always)]
1466                                    pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1467                                    rust_key_paths::Kp::new(
1468                                        |root: &#name| Some(&root.#field_ident),
1469                                        |root: &mut #name| Some(&mut root.#field_ident),
1470                                    )
1471                                }
1472                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #ty, #inner_ty> {
1473                                    rust_key_paths::lock::LockKp::new(
1474                                        rust_key_paths::Kp::new(
1475                                            |root: &#name| Some(&root.#field_ident),
1476                                            |root: &mut #name| Some(&mut root.#field_ident),
1477                                        ),
1478                                        rust_key_paths::lock::ArcRwLockAccess::new(),
1479                                        rust_key_paths::Kp::new(
1480                                            |v: &#inner_ty| Some(v),
1481                                            |v: &mut #inner_ty| Some(v),
1482                                        ),
1483                                    )
1484                                }
1485                            });
1486                        }
1487                        (WrapperKind::StdArcMutexOption, Some(inner_ty)) => {
1488                            // For Arc<std::sync::Mutex<Option<T>>> — LockKp value T (extract from Option); guard gives &Option<T>
1489                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1490                            tokens.extend(quote! {
1491                                #[inline(always)]
1492                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1493                                    rust_key_paths::Kp::new(
1494                                        |root: &#name| Some(&root.#field_ident),
1495                                        |root: &mut #name| Some(&mut root.#field_ident),
1496                                    )
1497                                }
1498                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcMutexOptionFor<#name, #ty, #inner_ty> {
1499                                    rust_key_paths::lock::LockKp::new(
1500                                        rust_key_paths::Kp::new(
1501                                            |root: &#name| Some(&root.#field_ident),
1502                                            |root: &mut #name| Some(&mut root.#field_ident),
1503                                        ),
1504                                        rust_key_paths::lock::ArcMutexAccess::<Option<#inner_ty>>::new(),
1505                                        rust_key_paths::Kp::new(
1506                                            Option::<#inner_ty>::as_ref,
1507                                            Option::<#inner_ty>::as_mut,
1508                                        ),
1509                                    )
1510                                }
1511                            });
1512                        }
1513                        (WrapperKind::StdArcRwLockOption, Some(inner_ty)) => {
1514                            // For Arc<std::sync::RwLock<Option<T>>> — LockKp value T (extract from Option); guard gives &Option<T>
1515                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1516                            tokens.extend(quote! {
1517                                #[inline(always)]
1518                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1519                                    rust_key_paths::Kp::new(
1520                                        |root: &#name| Some(&root.#field_ident),
1521                                        |root: &mut #name| Some(&mut root.#field_ident),
1522                                    )
1523                                }
1524                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcRwLockOptionFor<#name, #ty, #inner_ty> {
1525                                    rust_key_paths::lock::LockKp::new(
1526                                        rust_key_paths::Kp::new(
1527                                            |root: &#name| Some(&root.#field_ident),
1528                                            |root: &mut #name| Some(&mut root.#field_ident),
1529                                        ),
1530                                        rust_key_paths::lock::ArcRwLockAccess::<Option<#inner_ty>>::new(),
1531                                        rust_key_paths::Kp::new(
1532                                            Option::<#inner_ty>::as_ref,
1533                                            Option::<#inner_ty>::as_mut,
1534                                        ),
1535                                    )
1536                                }
1537                            });
1538                        }
1539                        (WrapperKind::ArcRwLock, Some(inner_ty)) => {
1540                            // For Arc<parking_lot::RwLock<T>> (requires rust-key-paths "parking_lot" feature)
1541                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1542                            tokens.extend(quote! {
1543                                #[inline(always)]
1544                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1545                                    rust_key_paths::Kp::new(
1546                                        |root: &#name| Some(&root.#field_ident),
1547                                        |root: &mut #name| Some(&mut root.#field_ident),
1548                                    )
1549                                }
1550                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #ty, #inner_ty> {
1551                                    rust_key_paths::lock::LockKp::new(
1552                                        rust_key_paths::Kp::new(
1553                                            |root: &#name| Some(&root.#field_ident),
1554                                            |root: &mut #name| Some(&mut root.#field_ident),
1555                                        ),
1556                                        rust_key_paths::lock::ParkingLotRwLockAccess::new(),
1557                                        rust_key_paths::Kp::new(
1558                                            |v: &#inner_ty| Some(v),
1559                                            |v: &mut #inner_ty| Some(v),
1560                                        ),
1561                                    )
1562                                }
1563                            });
1564                        }
1565                        (WrapperKind::ArcMutex, Some(inner_ty)) => {
1566                            // For Arc<parking_lot::Mutex<T>> (requires rust-key-paths "parking_lot" feature)
1567                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1568                            tokens.extend(quote! {
1569                                #[inline(always)]
1570                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1571                                    rust_key_paths::Kp::new(
1572                                        |root: &#name| Some(&root.#field_ident),
1573                                        |root: &mut #name| Some(&mut root.#field_ident),
1574                                    )
1575                                }
1576                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #ty, #inner_ty> {
1577                                    rust_key_paths::lock::LockKp::new(
1578                                        rust_key_paths::Kp::new(
1579                                            |root: &#name| Some(&root.#field_ident),
1580                                            |root: &mut #name| Some(&mut root.#field_ident),
1581                                        ),
1582                                        rust_key_paths::lock::ParkingLotMutexAccess::new(),
1583                                        rust_key_paths::Kp::new(
1584                                            |v: &#inner_ty| Some(v),
1585                                            |v: &mut #inner_ty| Some(v),
1586                                        ),
1587                                    )
1588                                }
1589                            });
1590                        }
1591                        (WrapperKind::ArcMutexOption, Some(inner_ty)) => {
1592                            // For Arc<parking_lot::Mutex<Option<T>>> — LockKp value T (extract from Option); guard gives &Option<T>
1593                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1594                            tokens.extend(quote! {
1595                                #[inline(always)]
1596                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1597                                    rust_key_paths::Kp::new(
1598                                        |root: &#name| Some(&root.#field_ident),
1599                                        |root: &mut #name| Some(&mut root.#field_ident),
1600                                    )
1601                                }
1602                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotMutexOptionFor<#name, #ty, #inner_ty> {
1603                                    rust_key_paths::lock::LockKp::new(
1604                                        rust_key_paths::Kp::new(
1605                                            |root: &#name| Some(&root.#field_ident),
1606                                            |root: &mut #name| Some(&mut root.#field_ident),
1607                                        ),
1608                                        rust_key_paths::lock::ParkingLotMutexAccess::<Option<#inner_ty>>::new(),
1609                                        rust_key_paths::Kp::new(
1610                                            Option::<#inner_ty>::as_ref,
1611                                            Option::<#inner_ty>::as_mut,
1612                                        ),
1613                                    )
1614                                }
1615                            });
1616                        }
1617                        (WrapperKind::ArcRwLockOption, Some(inner_ty)) => {
1618                            // For Arc<parking_lot::RwLock<Option<T>>> — LockKp value T (extract from Option); guard gives &Option<T>
1619                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1620                            tokens.extend(quote! {
1621                                #[inline(always)]
1622                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1623                                    rust_key_paths::Kp::new(
1624                                        |root: &#name| Some(&root.#field_ident),
1625                                        |root: &mut #name| Some(&mut root.#field_ident),
1626                                    )
1627                                }
1628                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockOptionFor<#name, #ty, #inner_ty> {
1629                                    rust_key_paths::lock::LockKp::new(
1630                                        rust_key_paths::Kp::new(
1631                                            |root: &#name| Some(&root.#field_ident),
1632                                            |root: &mut #name| Some(&mut root.#field_ident),
1633                                        ),
1634                                        rust_key_paths::lock::ParkingLotRwLockAccess::<Option<#inner_ty>>::new(),
1635                                        rust_key_paths::Kp::new(
1636                                            Option::<#inner_ty>::as_ref,
1637                                            Option::<#inner_ty>::as_mut,
1638                                        ),
1639                                    )
1640                                }
1641                            });
1642                        }
1643                        (WrapperKind::Mutex, Some(_inner_ty))
1644                        | (WrapperKind::StdMutex, Some(_inner_ty)) => {
1645                            // For Mutex<T>, return keypath to container
1646                            tokens.extend(quote! {
1647                                #[inline(always)]
1648                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1649                                    rust_key_paths::Kp::new(
1650                                        |root: &#name| Some(&root.#field_ident),
1651                                        |root: &mut #name| Some(&mut root.#field_ident),
1652                                    )
1653                                }
1654                            });
1655                        }
1656                        (WrapperKind::RwLock, Some(_inner_ty))
1657                        | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
1658                            // For RwLock<T>, return keypath to container
1659                            tokens.extend(quote! {
1660                                #[inline(always)]
1661                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1662                                    rust_key_paths::Kp::new(
1663                                        |root: &#name| Some(&root.#field_ident),
1664                                        |root: &mut #name| Some(&mut root.#field_ident),
1665                                    )
1666                                }
1667                            });
1668                        }
1669                        (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
1670                            let kp_async_fn = format_ident!("{}_kp", field_ident);
1671                            tokens.extend(quote! {
1672                                #[inline(always)]
1673                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1674                                    rust_key_paths::Kp::new(
1675                                        |root: &#name| Some(&root.#field_ident),
1676                                        |root: &mut #name| Some(&mut root.#field_ident),
1677                                    )
1678                                }
1679                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
1680                                    rust_key_paths::async_lock::AsyncLockKp::new(
1681                                        rust_key_paths::Kp::new(
1682                                            |root: &#name| Some(&root.#field_ident),
1683                                            |root: &mut #name| Some(&mut root.#field_ident),
1684                                        ),
1685                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
1686                                        rust_key_paths::Kp::new(
1687                                            |v: &#inner_ty| Some(v),
1688                                            |v: &mut #inner_ty| Some(v),
1689                                        ),
1690                                    )
1691                                }
1692                            });
1693                        }
1694                        (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
1695                            let kp_async_fn = format_ident!("{}_kp", field_ident);
1696                            tokens.extend(quote! {
1697                                #[inline(always)]
1698                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1699                                    rust_key_paths::Kp::new(
1700                                        |root: &#name| Some(&root.#field_ident),
1701                                        |root: &mut #name| Some(&mut root.#field_ident),
1702                                    )
1703                                }
1704                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
1705                                    rust_key_paths::async_lock::AsyncLockKp::new(
1706                                        rust_key_paths::Kp::new(
1707                                            |root: &#name| Some(&root.#field_ident),
1708                                            |root: &mut #name| Some(&mut root.#field_ident),
1709                                        ),
1710                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
1711                                        rust_key_paths::Kp::new(
1712                                            |v: &#inner_ty| Some(v),
1713                                            |v: &mut #inner_ty| Some(v),
1714                                        ),
1715                                    )
1716                                }
1717                            });
1718                        }
1719                        (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
1720                            let kp_async_fn = format_ident!("{}_kp", field_ident);
1721                            tokens.extend(quote! {
1722                                #[inline(always)]
1723                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1724                                    rust_key_paths::Kp::new(
1725                                        |root: &#name| Some(&root.#field_ident),
1726                                        |root: &mut #name| Some(&mut root.#field_ident),
1727                                    )
1728                                }
1729                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
1730                                    rust_key_paths::async_lock::AsyncLockKp::new(
1731                                        rust_key_paths::Kp::new(
1732                                            |root: &#name| root.#field_ident.as_ref(),
1733                                            |root: &mut #name| root.#field_ident.as_mut(),
1734                                        ),
1735                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
1736                                        rust_key_paths::Kp::new(
1737                                            |v: &#inner_ty| Some(v),
1738                                            |v: &mut #inner_ty| Some(v),
1739                                        ),
1740                                    )
1741                                }
1742                            });
1743                        }
1744                        (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
1745                            let kp_async_fn = format_ident!("{}_kp", field_ident);
1746                            tokens.extend(quote! {
1747                                #[inline(always)]
1748                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1749                                    rust_key_paths::Kp::new(
1750                                        |root: &#name| Some(&root.#field_ident),
1751                                        |root: &mut #name| Some(&mut root.#field_ident),
1752                                    )
1753                                }
1754                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
1755                                    rust_key_paths::async_lock::AsyncLockKp::new(
1756                                        rust_key_paths::Kp::new(
1757                                            |root: &#name| root.#field_ident.as_ref(),
1758                                            |root: &mut #name| root.#field_ident.as_mut(),
1759                                        ),
1760                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
1761                                        rust_key_paths::Kp::new(
1762                                            |v: &#inner_ty| Some(v),
1763                                            |v: &mut #inner_ty| Some(v),
1764                                        ),
1765                                    )
1766                                }
1767                            });
1768                        }
1769                        (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
1770                            // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1771                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1772                            tokens.extend(quote! {
1773                                #[inline(always)]
1774                                    pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1775                                    rust_key_paths::Kp::new(
1776                                        |root: &#name| Some(&root.#field_ident),
1777                                        |root: &mut #name| Some(&mut root.#field_ident),
1778                                    )
1779                                }
1780                                // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
1781                                //     rust_key_paths::Kp::new(
1782                                //         |root: &#name| root.#field_ident.as_ref(),
1783                                //         |root: &mut #name| root.#field_ident.as_mut(),
1784                                //     )
1785                                // }
1786                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
1787                                    rust_key_paths::lock::LockKp::new(
1788                                        rust_key_paths::Kp::new(
1789                                            |root: &#name| root.#field_ident.as_ref(),
1790                                            |root: &mut #name| root.#field_ident.as_mut(),
1791                                        ),
1792                                        rust_key_paths::lock::ArcMutexAccess::new(),
1793                                        rust_key_paths::Kp::new(
1794                                            |v: &#inner_ty| Some(v),
1795                                            |v: &mut #inner_ty| Some(v),
1796                                        ),
1797                                    )
1798                                }
1799                            });
1800                        }
1801                        (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
1802                            // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1803                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1804                            tokens.extend(quote! {
1805                                #[inline(always)]
1806                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1807                                    rust_key_paths::Kp::new(
1808                                        |root: &#name| Some(&root.#field_ident),
1809                                        |root: &mut #name| Some(&mut root.#field_ident),
1810                                    )
1811                                }
1812                                // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
1813                                //     rust_key_paths::Kp::new(
1814                                //         |root: &#name| root.#field_ident.as_ref(),
1815                                //         |root: &mut #name| root.#field_ident.as_mut(),
1816                                //     )
1817                                // }
1818                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>, #inner_ty> {
1819                                    rust_key_paths::lock::LockKp::new(
1820                                        rust_key_paths::Kp::new(
1821                                            |root: &#name| root.#field_ident.as_ref(),
1822                                            |root: &mut #name| root.#field_ident.as_mut(),
1823                                        ),
1824                                        rust_key_paths::lock::ParkingLotMutexAccess::new(),
1825                                        rust_key_paths::Kp::new(
1826                                            |v: &#inner_ty| Some(v),
1827                                            |v: &mut #inner_ty| Some(v),
1828                                        ),
1829                                    )
1830                                }
1831                            });
1832                        }
1833                        (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
1834                            // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1835                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1836                            tokens.extend(quote! {
1837                                #[inline(always)]
1838                                    pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1839                                    rust_key_paths::Kp::new(
1840                                        |root: &#name| Some(&root.#field_ident),
1841                                        |root: &mut #name| Some(&mut root.#field_ident),
1842                                    )
1843                                }
1844                                // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
1845                                //     rust_key_paths::Kp::new(
1846                                //         |root: &#name| root.#field_ident.as_ref(),
1847                                //         |root: &mut #name| root.#field_ident.as_mut(),
1848                                //     )
1849                                // }
1850                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
1851                                    rust_key_paths::lock::LockKp::new(
1852                                        rust_key_paths::Kp::new(
1853                                            |root: &#name| root.#field_ident.as_ref(),
1854                                            |root: &mut #name| root.#field_ident.as_mut(),
1855                                        ),
1856                                        rust_key_paths::lock::ArcRwLockAccess::new(),
1857                                        rust_key_paths::Kp::new(
1858                                            |v: &#inner_ty| Some(v),
1859                                            |v: &mut #inner_ty| Some(v),
1860                                        ),
1861                                    )
1862                                }
1863                            });
1864                        }
1865                        (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
1866                            // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1867                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1868                            tokens.extend(quote! {
1869                                #[inline(always)]
1870                                    pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1871                                    rust_key_paths::Kp::new(
1872                                        |root: &#name| Some(&root.#field_ident),
1873                                        |root: &mut #name| Some(&mut root.#field_ident),
1874                                    )
1875                                }
1876                                // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
1877                                //     rust_key_paths::Kp::new(
1878                                //         |root: &#name| root.#field_ident.as_ref(),
1879                                //         |root: &mut #name| root.#field_ident.as_mut(),
1880                                //     )
1881                                // }
1882                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>, #inner_ty> {
1883                                    rust_key_paths::lock::LockKp::new(
1884                                        rust_key_paths::Kp::new(
1885                                            |root: &#name| root.#field_ident.as_ref(),
1886                                            |root: &mut #name| root.#field_ident.as_mut(),
1887                                        ),
1888                                        rust_key_paths::lock::ParkingLotRwLockAccess::new(),
1889                                        rust_key_paths::Kp::new(
1890                                            |v: &#inner_ty| Some(v),
1891                                            |v: &mut #inner_ty| Some(v),
1892                                        ),
1893                                    )
1894                                }
1895                            });
1896                        }
1897                        (WrapperKind::OptionStdMutex, Some(inner_ty)) => {
1898                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1899                            tokens.extend(quote! {
1900                                #[inline(always)]
1901                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1902                                    rust_key_paths::Kp::new(
1903                                        |root: &#name| Some(&root.#field_ident),
1904                                        |root: &mut #name| Some(&mut root.#field_ident),
1905                                    )
1906                                }
1907                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
1908                                    rust_key_paths::Kp::new(
1909                                        |root: &#name| root.#field_ident.as_ref(),
1910                                        |root: &mut #name| root.#field_ident.as_mut(),
1911                                    )
1912                                }
1913                            });
1914                        }
1915                        (WrapperKind::OptionMutex, Some(inner_ty)) => {
1916                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1917                            tokens.extend(quote! {
1918                                #[inline(always)]
1919                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1920                                    rust_key_paths::Kp::new(
1921                                        |root: &#name| Some(&root.#field_ident),
1922                                        |root: &mut #name| Some(&mut root.#field_ident),
1923                                    )
1924                                }
1925                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, parking_lot::Mutex<#inner_ty>> {
1926                                    rust_key_paths::Kp::new(
1927                                        |root: &#name| root.#field_ident.as_ref(),
1928                                        |root: &mut #name| root.#field_ident.as_mut(),
1929                                    )
1930                                }
1931                            });
1932                        }
1933                        (WrapperKind::OptionStdRwLock, Some(inner_ty)) => {
1934                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1935                            tokens.extend(quote! {
1936                                #[inline(always)]
1937                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1938                                    rust_key_paths::Kp::new(
1939                                        |root: &#name| Some(&root.#field_ident),
1940                                        |root: &mut #name| Some(&mut root.#field_ident),
1941                                    )
1942                                }
1943                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
1944                                    rust_key_paths::Kp::new(
1945                                        |root: &#name| root.#field_ident.as_ref(),
1946                                        |root: &mut #name| root.#field_ident.as_mut(),
1947                                    )
1948                                }
1949                            });
1950                        }
1951                        (WrapperKind::OptionRwLock, Some(inner_ty)) => {
1952                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1953                            tokens.extend(quote! {
1954                                #[inline(always)]
1955                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1956                                    rust_key_paths::Kp::new(
1957                                        |root: &#name| Some(&root.#field_ident),
1958                                        |root: &mut #name| Some(&mut root.#field_ident),
1959                                    )
1960                                }
1961                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, parking_lot::RwLock<#inner_ty>> {
1962                                    rust_key_paths::Kp::new(
1963                                        |root: &#name| root.#field_ident.as_ref(),
1964                                        |root: &mut #name| root.#field_ident.as_mut(),
1965                                    )
1966                                }
1967                            });
1968                        }
1969                        (WrapperKind::Weak, Some(_inner_ty)) => {
1970                            // For Weak<T>, return keypath to container
1971                            tokens.extend(quote! {
1972                                #[inline(always)]
1973                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1974                                    rust_key_paths::Kp::new(
1975                                        |root: &#name| Some(&root.#field_ident),
1976                                        |_root: &mut #name| None, // Weak doesn't support mutable access
1977                                    )
1978                                }
1979                            });
1980                        }
1981                        (WrapperKind::Atomic, None | Some(_)) => {
1982                            // For atomic types: return keypath to the atomic (user calls .load()/.store())
1983                            tokens.extend(quote! {
1984                                #[inline(always)]
1985                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1986                                    rust_key_paths::Kp::new(
1987                                        |root: &#name| Some(&root.#field_ident),
1988                                        |root: &mut #name| Some(&mut root.#field_ident),
1989                                    )
1990                                }
1991                            });
1992                        }
1993                        (WrapperKind::OptionAtomic, Some(inner_ty)) => {
1994                            tokens.extend(quote! {
1995                                #[inline(always)]
1996                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1997                                    rust_key_paths::Kp::new(
1998                                        |root: &#name| root.#field_ident.as_ref(),
1999                                        |root: &mut #name| root.#field_ident.as_mut(),
2000                                    )
2001                                }
2002                            });
2003                        }
2004                        (WrapperKind::String, None) => {
2005                            tokens.extend(quote! {
2006                                #[inline(always)]
2007                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2008                                    rust_key_paths::Kp::new(
2009                                        |root: &#name| Some(&root.#field_ident),
2010                                        |root: &mut #name| Some(&mut root.#field_ident),
2011                                    )
2012                                }
2013                            });
2014                        }
2015                        (WrapperKind::OptionString, None) => {
2016                            tokens.extend(quote! {
2017                                #[inline(always)]
2018                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, std::string::String> {
2019                                    rust_key_paths::Kp::new(
2020                                        |root: &#name| root.#field_ident.as_ref(),
2021                                        |root: &mut #name| root.#field_ident.as_mut(),
2022                                    )
2023                                }
2024                            });
2025                        }
2026                        (WrapperKind::Cell, Some(_inner_ty)) => {
2027                            tokens.extend(quote! {
2028                                #[inline(always)]
2029                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2030                                    rust_key_paths::Kp::new(
2031                                        |root: &#name| Some(&root.#field_ident),
2032                                        |root: &mut #name| Some(&mut root.#field_ident),
2033                                    )
2034                                }
2035                            });
2036                        }
2037                        (WrapperKind::RefCell, Some(_inner_ty)) => {
2038                            tokens.extend(quote! {
2039                                #[inline(always)]
2040                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2041                                    rust_key_paths::Kp::new(
2042                                        |root: &#name| Some(&root.#field_ident),
2043                                        |root: &mut #name| Some(&mut root.#field_ident),
2044                                    )
2045                                }
2046                            });
2047                        }
2048                        (WrapperKind::OnceCell, Some(inner_ty)) => {
2049                            // OnceLock/OnceCell: keypath to inner value; get = .get() -> Option<&T>, set = None
2050                            tokens.extend(quote! {
2051                                #[inline(always)]
2052                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2053                                    rust_key_paths::Kp::new(
2054                                        |root: &#name| root.#field_ident.get(),
2055                                        |_root: &mut #name| None,
2056                                    )
2057                                }
2058                            });
2059                        }
2060                        (WrapperKind::Lazy, Some(inner_ty)) => {
2061                            // Lazy/LazyLock: keypath to inner value; get = .get() -> &T wrapped in Some, set = None
2062                            tokens.extend(quote! {
2063                                #[inline(always)]
2064                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2065                                    rust_key_paths::Kp::new(
2066                                        |root: &#name| Some(root.#field_ident.get()),
2067                                        |_root: &mut #name| None,
2068                                    )
2069                                }
2070                            });
2071                        }
2072                        (WrapperKind::PhantomData, Some(_inner_ty)) => {
2073                            tokens.extend(quote! {
2074                                #[inline(always)]
2075                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2076                                    rust_key_paths::Kp::new(
2077                                        |root: &#name| Some(&root.#field_ident),
2078                                        |root: &mut #name| Some(&mut root.#field_ident),
2079                                    )
2080                                }
2081                            });
2082                        }
2083                        (WrapperKind::Range, Some(_inner_ty)) => {
2084                            tokens.extend(quote! {
2085                                #[inline(always)]
2086                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2087                                    rust_key_paths::Kp::new(
2088                                        |root: &#name| Some(&root.#field_ident),
2089                                        |root: &mut #name| Some(&mut root.#field_ident),
2090                                    )
2091                                }
2092                            });
2093                        }
2094                        (WrapperKind::OptionCell, Some(_inner_ty)) => {
2095                            tokens.extend(quote! {
2096                                #[inline(always)]
2097                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2098                                    rust_key_paths::Kp::new(
2099                                        |root: &#name| Some(&root.#field_ident),
2100                                        |root: &mut #name| Some(&mut root.#field_ident),
2101                                    )
2102                                }
2103                            });
2104                        }
2105                        (WrapperKind::OptionRefCell, Some(inner_ty)) => {
2106                            // Option<RefCell<T>>: keypath to T via borrow()/borrow_mut(); get returns Option<Ref<V>> so caller holds guard (deref for &V)
2107                            tokens.extend(quote! {
2108                                #[inline(always)]
2109                                pub fn #kp_fn() -> rust_key_paths::KpOptionRefCellType<'_, #name, #inner_ty> {
2110                                    rust_key_paths::Kp::new(
2111                                        |root: &#name| root.#field_ident.as_ref().map(|r| r.borrow()),
2112                                        |root: &mut #name| root.#field_ident.as_ref().map(|r| r.borrow_mut()),
2113                                    )
2114                                }
2115                            });
2116                        }
2117                        (WrapperKind::OptionOnceCell, Some(inner_ty)) => {
2118                            tokens.extend(quote! {
2119                                #[inline(always)]
2120                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2121                                    rust_key_paths::Kp::new(
2122                                        |root: &#name| root.#field_ident.as_ref().and_then(|c| c.get()),
2123                                        |_root: &mut #name| None,
2124                                    )
2125                                }
2126                            });
2127                        }
2128                        (WrapperKind::OptionLazy, Some(inner_ty)) => {
2129                            tokens.extend(quote! {
2130                                #[inline(always)]
2131                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2132                                    rust_key_paths::Kp::new(
2133                                        |root: &#name| root.#field_ident.as_ref().map(|c| c.get()),
2134                                        |_root: &mut #name| None,
2135                                    )
2136                                }
2137                            });
2138                        }
2139                        (WrapperKind::OptionPhantomData, Some(_inner_ty)) => {
2140                            tokens.extend(quote! {
2141                                #[inline(always)]
2142                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2143                                    rust_key_paths::Kp::new(
2144                                        |root: &#name| Some(&root.#field_ident),
2145                                        |root: &mut #name| Some(&mut root.#field_ident),
2146                                    )
2147                                }
2148                            });
2149                        }
2150                        (WrapperKind::OptionRange, Some(_inner_ty)) => {
2151                            tokens.extend(quote! {
2152                                #[inline(always)]
2153                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2154                                    rust_key_paths::Kp::new(
2155                                        |root: &#name| Some(&root.#field_ident),
2156                                        |root: &mut #name| Some(&mut root.#field_ident),
2157                                    )
2158                                }
2159                            });
2160                        }
2161                        (WrapperKind::Reference, Some(_inner_ty)) => {
2162                            // For reference types (&T, &str, &[T]): read-only, setter returns None
2163                            tokens.extend(quote! {
2164                                #[inline(always)]
2165                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2166                                    rust_key_paths::Kp::new(
2167                                        |root: &#name| Some(&root.#field_ident),
2168                                        |_root: &mut #name| None, // references: read-only
2169                                    )
2170                                }
2171                            });
2172                        }
2173                        (WrapperKind::None, None) => {
2174                            // For basic types, direct access
2175                            tokens.extend(quote! {
2176                                #[inline(always)]
2177                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2178                                    rust_key_paths::Kp::new(
2179                                        |root: &#name| Some(&root.#field_ident),
2180                                        |root: &mut #name| Some(&mut root.#field_ident),
2181                                    )
2182                                }
2183                            });
2184                        }
2185                        _ => {
2186                            // For unknown/complex nested types, return keypath to field itself
2187                            tokens.extend(quote! {
2188                                #[inline(always)]
2189                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2190                            rust_key_paths::Kp::new(
2191                                |root: &#name| Some(&root.#field_ident),
2192                                |root: &mut #name| Some(&mut root.#field_ident),
2193                            )
2194                        }
2195                            });
2196                        }
2197                    }
2198                }
2199
2200                tokens
2201            }
2202            Fields::Unnamed(unnamed) => {
2203                let mut tokens = proc_macro2::TokenStream::new();
2204
2205                // Generate identity methods for the tuple struct
2206                tokens.extend(quote! {
2207                    /// Returns a generic identity keypath for this type
2208                    #[inline(always)]
2209                    pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
2210                        #name,
2211                        #name,
2212                        Root,
2213                        Root,
2214                        MutRoot,
2215                        MutRoot,
2216                        fn(Root) -> Option<Root>,
2217                        fn(MutRoot) -> Option<MutRoot>,
2218                    >
2219                    where
2220                        Root: std::borrow::Borrow<#name>,
2221                        MutRoot: std::borrow::BorrowMut<#name>,
2222                    {
2223                        rust_key_paths::Kp::new(
2224                            |r: Root| Some(r),
2225                            |r: MutRoot| Some(r)
2226                        )
2227                    }
2228
2229                    /// Returns a simple identity keypath for this type
2230                    #[inline(always)]
2231                    pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
2232                        rust_key_paths::Kp::new(
2233                            |r: &#name| Some(r),
2234                            |r: &mut #name| Some(r)
2235                        )
2236                    }
2237                });
2238
2239                for (idx, field) in unnamed.unnamed.iter().enumerate() {
2240                    let idx_lit = syn::Index::from(idx);
2241                    let ty = &field.ty;
2242                    // Centralized keypath method names for tuple fields – change here to adjust for all types
2243                    let kp_fn = format_ident!("f{}", idx);
2244                    let kp_at_fn = format_ident!("f{}_at", idx);
2245
2246                    let (kind, inner_ty) = extract_wrapper_inner_type(ty);
2247
2248                    match (kind, inner_ty.clone()) {
2249                        (WrapperKind::Option, Some(inner_ty)) => {
2250                            tokens.extend(quote! {
2251                                #[inline(always)]
2252                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2253                                    rust_key_paths::Kp::new(
2254                                        |root: &#name| root.#idx_lit.as_ref(),
2255                                        |root: &mut #name| root.#idx_lit.as_mut(),
2256                                    )
2257                                }
2258                            });
2259                        }
2260                        (WrapperKind::OptionBox, Some(inner_ty)) => {
2261                            tokens.extend(quote! {
2262                                #[inline(always)]
2263                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2264                                    rust_key_paths::Kp::new(
2265                                        |root: &#name| root.#idx_lit.as_deref(),
2266                                        |root: &mut #name| root.#idx_lit.as_deref_mut(),
2267                                    )
2268                                }
2269                            });
2270                        }
2271                        (WrapperKind::OptionRc, Some(inner_ty)) => {
2272                            tokens.extend(quote! {
2273                                #[inline(always)]
2274                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2275                                    rust_key_paths::Kp::new(
2276                                        |root: &#name| root.#idx_lit.as_deref(),
2277                                        |root: &mut #name| root.#idx_lit.as_mut().and_then(std::rc::Rc::get_mut),
2278                                    )
2279                                }
2280                            });
2281                        }
2282                        (WrapperKind::OptionArc, Some(inner_ty)) => {
2283                            tokens.extend(quote! {
2284                                #[inline(always)]
2285                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2286                                    rust_key_paths::Kp::new(
2287                                        |root: &#name| root.#idx_lit.as_deref(),
2288                                        |root: &mut #name| root.#idx_lit.as_mut().and_then(std::sync::Arc::get_mut),
2289                                    )
2290                                }
2291                            });
2292                        }
2293                        (WrapperKind::OptionHashMap, Some(inner_ty)) => {
2294                            if let Some((key_ty, _)) = extract_map_key_value_through_option(ty) {
2295                                let type_name = name.to_string();
2296                                let whole_fn = kp_fn.to_string();
2297                                let at_fn = kp_at_fn.to_string();
2298                                let whole_doc = format!(
2299                                    "Keypath to the whole optional `HashMap` (`{type_name}::{whole_fn}`). For a value at one key when the map is `Some`, use `{type_name}::{at_fn}(key)`."
2300                                );
2301                                let at_doc = format!(
2302                                    "Keyed access into the inner `HashMap` (`{type_name}::{at_fn}`). `get`/`get_mut` return `None` if the field is `None` or the key is missing. See also `{type_name}::{whole_fn}` for the full optional map."
2303                                );
2304                                tokens.extend(quote! {
2305                                    #[doc = #whole_doc]
2306                                    #[inline(always)]
2307                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2308                                        rust_key_paths::Kp::new(
2309                                            |root: &#name| Some(&root.#idx_lit),
2310                                            |root: &mut #name| Some(&mut root.#idx_lit),
2311                                        )
2312                                    }
2313                                    #[doc = #at_doc]
2314                                    #[inline(always)]
2315                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2316                                    where
2317                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
2318                                    {
2319                                        let key2 = key.clone();
2320                                        rust_key_paths::Kp::new(
2321                                            Box::new(move |root: &#name| root.#idx_lit.as_ref().and_then(|m| m.get(&key))),
2322                                            Box::new(move |root: &mut #name| root.#idx_lit.as_mut().and_then(|m| m.get_mut(&key2))),
2323                                        )
2324                                    }
2325                                });
2326                            } else {
2327                                tokens.extend(quote! {
2328                                    #[inline(always)]
2329                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2330                                        rust_key_paths::Kp::new(
2331                                            |root: &#name| Some(&root.#idx_lit),
2332                                            |root: &mut #name| Some(&mut root.#idx_lit),
2333                                        )
2334                                    }
2335                                });
2336                            }
2337                        }
2338                        (WrapperKind::OptionBTreeMap, Some(inner_ty)) => {
2339                            if let Some((key_ty, _)) = extract_map_key_value_through_option(ty) {
2340                                let type_name = name.to_string();
2341                                let whole_fn = kp_fn.to_string();
2342                                let at_fn = kp_at_fn.to_string();
2343                                let whole_doc = format!(
2344                                    "Keypath to the whole optional `BTreeMap` (`{type_name}::{whole_fn}`). For a value at one key when the map is `Some`, use `{type_name}::{at_fn}(key)`."
2345                                );
2346                                let at_doc = format!(
2347                                    "Keyed access into the inner `BTreeMap` (`{type_name}::{at_fn}`). `get`/`get_mut` return `None` if the field is `None` or the key is missing. See also `{type_name}::{whole_fn}` for the full optional map."
2348                                );
2349                                tokens.extend(quote! {
2350                                    #[doc = #whole_doc]
2351                                    #[inline(always)]
2352                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2353                                        rust_key_paths::Kp::new(
2354                                            |root: &#name| Some(&root.#idx_lit),
2355                                            |root: &mut #name| Some(&mut root.#idx_lit),
2356                                        )
2357                                    }
2358                                    #[doc = #at_doc]
2359                                    #[inline(always)]
2360                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2361                                    where
2362                                        #key_ty: Clone + Ord + 'static,
2363                                    {
2364                                        let key2 = key.clone();
2365                                        rust_key_paths::Kp::new(
2366                                            Box::new(move |root: &#name| root.#idx_lit.as_ref().and_then(|m| m.get(&key))),
2367                                            Box::new(move |root: &mut #name| root.#idx_lit.as_mut().and_then(|m| m.get_mut(&key2))),
2368                                        )
2369                                    }
2370                                });
2371                            } else {
2372                                tokens.extend(quote! {
2373                                    #[inline(always)]
2374                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2375                                        rust_key_paths::Kp::new(
2376                                            |root: &#name| Some(&root.#idx_lit),
2377                                            |root: &mut #name| Some(&mut root.#idx_lit),
2378                                        )
2379                                    }
2380                                });
2381                            }
2382                        }
2383                        (WrapperKind::OptionHashSet, Some(inner_ty)) => {
2384                            tokens.extend(quote! {
2385                                #[inline(always)]
2386                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2387                                    rust_key_paths::Kp::new(
2388                                        |root: &#name| Some(&root.#idx_lit),
2389                                        |root: &mut #name| Some(&mut root.#idx_lit),
2390                                    )
2391                                }
2392
2393                                /// _at: check if element exists and get reference.
2394                                /// HashSet does not allow mutable element access (would break hash invariant).
2395                                #[inline(always)]
2396                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2397                                where
2398                                    #inner_ty: Clone + std::hash::Hash + Eq + 'static,
2399                                {
2400                                    rust_key_paths::Kp::new(
2401                                        Box::new(move |root: &#name| root.#idx_lit.as_ref().and_then(|s| s.get(&key))),
2402                                        Box::new(move |_root: &mut #name| None),
2403                                    )
2404                                }
2405                            });
2406                        }
2407                        (WrapperKind::OptionBTreeSet, Some(inner_ty)) => {
2408                            tokens.extend(quote! {
2409                                #[inline(always)]
2410                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2411                                    rust_key_paths::Kp::new(
2412                                        |root: &#name| Some(&root.#idx_lit),
2413                                        |root: &mut #name| Some(&mut root.#idx_lit),
2414                                    )
2415                                }
2416
2417                                /// _at: check if element exists and get reference.
2418                                /// BTreeSet does not allow mutable element access (would break ordering invariant).
2419                                #[inline(always)]
2420                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2421                                where
2422                                    #inner_ty: Clone + Ord + 'static,
2423                                {
2424                                    rust_key_paths::Kp::new(
2425                                        Box::new(move |root: &#name| root.#idx_lit.as_ref().and_then(|s| s.get(&key))),
2426                                        Box::new(move |_root: &mut #name| None),
2427                                    )
2428                                }
2429                            });
2430                        }
2431                        (WrapperKind::OptionVec, Some(inner_ty)) => {
2432                            tokens.extend(quote! {
2433                                #[inline(always)]
2434                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2435                                    rust_key_paths::Kp::new(
2436                                        |root: &#name| Some(&root.#idx_lit),
2437                                        |root: &mut #name| Some(&mut root.#idx_lit),
2438                                    )
2439                                }
2440                                #[inline(always)]
2441                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
2442                                    rust_key_paths::Kp::new(
2443                                        Box::new(move |root: &#name| root.#idx_lit.as_ref().and_then(|v| v.get(index))),
2444                                        Box::new(move |root: &mut #name| root.#idx_lit.as_mut().and_then(|v| v.get_mut(index))),
2445                                    )
2446                                }
2447                            });
2448                        }
2449                        (WrapperKind::OptionVecDeque, Some(inner_ty)) => {
2450                            tokens.extend(quote! {
2451                                #[inline(always)]
2452                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2453                                    rust_key_paths::Kp::new(
2454                                        |root: &#name| Some(&root.#idx_lit),
2455                                        |root: &mut #name| Some(&mut root.#idx_lit),
2456                                    )
2457                                }
2458                                #[inline(always)]
2459                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
2460                                    rust_key_paths::Kp::new(
2461                                        Box::new(move |root: &#name| root.#idx_lit.as_ref().and_then(|v| v.get(index))),
2462                                        Box::new(move |root: &mut #name| root.#idx_lit.as_mut().and_then(|v| v.get_mut(index))),
2463                                    )
2464                                }
2465                            });
2466                        }
2467                        (WrapperKind::OptionLinkedList, Some(_inner_ty))
2468                        | (WrapperKind::OptionBinaryHeap, Some(_inner_ty))
2469                        | (WrapperKind::OptionResult, Some(_inner_ty)) => {
2470                            tokens.extend(quote! {
2471                                #[inline(always)]
2472                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2473                                    rust_key_paths::Kp::new(
2474                                        |root: &#name| Some(&root.#idx_lit),
2475                                        |root: &mut #name| Some(&mut root.#idx_lit),
2476                                    )
2477                                }
2478                            });
2479                        }
2480                        (WrapperKind::Vec, Some(inner_ty)) => {
2481                            tokens.extend(quote! {
2482                                #[inline(always)]
2483                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2484                                    rust_key_paths::Kp::new(
2485                                        |root: &#name| Some(&root.#idx_lit),
2486                                        |root: &mut #name| Some(&mut root.#idx_lit),
2487                                    )
2488                                }
2489                                #[inline(always)]
2490                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
2491                                    rust_key_paths::Kp::new(
2492                                        Box::new(move |root: &#name| root.#idx_lit.get(index)),
2493                                        Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
2494                                    )
2495                                }
2496                            });
2497                        }
2498                        (WrapperKind::HashMap, Some(inner_ty)) => {
2499                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
2500                                tokens.extend(quote! {
2501                                    #[inline(always)]
2502                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2503                                        rust_key_paths::Kp::new(
2504                                            |root: &#name| Some(&root.#idx_lit),
2505                                            |root: &mut #name| Some(&mut root.#idx_lit),
2506                                        )
2507                                    }
2508                                    #[inline(always)]
2509                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2510                                    where
2511                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
2512                                    {
2513                                        let key2 = key.clone();
2514                                        rust_key_paths::Kp::new(
2515                                            Box::new(move |root: &#name| root.#idx_lit.get(&key)),
2516                                            Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
2517                                        )
2518                                    }
2519                                });
2520                            } else {
2521                                tokens.extend(quote! {
2522                                    #[inline(always)]
2523                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2524                                        rust_key_paths::Kp::new(
2525                                            |root: &#name| Some(&root.#idx_lit),
2526                                            |root: &mut #name| Some(&mut root.#idx_lit),
2527                                        )
2528                                    }
2529                                });
2530                            }
2531                        }
2532                        (WrapperKind::BTreeMap, Some(inner_ty))
2533                        | (WrapperKind::BTreeMapOption, Some(inner_ty)) => {
2534                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
2535                                tokens.extend(quote! {
2536                                    #[inline(always)]
2537                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2538                                        rust_key_paths::Kp::new(
2539                                            |root: &#name| Some(&root.#idx_lit),
2540                                            |root: &mut #name| Some(&mut root.#idx_lit),
2541                                        )
2542                                    }
2543                                    #[inline(always)]
2544                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2545                                    where
2546                                        #key_ty: Clone + Ord + 'static,
2547                                    {
2548                                        let key2 = key.clone();
2549                                        rust_key_paths::Kp::new(
2550                                            Box::new(move |root: &#name| root.#idx_lit.get(&key)),
2551                                            Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
2552                                        )
2553                                    }
2554                                });
2555                            } else {
2556                                tokens.extend(quote! {
2557                                    #[inline(always)]
2558                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2559                                        rust_key_paths::Kp::new(
2560                                            |root: &#name| Some(&root.#idx_lit),
2561                                            |root: &mut #name| Some(&mut root.#idx_lit),
2562                                        )
2563                                    }
2564                                });
2565                            }
2566                        }
2567                        (WrapperKind::Box, Some(inner_ty)) => {
2568                            // Box: deref to inner (returns &T / &mut T)
2569                            tokens.extend(quote! {
2570                                #[inline(always)]
2571                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2572                                    rust_key_paths::Kp::new(
2573                                        |root: &#name| Some(&*root.#idx_lit),
2574                                        |root: &mut #name| Some(&mut *root.#idx_lit),
2575                                    )
2576                                }
2577                            });
2578                        }
2579                        (WrapperKind::BoxOption, Some(inner_ty)) => {
2580                            tokens.extend(quote! {
2581                                #[inline(always)]
2582                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2583                                    rust_key_paths::Kp::new(
2584                                        |root: &#name| (&*root.#idx_lit).as_ref(),
2585                                        |root: &mut #name| (&mut *root.#idx_lit).as_mut(),
2586                                    )
2587                                }
2588                            });
2589                        }
2590                        (WrapperKind::RcOption, Some(inner_ty)) => {
2591                            tokens.extend(quote! {
2592                                #[inline(always)]
2593                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2594                                    rust_key_paths::Kp::new(
2595                                        |root: &#name| (&*root.#idx_lit).as_ref(),
2596                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#idx_lit).and_then(std::option::Option::as_mut),
2597                                    )
2598                                }
2599                            });
2600                        }
2601                        (WrapperKind::ArcOption, Some(inner_ty)) => {
2602                            tokens.extend(quote! {
2603                                #[inline(always)]
2604                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2605                                    rust_key_paths::Kp::new(
2606                                        |root: &#name| (&*root.#idx_lit).as_ref(),
2607                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#idx_lit).and_then(std::option::Option::as_mut),
2608                                    )
2609                                }
2610                            });
2611                        }
2612                        (WrapperKind::Pin, Some(inner_ty)) => {
2613                            let kp_inner_fn = format_ident!("{}_inner", kp_fn);
2614                            tokens.extend(quote! {
2615                                #[inline(always)]
2616                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2617                                    rust_key_paths::Kp::new(
2618                                        |root: &#name| Some(&root.#idx_lit),
2619                                        |root: &mut #name| Some(&mut root.#idx_lit),
2620                                    )
2621                                }
2622                                #[inline(always)]
2623                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2624                                where #inner_ty: std::marker::Unpin
2625                                {
2626                                    rust_key_paths::Kp::new(
2627                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#idx_lit).get_ref()),
2628                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#idx_lit).get_mut()),
2629                                    )
2630                                }
2631                            });
2632                        }
2633                        (WrapperKind::PinBox, Some(inner_ty)) => {
2634                            let kp_inner_fn = format_ident!("{}_inner", kp_fn);
2635                            tokens.extend(quote! {
2636                                #[inline(always)]
2637                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2638                                    rust_key_paths::Kp::new(
2639                                        |root: &#name| Some(&root.#idx_lit),
2640                                        |root: &mut #name| Some(&mut root.#idx_lit),
2641                                    )
2642                                }
2643                                #[inline(always)]
2644                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2645                                where #inner_ty: std::marker::Unpin
2646                                {
2647                                    rust_key_paths::Kp::new(
2648                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#idx_lit).get_ref()),
2649                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#idx_lit).get_mut()),
2650                                    )
2651                                }
2652                            });
2653                        }
2654                        (WrapperKind::Rc, Some(inner_ty)) => {
2655                            tokens.extend(quote! {
2656                                #[inline(always)]
2657                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2658                                    rust_key_paths::Kp::new(
2659                                        |root: &#name| Some(root.#idx_lit.as_ref()),
2660                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#idx_lit),
2661                                    )
2662                                }
2663                            });
2664                        }
2665                        (WrapperKind::Arc, Some(inner_ty)) => {
2666                            tokens.extend(quote! {
2667                                #[inline(always)]
2668                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2669                                    rust_key_paths::Kp::new(
2670                                        |root: &#name| Some(root.#idx_lit.as_ref()),
2671                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#idx_lit),
2672                                    )
2673                                }
2674                            });
2675                        }
2676
2677                        (WrapperKind::Cow, Some(inner_ty)) => {
2678                            tokens.extend(quote! {
2679                                #[inline(always)]
2680                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2681                                    rust_key_paths::Kp::new(
2682                                        |root: &#name| Some(root.#idx_lit.as_ref()),
2683                                        |root: &mut #name| Some(root.#idx_lit.to_mut()),
2684                                    )
2685                                }
2686                            });
2687                        }
2688
2689                        (WrapperKind::OptionCow, Some(inner_ty)) => {
2690                            tokens.extend(quote! {
2691                                #[inline(always)]
2692                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2693                                    rust_key_paths::Kp::new(
2694                                        |root: &#name| root.#idx_lit.as_ref().map(|c| c.as_ref()),
2695                                        |root: &mut #name| root.#idx_lit.as_mut().map(|c| c.to_mut()),
2696                                    )
2697                                }
2698                            });
2699                        }
2700                        (WrapperKind::OptionTagged, Some(inner_ty)) => {
2701                            tokens.extend(quote! {
2702                                #[inline(always)]
2703                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2704                                    rust_key_paths::Kp::new(
2705                                        |root: &#name| root.#idx_lit.as_ref().map(|t| std::ops::Deref::deref(t)),
2706                                        |root: &mut #name| root.#idx_lit.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
2707                                    )
2708                                }
2709                            });
2710                        }
2711                        (WrapperKind::OptionReference, Some(inner_ty)) => {
2712                            tokens.extend(quote! {
2713                                #[inline(always)]
2714                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2715                                    rust_key_paths::Kp::new(
2716                                        |root: &#name| root.#idx_lit.as_ref(),
2717                                        |_root: &mut #name| None,
2718                                    )
2719                                }
2720                            });
2721                        }
2722                        (WrapperKind::HashSet, Some(inner_ty))
2723                        | (WrapperKind::HashSetOption, Some(inner_ty)) => {
2724                            let kp_at_fn = format_ident!("f{}_at", idx);
2725
2726                            tokens.extend(quote! {
2727                                #[inline(always)]
2728                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2729                                    rust_key_paths::Kp::new(
2730                                        |root: &#name| Some(&root.#idx_lit),
2731                                        |root: &mut #name| Some(&mut root.#idx_lit),
2732                                    )
2733                                }
2734
2735                                /// _at: check if element exists and get reference.
2736                                /// HashSet does not allow mutable element access (would break hash invariant).
2737                                #[inline(always)]
2738                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2739                                where
2740                                    #inner_ty: Clone + std::hash::Hash + Eq + 'static,
2741                                {
2742                                    rust_key_paths::Kp::new(
2743                                        Box::new(move |root: &#name| root.#idx_lit.get(&key)),
2744                                        Box::new(move |_root: &mut #name| None),
2745                                    )
2746                                }
2747                            });
2748                        }
2749                        (WrapperKind::BTreeSet, Some(inner_ty))
2750                        | (WrapperKind::BTreeSetOption, Some(inner_ty)) => {
2751                            let kp_at_fn = format_ident!("f{}_at", idx);
2752
2753                            tokens.extend(quote! {
2754                                #[inline(always)]
2755                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2756                                    rust_key_paths::Kp::new(
2757                                        |root: &#name| Some(&root.#idx_lit),
2758                                        |root: &mut #name| Some(&mut root.#idx_lit),
2759                                    )
2760                                }
2761
2762                                /// _at: check if element exists and get reference.
2763                                /// BTreeSet does not allow mutable element access (would break ordering invariant).
2764                                #[inline(always)]
2765                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2766                                where
2767                                    #inner_ty: Clone + Ord + 'static,
2768                                {
2769                                    rust_key_paths::Kp::new(
2770                                        Box::new(move |root: &#name| root.#idx_lit.get(&key)),
2771                                        Box::new(move |_root: &mut #name| None),
2772                                    )
2773                                }
2774                            });
2775                        }
2776                        (WrapperKind::VecDeque, Some(inner_ty))
2777                        | (WrapperKind::VecDequeOption, Some(inner_ty)) => {
2778                            tokens.extend(quote! {
2779                                #[inline(always)]
2780                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2781                                    rust_key_paths::Kp::new(
2782                                        |root: &#name| Some(&root.#idx_lit),
2783                                        |root: &mut #name| Some(&mut root.#idx_lit),
2784                                    )
2785                                }
2786                                #[inline(always)]
2787                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
2788                                    rust_key_paths::Kp::new(
2789                                        Box::new(move |root: &#name| root.#idx_lit.get(index)),
2790                                        Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
2791                                    )
2792                                }
2793                            });
2794                        }
2795                        (WrapperKind::LinkedList, Some(_inner_ty))
2796                        | (WrapperKind::LinkedListOption, Some(_inner_ty)) => {
2797                            tokens.extend(quote! {
2798                                #[inline(always)]
2799                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2800                                    rust_key_paths::Kp::new(
2801                                        |root: &#name| Some(&root.#idx_lit),
2802                                        |root: &mut #name| Some(&mut root.#idx_lit),
2803                                    )
2804                                }
2805                            });
2806                        }
2807                        (WrapperKind::BinaryHeap, Some(_inner_ty))
2808                        | (WrapperKind::BinaryHeapOption, Some(_inner_ty)) => {
2809                            tokens.extend(quote! {
2810                                #[inline(always)]
2811                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2812                                    rust_key_paths::Kp::new(
2813                                        |root: &#name| Some(&root.#idx_lit),
2814                                        |root: &mut #name| Some(&mut root.#idx_lit),
2815                                    )
2816                                }
2817                            });
2818                        }
2819                        (WrapperKind::Result, Some(inner_ty)) => {
2820                            tokens.extend(quote! {
2821                                #[inline(always)]
2822                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2823                                    rust_key_paths::Kp::new(
2824                                        |root: &#name| root.#idx_lit.as_ref().ok(),
2825                                        |root: &mut #name| root.#idx_lit.as_mut().ok(),
2826                                    )
2827                                }
2828                            });
2829                        }
2830                        (WrapperKind::Mutex, Some(_inner_ty))
2831                        | (WrapperKind::StdMutex, Some(_inner_ty)) => {
2832                            tokens.extend(quote! {
2833                                #[inline(always)]
2834                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2835                                    rust_key_paths::Kp::new(
2836                                        |root: &#name| Some(&root.#idx_lit),
2837                                        |root: &mut #name| Some(&mut root.#idx_lit),
2838                                    )
2839                                }
2840                            });
2841                        }
2842                        (WrapperKind::RwLock, Some(_inner_ty))
2843                        | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
2844                            tokens.extend(quote! {
2845                                #[inline(always)]
2846                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2847                                    rust_key_paths::Kp::new(
2848                                        |root: &#name| Some(&root.#idx_lit),
2849                                        |root: &mut #name| Some(&mut root.#idx_lit),
2850                                    )
2851                                }
2852                            });
2853                        }
2854                        (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
2855                            let kp_async_fn = format_ident!("f{}_kp", idx);
2856                            tokens.extend(quote! {
2857                                #[inline(always)]
2858                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2859                                    rust_key_paths::Kp::new(
2860                                        |root: &#name| Some(&root.#idx_lit),
2861                                        |root: &mut #name| Some(&mut root.#idx_lit),
2862                                    )
2863                                }
2864                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
2865                                    rust_key_paths::async_lock::AsyncLockKp::new(
2866                                        rust_key_paths::Kp::new(
2867                                            |root: &#name| Some(&root.#idx_lit),
2868                                            |root: &mut #name| Some(&mut root.#idx_lit),
2869                                        ),
2870                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
2871                                        rust_key_paths::Kp::new(
2872                                            |v: &#inner_ty| Some(v),
2873                                            |v: &mut #inner_ty| Some(v),
2874                                        ),
2875                                    )
2876                                }
2877                            });
2878                        }
2879                        (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
2880                            let kp_async_fn = format_ident!("f{}_kp", idx);
2881                            tokens.extend(quote! {
2882                                #[inline(always)]
2883                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2884                                    rust_key_paths::Kp::new(
2885                                        |root: &#name| Some(&root.#idx_lit),
2886                                        |root: &mut #name| Some(&mut root.#idx_lit),
2887                                    )
2888                                }
2889                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
2890                                    rust_key_paths::async_lock::AsyncLockKp::new(
2891                                        rust_key_paths::Kp::new(
2892                                            |root: &#name| Some(&root.#idx_lit),
2893                                            |root: &mut #name| Some(&mut root.#idx_lit),
2894                                        ),
2895                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
2896                                        rust_key_paths::Kp::new(
2897                                            |v: &#inner_ty| Some(v),
2898                                            |v: &mut #inner_ty| Some(v),
2899                                        ),
2900                                    )
2901                                }
2902                            });
2903                        }
2904                        (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
2905                            let kp_async_fn = format_ident!("f{}_kp", idx);
2906                            tokens.extend(quote! {
2907                                #[inline(always)]
2908                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2909                                    rust_key_paths::Kp::new(
2910                                        |root: &#name| Some(&root.#idx_lit),
2911                                        |root: &mut #name| Some(&mut root.#idx_lit),
2912                                    )
2913                                }
2914                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
2915                                    rust_key_paths::async_lock::AsyncLockKp::new(
2916                                        rust_key_paths::Kp::new(
2917                                            |root: &#name| root.#idx_lit.as_ref(),
2918                                            |root: &mut #name| root.#idx_lit.as_mut(),
2919                                        ),
2920                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
2921                                        rust_key_paths::Kp::new(
2922                                            |v: &#inner_ty| Some(v),
2923                                            |v: &mut #inner_ty| Some(v),
2924                                        ),
2925                                    )
2926                                }
2927                            });
2928                        }
2929                        (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
2930                            let kp_async_fn = format_ident!("f{}_kp", idx);
2931                            tokens.extend(quote! {
2932                                #[inline(always)]
2933                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2934                                    rust_key_paths::Kp::new(
2935                                        |root: &#name| Some(&root.#idx_lit),
2936                                        |root: &mut #name| Some(&mut root.#idx_lit),
2937                                    )
2938                                }
2939                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
2940                                    rust_key_paths::async_lock::AsyncLockKp::new(
2941                                        rust_key_paths::Kp::new(
2942                                            |root: &#name| root.#idx_lit.as_ref(),
2943                                            |root: &mut #name| root.#idx_lit.as_mut(),
2944                                        ),
2945                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
2946                                        rust_key_paths::Kp::new(
2947                                            |v: &#inner_ty| Some(v),
2948                                            |v: &mut #inner_ty| Some(v),
2949                                        ),
2950                                    )
2951                                }
2952                            });
2953                        }
2954                        (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
2955                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2956                            tokens.extend(quote! {
2957                                #[inline(always)]
2958                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2959                                    rust_key_paths::Kp::new(
2960                                        |root: &#name| Some(&root.#idx_lit),
2961                                        |root: &mut #name| Some(&mut root.#idx_lit),
2962                                    )
2963                                }
2964                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
2965                                    rust_key_paths::Kp::new(
2966                                        |root: &#name| root.#idx_lit.as_ref(),
2967                                        |root: &mut #name| root.#idx_lit.as_mut(),
2968                                    )
2969                                }
2970                            });
2971                        }
2972                        (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
2973                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2974                            tokens.extend(quote! {
2975                                #[inline(always)]
2976                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2977                                    rust_key_paths::Kp::new(
2978                                        |root: &#name| Some(&root.#idx_lit),
2979                                        |root: &mut #name| Some(&mut root.#idx_lit),
2980                                    )
2981                                }
2982                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
2983                                    rust_key_paths::Kp::new(
2984                                        |root: &#name| root.#idx_lit.as_ref(),
2985                                        |root: &mut #name| root.#idx_lit.as_mut(),
2986                                    )
2987                                }
2988                            });
2989                        }
2990                        (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
2991                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2992                            tokens.extend(quote! {
2993                                #[inline(always)]
2994                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2995                                    rust_key_paths::Kp::new(
2996                                        |root: &#name| Some(&root.#idx_lit),
2997                                        |root: &mut #name| Some(&mut root.#idx_lit),
2998                                    )
2999                                }
3000                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
3001                                    rust_key_paths::Kp::new(
3002                                        |root: &#name| root.#idx_lit.as_ref(),
3003                                        |root: &mut #name| root.#idx_lit.as_mut(),
3004                                    )
3005                                }
3006                            });
3007                        }
3008                        (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
3009                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
3010                            tokens.extend(quote! {
3011                                #[inline(always)]
3012                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3013                                    rust_key_paths::Kp::new(
3014                                        |root: &#name| Some(&root.#idx_lit),
3015                                        |root: &mut #name| Some(&mut root.#idx_lit),
3016                                    )
3017                                }
3018                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
3019                                    rust_key_paths::Kp::new(
3020                                        |root: &#name| root.#idx_lit.as_ref(),
3021                                        |root: &mut #name| root.#idx_lit.as_mut(),
3022                                    )
3023                                }
3024                            });
3025                        }
3026                        (WrapperKind::OptionStdMutex, Some(inner_ty)) => {
3027                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
3028                            tokens.extend(quote! {
3029                                #[inline(always)]
3030                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3031                                    rust_key_paths::Kp::new(
3032                                        |root: &#name| Some(&root.#idx_lit),
3033                                        |root: &mut #name| Some(&mut root.#idx_lit),
3034                                    )
3035                                }
3036                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
3037                                    rust_key_paths::Kp::new(
3038                                        |root: &#name| root.#idx_lit.as_ref(),
3039                                        |root: &mut #name| root.#idx_lit.as_mut(),
3040                                    )
3041                                }
3042                            });
3043                        }
3044                        (WrapperKind::OptionMutex, Some(inner_ty)) => {
3045                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
3046                            tokens.extend(quote! {
3047                                #[inline(always)]
3048                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3049                                    rust_key_paths::Kp::new(
3050                                        |root: &#name| Some(&root.#idx_lit),
3051                                        |root: &mut #name| Some(&mut root.#idx_lit),
3052                                    )
3053                                }
3054                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, parking_lot::Mutex<#inner_ty>> {
3055                                    rust_key_paths::Kp::new(
3056                                        |root: &#name| root.#idx_lit.as_ref(),
3057                                        |root: &mut #name| root.#idx_lit.as_mut(),
3058                                    )
3059                                }
3060                            });
3061                        }
3062                        (WrapperKind::OptionStdRwLock, Some(inner_ty)) => {
3063                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
3064                            tokens.extend(quote! {
3065                                #[inline(always)]
3066                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3067                                    rust_key_paths::Kp::new(
3068                                        |root: &#name| Some(&root.#idx_lit),
3069                                        |root: &mut #name| Some(&mut root.#idx_lit),
3070                                    )
3071                                }
3072                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
3073                                    rust_key_paths::Kp::new(
3074                                        |root: &#name| root.#idx_lit.as_ref(),
3075                                        |root: &mut #name| root.#idx_lit.as_mut(),
3076                                    )
3077                                }
3078                            });
3079                        }
3080                        (WrapperKind::OptionRwLock, Some(inner_ty)) => {
3081                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
3082                            tokens.extend(quote! {
3083                                #[inline(always)]
3084                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3085                                    rust_key_paths::Kp::new(
3086                                        |root: &#name| Some(&root.#idx_lit),
3087                                        |root: &mut #name| Some(&mut root.#idx_lit),
3088                                    )
3089                                }
3090                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, parking_lot::RwLock<#inner_ty>> {
3091                                    rust_key_paths::Kp::new(
3092                                        |root: &#name| root.#idx_lit.as_ref(),
3093                                        |root: &mut #name| root.#idx_lit.as_mut(),
3094                                    )
3095                                }
3096                            });
3097                        }
3098                        (WrapperKind::Weak, Some(_inner_ty)) => {
3099                            tokens.extend(quote! {
3100                                #[inline(always)]
3101                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3102                                    rust_key_paths::Kp::new(
3103                                        |root: &#name| Some(&root.#idx_lit),
3104                                        |_root: &mut #name| None,
3105                                    )
3106                                }
3107                            });
3108                        }
3109                        (WrapperKind::Atomic, None | Some(_)) => {
3110                            tokens.extend(quote! {
3111                                #[inline(always)]
3112                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3113                                    rust_key_paths::Kp::new(
3114                                        |root: &#name| Some(&root.#idx_lit),
3115                                        |root: &mut #name| Some(&mut root.#idx_lit),
3116                                    )
3117                                }
3118                            });
3119                        }
3120                        (WrapperKind::OptionAtomic, Some(inner_ty)) => {
3121                            tokens.extend(quote! {
3122                                #[inline(always)]
3123                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3124                                    rust_key_paths::Kp::new(
3125                                        |root: &#name| root.#idx_lit.as_ref(),
3126                                        |root: &mut #name| root.#idx_lit.as_mut(),
3127                                    )
3128                                }
3129                            });
3130                        }
3131                        (WrapperKind::String, None) => {
3132                            tokens.extend(quote! {
3133                                #[inline(always)]
3134                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3135                                    rust_key_paths::Kp::new(
3136                                        |root: &#name| Some(&root.#idx_lit),
3137                                        |root: &mut #name| Some(&mut root.#idx_lit),
3138                                    )
3139                                }
3140                            });
3141                        }
3142                        (WrapperKind::OptionString, None) => {
3143                            tokens.extend(quote! {
3144                                #[inline(always)]
3145                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, std::string::String> {
3146                                    rust_key_paths::Kp::new(
3147                                        |root: &#name| root.#idx_lit.as_ref(),
3148                                        |root: &mut #name| root.#idx_lit.as_mut(),
3149                                    )
3150                                }
3151                            });
3152                        }
3153                        (WrapperKind::OnceCell, Some(inner_ty)) => {
3154                            tokens.extend(quote! {
3155                                #[inline(always)]
3156                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3157                                    rust_key_paths::Kp::new(
3158                                        |root: &#name| root.#idx_lit.get(),
3159                                        |_root: &mut #name| None,
3160                                    )
3161                                }
3162                            });
3163                        }
3164                        (WrapperKind::Lazy, Some(inner_ty)) => {
3165                            tokens.extend(quote! {
3166                                #[inline(always)]
3167                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3168                                    rust_key_paths::Kp::new(
3169                                        |root: &#name| Some(root.#idx_lit.get()),
3170                                        |_root: &mut #name| None,
3171                                    )
3172                                }
3173                            });
3174                        }
3175                        (WrapperKind::OptionOnceCell, Some(inner_ty)) => {
3176                            tokens.extend(quote! {
3177                                #[inline(always)]
3178                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3179                                    rust_key_paths::Kp::new(
3180                                        |root: &#name| root.#idx_lit.as_ref().and_then(|c| c.get()),
3181                                        |_root: &mut #name| None,
3182                                    )
3183                                }
3184                            });
3185                        }
3186                        (WrapperKind::OptionLazy, Some(inner_ty)) => {
3187                            tokens.extend(quote! {
3188                                #[inline(always)]
3189                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3190                                    rust_key_paths::Kp::new(
3191                                        |root: &#name| root.#idx_lit.as_ref().map(|c| c.get()),
3192                                        |_root: &mut #name| None,
3193                                    )
3194                                }
3195                            });
3196                        }
3197                        (WrapperKind::Cell, Some(_inner_ty))
3198                        | (WrapperKind::RefCell, Some(_inner_ty))
3199                        | (WrapperKind::PhantomData, Some(_inner_ty))
3200                        | (WrapperKind::Range, Some(_inner_ty))
3201                        | (WrapperKind::OptionCell, Some(_inner_ty))
3202                        | (WrapperKind::OptionPhantomData, Some(_inner_ty))
3203                        | (WrapperKind::OptionRange, Some(_inner_ty)) => {
3204                            tokens.extend(quote! {
3205                                #[inline(always)]
3206                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3207                                    rust_key_paths::Kp::new(
3208                                        |root: &#name| Some(&root.#idx_lit),
3209                                        |root: &mut #name| Some(&mut root.#idx_lit),
3210                                    )
3211                                }
3212                            });
3213                        }
3214                        (WrapperKind::OptionRefCell, Some(inner_ty)) => {
3215                            tokens.extend(quote! {
3216                                #[inline(always)]
3217                                pub fn #kp_fn() -> rust_key_paths::KpOptionRefCellType<'_, #name, #inner_ty> {
3218                                    rust_key_paths::Kp::new(
3219                                        |root: &#name| root.#idx_lit.as_ref().map(|r| r.borrow()),
3220                                        |root: &mut #name| root.#idx_lit.as_ref().map(|r| r.borrow_mut()),
3221                                    )
3222                                }
3223                            });
3224                        }
3225                        (WrapperKind::Reference, Some(_inner_ty)) => {
3226                            tokens.extend(quote! {
3227                                #[inline(always)]
3228                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3229                                    rust_key_paths::Kp::new(
3230                                        |root: &#name| Some(&root.#idx_lit),
3231                                        |_root: &mut #name| None,
3232                                    )
3233                                }
3234                            });
3235                        }
3236                        (WrapperKind::None, None) => {
3237                            tokens.extend(quote! {
3238                                #[inline(always)]
3239                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3240                                    rust_key_paths::Kp::new(
3241                                        |root: &#name| Some(&root.#idx_lit),
3242                                        |root: &mut #name| Some(&mut root.#idx_lit),
3243                                    )
3244                                }
3245                            });
3246                        }
3247                        _ => {
3248                            tokens.extend(quote! {
3249                                #[inline(always)]
3250                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3251                                    rust_key_paths::Kp::new(
3252                                        |root: &#name| Some(&root.#idx_lit),
3253                                        |root: &mut #name| Some(&mut root.#idx_lit),
3254                                    )
3255                                }
3256                            });
3257                        }
3258                    }
3259                }
3260
3261                tokens
3262            }
3263            Fields::Unit => {
3264                return syn::Error::new(input_span, "Kp derive does not support unit structs")
3265                    .to_compile_error()
3266                    .into();
3267            }
3268        },
3269        Data::Enum(data_enum) => {
3270            let mut tokens = proc_macro2::TokenStream::new();
3271
3272            // Generate identity methods for the enum
3273            tokens.extend(quote! {
3274                /// Returns a generic identity keypath for this type
3275                #[inline(always)]
3276                pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
3277                    #name,
3278                    #name,
3279                    Root,
3280                    Root,
3281                    MutRoot,
3282                    MutRoot,
3283                    fn(Root) -> Option<Root>,
3284                    fn(MutRoot) -> Option<MutRoot>,
3285                >
3286                where
3287                    Root: std::borrow::Borrow<#name>,
3288                    MutRoot: std::borrow::BorrowMut<#name>,
3289                {
3290                    rust_key_paths::Kp::new(
3291                        |r: Root| Some(r),
3292                        |r: MutRoot| Some(r)
3293                    )
3294                }
3295
3296                /// Returns a simple identity keypath for this type
3297                #[inline(always)]
3298                pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
3299                    rust_key_paths::Kp::new(
3300                        |r: &#name| Some(r),
3301                        |r: &mut #name| Some(r)
3302                    )
3303                }
3304            });
3305
3306            for variant in data_enum.variants.iter() {
3307                let v_ident = &variant.ident;
3308                let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
3309
3310                match &variant.fields {
3311                    Fields::Unit => {
3312                        // Unit variant - return keypath that checks if enum matches variant
3313                        tokens.extend(quote! {
3314                            #[inline(always)]
3315                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, ()> {
3316                                rust_key_paths::Kp::new(
3317                                    |root: &#name| match root {
3318                                        #name::#v_ident => {
3319                                            static UNIT: () = ();
3320                                            Some(&UNIT)
3321                                        },
3322                                        _ => None,
3323                                    },
3324                                    |_root: &mut #name| None, // Can't mutate unit variant
3325                                )
3326                            }
3327                        });
3328                    }
3329                    Fields::Unnamed(unnamed) => {
3330                        if unnamed.unnamed.len() == 1 {
3331                            // Single-field tuple variant
3332                            let field_ty = &unnamed.unnamed[0].ty;
3333                            let (kind, inner_ty) = extract_wrapper_inner_type(field_ty);
3334
3335                            match (kind, inner_ty.clone()) {
3336                                (WrapperKind::Option, Some(inner_ty)) => {
3337                                    tokens.extend(quote! {
3338                                        #[inline(always)]
3339                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3340                                            rust_key_paths::Kp::new(
3341                                                |root: &#name| match root {
3342                                                    #name::#v_ident(inner) => inner.as_ref(),
3343                                                    _ => None,
3344                                                },
3345                                                |root: &mut #name| match root {
3346                                                    #name::#v_ident(inner) => inner.as_mut(),
3347                                                    _ => None,
3348                                                },
3349                                            )
3350                                        }
3351                                    });
3352                                }
3353                                (WrapperKind::OptionHashMap, Some(inner_ty)) => {
3354                                    let snake_at = format_ident!("{}_at", snake);
3355                                    if let Some((key_ty, _)) = extract_map_key_value_through_option(field_ty) {
3356                                        tokens.extend(quote! {
3357                                            #[inline(always)]
3358                                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3359                                                rust_key_paths::Kp::new(
3360                                                    |root: &#name| match root {
3361                                                        #name::#v_ident(inner) => Some(inner),
3362                                                        _ => None,
3363                                                    },
3364                                                    |root: &mut #name| match root {
3365                                                        #name::#v_ident(inner) => Some(inner),
3366                                                        _ => None,
3367                                                    },
3368                                                )
3369                                            }
3370                                            #[inline(always)]
3371                                            pub fn #snake_at(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
3372                                            where
3373                                                #key_ty: Clone + std::hash::Hash + Eq + 'static,
3374                                            {
3375                                                let key2 = key.clone();
3376                                                rust_key_paths::Kp::new(
3377                                                    Box::new(move |root: &#name| match root {
3378                                                        #name::#v_ident(inner) => inner.as_ref().and_then(|m| m.get(&key)),
3379                                                        _ => None,
3380                                                    }),
3381                                                    Box::new(move |root: &mut #name| match root {
3382                                                        #name::#v_ident(inner) => inner.as_mut().and_then(|m| m.get_mut(&key2)),
3383                                                        _ => None,
3384                                                    }),
3385                                                )
3386                                            }
3387                                        });
3388                                    } else {
3389                                        tokens.extend(quote! {
3390                                            #[inline(always)]
3391                                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3392                                                rust_key_paths::Kp::new(
3393                                                    |root: &#name| match root {
3394                                                        #name::#v_ident(inner) => Some(inner),
3395                                                        _ => None,
3396                                                    },
3397                                                    |root: &mut #name| match root {
3398                                                        #name::#v_ident(inner) => Some(inner),
3399                                                        _ => None,
3400                                                    },
3401                                                )
3402                                            }
3403                                        });
3404                                    }
3405                                }
3406                                (WrapperKind::OptionBTreeMap, Some(inner_ty)) => {
3407                                    let snake_at = format_ident!("{}_at", snake);
3408                                    if let Some((key_ty, _)) = extract_map_key_value_through_option(field_ty) {
3409                                        tokens.extend(quote! {
3410                                            #[inline(always)]
3411                                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3412                                                rust_key_paths::Kp::new(
3413                                                    |root: &#name| match root {
3414                                                        #name::#v_ident(inner) => Some(inner),
3415                                                        _ => None,
3416                                                    },
3417                                                    |root: &mut #name| match root {
3418                                                        #name::#v_ident(inner) => Some(inner),
3419                                                        _ => None,
3420                                                    },
3421                                                )
3422                                            }
3423                                            #[inline(always)]
3424                                            pub fn #snake_at(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
3425                                            where
3426                                                #key_ty: Clone + Ord + 'static,
3427                                            {
3428                                                let key2 = key.clone();
3429                                                rust_key_paths::Kp::new(
3430                                                    Box::new(move |root: &#name| match root {
3431                                                        #name::#v_ident(inner) => inner.as_ref().and_then(|m| m.get(&key)),
3432                                                        _ => None,
3433                                                    }),
3434                                                    Box::new(move |root: &mut #name| match root {
3435                                                        #name::#v_ident(inner) => inner.as_mut().and_then(|m| m.get_mut(&key2)),
3436                                                        _ => None,
3437                                                    }),
3438                                                )
3439                                            }
3440                                        });
3441                                    } else {
3442                                        tokens.extend(quote! {
3443                                            #[inline(always)]
3444                                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3445                                                rust_key_paths::Kp::new(
3446                                                    |root: &#name| match root {
3447                                                        #name::#v_ident(inner) => Some(inner),
3448                                                        _ => None,
3449                                                    },
3450                                                    |root: &mut #name| match root {
3451                                                        #name::#v_ident(inner) => Some(inner),
3452                                                        _ => None,
3453                                                    },
3454                                                )
3455                                            }
3456                                        });
3457                                    }
3458                                }
3459                                (WrapperKind::OptionHashSet, Some(inner_ty)) => {
3460                                    let snake_at = format_ident!("{}_at", snake);
3461                                    tokens.extend(quote! {
3462                                        #[inline(always)]
3463                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3464                                            rust_key_paths::Kp::new(
3465                                                |root: &#name| match root {
3466                                                    #name::#v_ident(inner) => Some(inner),
3467                                                    _ => None,
3468                                                },
3469                                                |root: &mut #name| match root {
3470                                                    #name::#v_ident(inner) => Some(inner),
3471                                                    _ => None,
3472                                                },
3473                                            )
3474                                        }
3475
3476                                        /// _at: check if element exists and get reference.
3477                                        /// HashSet does not allow mutable element access (would break hash invariant).
3478                                        #[inline(always)]
3479                                        pub fn #snake_at(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
3480                                        where
3481                                            #inner_ty: Clone + std::hash::Hash + Eq + 'static,
3482                                        {
3483                                            rust_key_paths::Kp::new(
3484                                                Box::new(move |root: &#name| match root {
3485                                                    #name::#v_ident(inner) => inner.as_ref().and_then(|s| s.get(&key)),
3486                                                    _ => None,
3487                                                }),
3488                                                Box::new(move |_root: &mut #name| None),
3489                                            )
3490                                        }
3491                                    });
3492                                }
3493                                (WrapperKind::OptionBTreeSet, Some(inner_ty)) => {
3494                                    let snake_at = format_ident!("{}_at", snake);
3495                                    tokens.extend(quote! {
3496                                        #[inline(always)]
3497                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3498                                            rust_key_paths::Kp::new(
3499                                                |root: &#name| match root {
3500                                                    #name::#v_ident(inner) => Some(inner),
3501                                                    _ => None,
3502                                                },
3503                                                |root: &mut #name| match root {
3504                                                    #name::#v_ident(inner) => Some(inner),
3505                                                    _ => None,
3506                                                },
3507                                            )
3508                                        }
3509
3510                                        /// _at: check if element exists and get reference.
3511                                        /// BTreeSet does not allow mutable element access (would break ordering invariant).
3512                                        #[inline(always)]
3513                                        pub fn #snake_at(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
3514                                        where
3515                                            #inner_ty: Clone + Ord + 'static,
3516                                        {
3517                                            rust_key_paths::Kp::new(
3518                                                Box::new(move |root: &#name| match root {
3519                                                    #name::#v_ident(inner) => inner.as_ref().and_then(|s| s.get(&key)),
3520                                                    _ => None,
3521                                                }),
3522                                                Box::new(move |_root: &mut #name| None),
3523                                            )
3524                                        }
3525                                    });
3526                                }
3527                                (WrapperKind::OptionVec, Some(inner_ty)) => {
3528                                    let snake_at = format_ident!("{}_at", snake);
3529                                    tokens.extend(quote! {
3530                                        #[inline(always)]
3531                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3532                                            rust_key_paths::Kp::new(
3533                                                |root: &#name| match root {
3534                                                    #name::#v_ident(inner) => Some(inner),
3535                                                    _ => None,
3536                                                },
3537                                                |root: &mut #name| match root {
3538                                                    #name::#v_ident(inner) => Some(inner),
3539                                                    _ => None,
3540                                                },
3541                                            )
3542                                        }
3543                                        #[inline(always)]
3544                                        pub fn #snake_at(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
3545                                            rust_key_paths::Kp::new(
3546                                                Box::new(move |root: &#name| match root {
3547                                                    #name::#v_ident(inner) => inner.as_ref().and_then(|v| v.get(index)),
3548                                                    _ => None,
3549                                                }),
3550                                                Box::new(move |root: &mut #name| match root {
3551                                                    #name::#v_ident(inner) => inner.as_mut().and_then(|v| v.get_mut(index)),
3552                                                    _ => None,
3553                                                }),
3554                                            )
3555                                        }
3556                                    });
3557                                }
3558                                (WrapperKind::OptionVecDeque, Some(inner_ty)) => {
3559                                    let snake_at = format_ident!("{}_at", snake);
3560                                    tokens.extend(quote! {
3561                                        #[inline(always)]
3562                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3563                                            rust_key_paths::Kp::new(
3564                                                |root: &#name| match root {
3565                                                    #name::#v_ident(inner) => Some(inner),
3566                                                    _ => None,
3567                                                },
3568                                                |root: &mut #name| match root {
3569                                                    #name::#v_ident(inner) => Some(inner),
3570                                                    _ => None,
3571                                                },
3572                                            )
3573                                        }
3574                                        #[inline(always)]
3575                                        pub fn #snake_at(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
3576                                            rust_key_paths::Kp::new(
3577                                                Box::new(move |root: &#name| match root {
3578                                                    #name::#v_ident(inner) => inner.as_ref().and_then(|v| v.get(index)),
3579                                                    _ => None,
3580                                                }),
3581                                                Box::new(move |root: &mut #name| match root {
3582                                                    #name::#v_ident(inner) => inner.as_mut().and_then(|v| v.get_mut(index)),
3583                                                    _ => None,
3584                                                }),
3585                                            )
3586                                        }
3587                                    });
3588                                }
3589                                (WrapperKind::OptionLinkedList, Some(_inner_ty))
3590                                | (WrapperKind::OptionBinaryHeap, Some(_inner_ty))
3591                                | (WrapperKind::OptionResult, Some(_inner_ty)) => {
3592                                    tokens.extend(quote! {
3593                                        #[inline(always)]
3594                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3595                                            rust_key_paths::Kp::new(
3596                                                |root: &#name| match root {
3597                                                    #name::#v_ident(inner) => Some(inner),
3598                                                    _ => None,
3599                                                },
3600                                                |root: &mut #name| match root {
3601                                                    #name::#v_ident(inner) => Some(inner),
3602                                                    _ => None,
3603                                                },
3604                                            )
3605                                        }
3606                                    });
3607                                }
3608                                (WrapperKind::Vec, Some(inner_ty)) => {
3609                                    tokens.extend(quote! {
3610                                        #[inline(always)]
3611                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3612                                            rust_key_paths::Kp::new(
3613                                                |root: &#name| match root {
3614                                                    #name::#v_ident(inner) => inner.first(),
3615                                                    _ => None,
3616                                                },
3617                                                |root: &mut #name| match root {
3618                                                    #name::#v_ident(inner) => inner.first_mut(),
3619                                                    _ => None,
3620                                                },
3621                                            )
3622                                        }
3623                                    });
3624                                }
3625                                (WrapperKind::Box, Some(inner_ty)) => {
3626                                    // Box in enum: deref to inner (&T / &mut T)
3627                                    tokens.extend(quote! {
3628                                        #[inline(always)]
3629                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3630                                            rust_key_paths::Kp::new(
3631                                                |root: &#name| match root {
3632                                                    #name::#v_ident(inner) => Some(&**inner),
3633                                                    _ => None,
3634                                                },
3635                                                |root: &mut #name| match root {
3636                                                    #name::#v_ident(inner) => Some(&mut **inner),
3637                                                    _ => None,
3638                                                },
3639                                            )
3640                                        }
3641                                    });
3642                                }
3643                                (WrapperKind::Pin, Some(inner_ty)) => {
3644                                    let snake_inner = format_ident!("{}_inner", snake);
3645                                    tokens.extend(quote! {
3646                                        #[inline(always)]
3647                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3648                                            rust_key_paths::Kp::new(
3649                                                |root: &#name| match root {
3650                                                    #name::#v_ident(inner) => Some(inner),
3651                                                    _ => None,
3652                                                },
3653                                                |root: &mut #name| match root {
3654                                                    #name::#v_ident(inner) => Some(inner),
3655                                                    _ => None,
3656                                                },
3657                                            )
3658                                        }
3659                                        #[inline(always)]
3660                                        pub fn #snake_inner() -> rust_key_paths::KpType<'static, #name, #inner_ty>
3661                                        where #inner_ty: std::marker::Unpin
3662                                        {
3663                                            rust_key_paths::Kp::new(
3664                                                |root: &#name| match root {
3665                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_ref(inner).get_ref()),
3666                                                    _ => None,
3667                                                },
3668                                                |root: &mut #name| match root {
3669                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_mut(inner).get_mut()),
3670                                                    _ => None,
3671                                                },
3672                                            )
3673                                        }
3674                                    });
3675                                }
3676                                (WrapperKind::PinBox, Some(inner_ty)) => {
3677                                    let snake_inner = format_ident!("{}_inner", snake);
3678                                    tokens.extend(quote! {
3679                                        #[inline(always)]
3680                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3681                                            rust_key_paths::Kp::new(
3682                                                |root: &#name| match root {
3683                                                    #name::#v_ident(inner) => Some(inner),
3684                                                    _ => None,
3685                                                },
3686                                                |root: &mut #name| match root {
3687                                                    #name::#v_ident(inner) => Some(inner),
3688                                                    _ => None,
3689                                                },
3690                                            )
3691                                        }
3692                                        #[inline(always)]
3693                                        pub fn #snake_inner() -> rust_key_paths::KpType<'static, #name, #inner_ty>
3694                                        where #inner_ty: std::marker::Unpin
3695                                        {
3696                                            rust_key_paths::Kp::new(
3697                                                |root: &#name| match root {
3698                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_ref(inner).get_ref()),
3699                                                    _ => None,
3700                                                },
3701                                                |root: &mut #name| match root {
3702                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_mut(inner).get_mut()),
3703                                                    _ => None,
3704                                                },
3705                                            )
3706                                        }
3707                                    });
3708                                }
3709                                (WrapperKind::Rc, Some(inner_ty)) => {
3710                                    tokens.extend(quote! {
3711                                        #[inline(always)]
3712                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3713                                            rust_key_paths::Kp::new(
3714                                                |root: &#name| match root {
3715                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
3716                                                    _ => None,
3717                                                },
3718                                                |root: &mut #name| match root {
3719                                                    #name::#v_ident(inner) => std::rc::Rc::get_mut(inner),
3720                                                    _ => None,
3721                                                },
3722                                            )
3723                                        }
3724                                    });
3725                                }
3726                                (WrapperKind::Arc, Some(inner_ty)) => {
3727                                    tokens.extend(quote! {
3728                                        #[inline(always)]
3729                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3730                                            rust_key_paths::Kp::new(
3731                                                |root: &#name| match root {
3732                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
3733                                                    _ => None,
3734                                                },
3735                                                |root: &mut #name| match root {
3736                                                    #name::#v_ident(inner) => std::sync::Arc::get_mut(inner),
3737                                                    _ => None,
3738                                                },
3739                                            )
3740                                        }
3741                                    });
3742                                }
3743                                (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
3744                                    let snake_lock = format_ident!("{}_lock", snake);
3745                                    tokens.extend(quote! {
3746                                        #[inline(always)]
3747                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3748                                            rust_key_paths::Kp::new(
3749                                                |root: &#name| match root {
3750                                                    #name::#v_ident(inner) => Some(inner),
3751                                                    _ => None,
3752                                                },
3753                                                |root: &mut #name| match root {
3754                                                    #name::#v_ident(inner) => Some(inner),
3755                                                    _ => None,
3756                                                },
3757                                            )
3758                                        }
3759                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #field_ty, #inner_ty> {
3760                                            rust_key_paths::lock::LockKp::new(
3761                                                rust_key_paths::Kp::new(
3762                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3763                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3764                                                ),
3765                                                rust_key_paths::lock::ArcRwLockAccess::new(),
3766                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3767                                            )
3768                                        }
3769                                    });
3770                                }
3771                                (WrapperKind::StdArcMutex, Some(inner_ty)) => {
3772                                    let snake_lock = format_ident!("{}_lock", snake);
3773                                    tokens.extend(quote! {
3774                                        #[inline(always)]
3775                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3776                                            rust_key_paths::Kp::new(
3777                                                |root: &#name| match root {
3778                                                    #name::#v_ident(inner) => Some(inner),
3779                                                    _ => None,
3780                                                },
3781                                                |root: &mut #name| match root {
3782                                                    #name::#v_ident(inner) => Some(inner),
3783                                                    _ => None,
3784                                                },
3785                                            )
3786                                        }
3787                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #field_ty, #inner_ty> {
3788                                            rust_key_paths::lock::LockKp::new(
3789                                                rust_key_paths::Kp::new(
3790                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3791                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3792                                                ),
3793                                                rust_key_paths::lock::ArcMutexAccess::new(),
3794                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3795                                            )
3796                                        }
3797                                    });
3798                                }
3799                                (WrapperKind::ArcRwLock, Some(inner_ty)) => {
3800                                    let snake_lock = format_ident!("{}_lock", snake);
3801                                    tokens.extend(quote! {
3802                                        #[inline(always)]
3803                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3804                                            rust_key_paths::Kp::new(
3805                                                |root: &#name| match root {
3806                                                    #name::#v_ident(inner) => Some(inner),
3807                                                    _ => None,
3808                                                },
3809                                                |root: &mut #name| match root {
3810                                                    #name::#v_ident(inner) => Some(inner),
3811                                                    _ => None,
3812                                                },
3813                                            )
3814                                        }
3815                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #field_ty, #inner_ty> {
3816                                            rust_key_paths::lock::LockKp::new(
3817                                                rust_key_paths::Kp::new(
3818                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3819                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3820                                                ),
3821                                                rust_key_paths::lock::ParkingLotRwLockAccess::new(),
3822                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3823                                            )
3824                                        }
3825                                    });
3826                                }
3827                                (WrapperKind::ArcMutex, Some(inner_ty)) => {
3828                                    let snake_lock = format_ident!("{}_lock", snake);
3829                                    tokens.extend(quote! {
3830                                        #[inline(always)]
3831                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3832                                            rust_key_paths::Kp::new(
3833                                                |root: &#name| match root {
3834                                                    #name::#v_ident(inner) => Some(inner),
3835                                                    _ => None,
3836                                                },
3837                                                |root: &mut #name| match root {
3838                                                    #name::#v_ident(inner) => Some(inner),
3839                                                    _ => None,
3840                                                },
3841                                            )
3842                                        }
3843                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #field_ty, #inner_ty> {
3844                                            rust_key_paths::lock::LockKp::new(
3845                                                rust_key_paths::Kp::new(
3846                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3847                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3848                                                ),
3849                                                rust_key_paths::lock::ParkingLotMutexAccess::new(),
3850                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3851                                            )
3852                                        }
3853                                    });
3854                                }
3855                                (WrapperKind::StdArcMutexOption, Some(inner_ty)) => {
3856                                    let snake_lock = format_ident!("{}_lock", snake);
3857                                    tokens.extend(quote! {
3858                                        #[inline(always)]
3859                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3860                                            rust_key_paths::Kp::new(
3861                                                |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3862                                                |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3863                                            )
3864                                        }
3865                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexOptionFor<#name, #field_ty, #inner_ty> {
3866                                            rust_key_paths::lock::LockKp::new(
3867                                                rust_key_paths::Kp::new(
3868                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3869                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3870                                                ),
3871                                                rust_key_paths::lock::ArcMutexAccess::<Option<#inner_ty>>::new(),
3872                                                rust_key_paths::Kp::new(Option::<#inner_ty>::as_ref, Option::<#inner_ty>::as_mut),
3873                                            )
3874                                        }
3875                                    });
3876                                }
3877                                (WrapperKind::StdArcRwLockOption, Some(inner_ty)) => {
3878                                    let snake_lock = format_ident!("{}_lock", snake);
3879                                    tokens.extend(quote! {
3880                                        #[inline(always)]
3881                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3882                                            rust_key_paths::Kp::new(
3883                                                |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3884                                                |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3885                                            )
3886                                        }
3887                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockOptionFor<#name, #field_ty, #inner_ty> {
3888                                            rust_key_paths::lock::LockKp::new(
3889                                                rust_key_paths::Kp::new(
3890                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3891                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3892                                                ),
3893                                                rust_key_paths::lock::ArcRwLockAccess::<Option<#inner_ty>>::new(),
3894                                                rust_key_paths::Kp::new(Option::<#inner_ty>::as_ref, Option::<#inner_ty>::as_mut),
3895                                            )
3896                                        }
3897                                    });
3898                                }
3899                                (WrapperKind::ArcMutexOption, Some(inner_ty)) => {
3900                                    let snake_lock = format_ident!("{}_lock", snake);
3901                                    tokens.extend(quote! {
3902                                        #[inline(always)]
3903                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3904                                            rust_key_paths::Kp::new(
3905                                                |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3906                                                |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3907                                            )
3908                                        }
3909                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexOptionFor<#name, #field_ty, #inner_ty> {
3910                                            rust_key_paths::lock::LockKp::new(
3911                                                rust_key_paths::Kp::new(
3912                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3913                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3914                                                ),
3915                                                rust_key_paths::lock::ParkingLotMutexAccess::<Option<#inner_ty>>::new(),
3916                                                rust_key_paths::Kp::new(Option::<#inner_ty>::as_ref, Option::<#inner_ty>::as_mut),
3917                                            )
3918                                        }
3919                                    });
3920                                }
3921                                (WrapperKind::ArcRwLockOption, Some(inner_ty)) => {
3922                                    let snake_lock = format_ident!("{}_lock", snake);
3923                                    tokens.extend(quote! {
3924                                        #[inline(always)]
3925                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3926                                            rust_key_paths::Kp::new(
3927                                                |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3928                                                |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3929                                            )
3930                                        }
3931                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockOptionFor<#name, #field_ty, #inner_ty> {
3932                                            rust_key_paths::lock::LockKp::new(
3933                                                rust_key_paths::Kp::new(
3934                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3935                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3936                                                ),
3937                                                rust_key_paths::lock::ParkingLotRwLockAccess::<Option<#inner_ty>>::new(),
3938                                                rust_key_paths::Kp::new(Option::<#inner_ty>::as_ref, Option::<#inner_ty>::as_mut),
3939                                            )
3940                                        }
3941                                    });
3942                                }
3943                                (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
3944                                    let snake_async = format_ident!("{}_kp", snake);
3945                                    tokens.extend(quote! {
3946                                        #[inline(always)]
3947                                        pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3948                                            rust_key_paths::Kp::new(
3949                                                |root: &#name| match root {
3950                                                    #name::#v_ident(inner) => Some(inner),
3951                                                    _ => None,
3952                                                },
3953                                                |root: &mut #name| match root {
3954                                                    #name::#v_ident(inner) => Some(inner),
3955                                                    _ => None,
3956                                                },
3957                                            )
3958                                        }
3959                                        pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #field_ty, #inner_ty> {
3960                                            rust_key_paths::async_lock::AsyncLockKp::new(
3961                                                rust_key_paths::Kp::new(
3962                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3963                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3964                                                ),
3965                                                rust_key_paths::async_lock::TokioMutexAccess::new(),
3966                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3967                                            )
3968                                        }
3969                                    });
3970                                }
3971                                (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
3972                                    let snake_async = format_ident!("{}_kp", snake);
3973                                    tokens.extend(quote! {
3974                                        #[inline(always)]
3975                                        pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3976                                            rust_key_paths::Kp::new(
3977                                                |root: &#name| match root {
3978                                                    #name::#v_ident(inner) => Some(inner),
3979                                                    _ => None,
3980                                                },
3981                                                |root: &mut #name| match root {
3982                                                    #name::#v_ident(inner) => Some(inner),
3983                                                    _ => None,
3984                                                },
3985                                            )
3986                                        }
3987                                        pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #field_ty, #inner_ty> {
3988                                            rust_key_paths::async_lock::AsyncLockKp::new(
3989                                                rust_key_paths::Kp::new(
3990                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3991                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3992                                                ),
3993                                                rust_key_paths::async_lock::TokioRwLockAccess::new(),
3994                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3995                                            )
3996                                        }
3997                                    });
3998                                }
3999                                (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
4000                                    let snake_async = format_ident!("{}_kp", snake);
4001                                    tokens.extend(quote! {
4002                                        #[inline(always)]
4003                                        pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4004                                            rust_key_paths::Kp::new(
4005                                                |root: &#name| match root {
4006                                                    #name::#v_ident(inner) => Some(inner),
4007                                                    _ => None,
4008                                                },
4009                                                |root: &mut #name| match root {
4010                                                    #name::#v_ident(inner) => Some(inner),
4011                                                    _ => None,
4012                                                },
4013                                            )
4014                                        }
4015                                        pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
4016                                            rust_key_paths::async_lock::AsyncLockKp::new(
4017                                                rust_key_paths::Kp::new(
4018                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4019                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4020                                                ),
4021                                                rust_key_paths::async_lock::TokioMutexAccess::new(),
4022                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
4023                                            )
4024                                        }
4025                                    });
4026                                }
4027                                (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
4028                                    let snake_async = format_ident!("{}_kp", snake);
4029                                    tokens.extend(quote! {
4030                                        #[inline(always)]
4031                                        pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4032                                            rust_key_paths::Kp::new(
4033                                                |root: &#name| match root {
4034                                                    #name::#v_ident(inner) => Some(inner),
4035                                                    _ => None,
4036                                                },
4037                                                |root: &mut #name| match root {
4038                                                    #name::#v_ident(inner) => Some(inner),
4039                                                    _ => None,
4040                                                },
4041                                            )
4042                                        }
4043                                        pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
4044                                            rust_key_paths::async_lock::AsyncLockKp::new(
4045                                                rust_key_paths::Kp::new(
4046                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4047                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4048                                                ),
4049                                                rust_key_paths::async_lock::TokioRwLockAccess::new(),
4050                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
4051                                            )
4052                                        }
4053                                    });
4054                                }
4055                                (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
4056                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
4057                                    let snake_lock = format_ident!("{}_lock", snake);
4058                                    tokens.extend(quote! {
4059                                        #[inline(always)]
4060                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4061                                            rust_key_paths::Kp::new(
4062                                                |root: &#name| match root {
4063                                                    #name::#v_ident(inner) => Some(inner),
4064                                                    _ => None,
4065                                                },
4066                                                |root: &mut #name| match root {
4067                                                    #name::#v_ident(inner) => Some(inner),
4068                                                    _ => None,
4069                                                },
4070                                            )
4071                                        }
4072                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
4073                                            rust_key_paths::Kp::new(
4074                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4075                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4076                                            )
4077                                        }
4078                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
4079                                            rust_key_paths::lock::LockKp::new(
4080                                                rust_key_paths::Kp::new(
4081                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4082                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4083                                                ),
4084                                                rust_key_paths::lock::ArcMutexAccess::new(),
4085                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
4086                                            )
4087                                        }
4088                                    });
4089                                }
4090                                (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
4091                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
4092                                    let snake_lock = format_ident!("{}_lock", snake);
4093                                    tokens.extend(quote! {
4094                                        #[inline(always)]
4095                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4096                                            rust_key_paths::Kp::new(
4097                                                |root: &#name| match root {
4098                                                    #name::#v_ident(inner) => Some(inner),
4099                                                    _ => None,
4100                                                },
4101                                                |root: &mut #name| match root {
4102                                                    #name::#v_ident(inner) => Some(inner),
4103                                                    _ => None,
4104                                                },
4105                                            )
4106                                        }
4107                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
4108                                            rust_key_paths::Kp::new(
4109                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4110                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4111                                            )
4112                                        }
4113                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>, #inner_ty> {
4114                                            rust_key_paths::lock::LockKp::new(
4115                                                rust_key_paths::Kp::new(
4116                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4117                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4118                                                ),
4119                                                rust_key_paths::lock::ParkingLotMutexAccess::new(),
4120                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
4121                                            )
4122                                        }
4123                                    });
4124                                }
4125                                (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
4126                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
4127                                    let snake_lock = format_ident!("{}_lock", snake);
4128                                    tokens.extend(quote! {
4129                                        #[inline(always)]
4130                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4131                                            rust_key_paths::Kp::new(
4132                                                |root: &#name| match root {
4133                                                    #name::#v_ident(inner) => Some(inner),
4134                                                    _ => None,
4135                                                },
4136                                                |root: &mut #name| match root {
4137                                                    #name::#v_ident(inner) => Some(inner),
4138                                                    _ => None,
4139                                                },
4140                                            )
4141                                        }
4142                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
4143                                            rust_key_paths::Kp::new(
4144                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4145                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4146                                            )
4147                                        }
4148                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
4149                                            rust_key_paths::lock::LockKp::new(
4150                                                rust_key_paths::Kp::new(
4151                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4152                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4153                                                ),
4154                                                rust_key_paths::lock::ArcRwLockAccess::new(),
4155                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
4156                                            )
4157                                        }
4158                                    });
4159                                }
4160                                (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
4161                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
4162                                    let snake_lock = format_ident!("{}_lock", snake);
4163                                    tokens.extend(quote! {
4164                                        #[inline(always)]
4165                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4166                                            rust_key_paths::Kp::new(
4167                                                |root: &#name| match root {
4168                                                    #name::#v_ident(inner) => Some(inner),
4169                                                    _ => None,
4170                                                },
4171                                                |root: &mut #name| match root {
4172                                                    #name::#v_ident(inner) => Some(inner),
4173                                                    _ => None,
4174                                                },
4175                                            )
4176                                        }
4177                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
4178                                            rust_key_paths::Kp::new(
4179                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4180                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4181                                            )
4182                                        }
4183                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>, #inner_ty> {
4184                                            rust_key_paths::lock::LockKp::new(
4185                                                rust_key_paths::Kp::new(
4186                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4187                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4188                                                ),
4189                                                rust_key_paths::lock::ParkingLotRwLockAccess::new(),
4190                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
4191                                            )
4192                                        }
4193                                    });
4194                                }
4195                                (WrapperKind::StdMutex, Some(_inner_ty))
4196                                | (WrapperKind::Mutex, Some(_inner_ty))
4197                                | (WrapperKind::StdRwLock, Some(_inner_ty))
4198                                | (WrapperKind::RwLock, Some(_inner_ty)) => {
4199                                    tokens.extend(quote! {
4200                                        #[inline(always)]
4201                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4202                                            rust_key_paths::Kp::new(
4203                                                |root: &#name| match root {
4204                                                    #name::#v_ident(inner) => Some(inner),
4205                                                    _ => None,
4206                                                },
4207                                                |root: &mut #name| match root {
4208                                                    #name::#v_ident(inner) => Some(inner),
4209                                                    _ => None,
4210                                                },
4211                                            )
4212                                        }
4213                                    });
4214                                }
4215                                (WrapperKind::Tagged, Some(inner_ty)) => {
4216                                    tokens.extend(quote! {
4217                                        #[inline(always)]
4218                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4219                                            rust_key_paths::Kp::new(
4220                                                |root: &#name| match root {
4221                                                    #name::#v_ident(inner) => Some(std::ops::Deref::deref(inner)),
4222                                                    _ => None,
4223                                                },
4224                                                |root: &mut #name| match root {
4225                                                    #name::#v_ident(inner) => Some(std::ops::DerefMut::deref_mut(inner)),
4226                                                    _ => None,
4227                                                },
4228                                            )
4229                                        }
4230                                    });
4231                                }
4232                                (WrapperKind::Atomic, None | Some(_)) => {
4233                                    tokens.extend(quote! {
4234                                        #[inline(always)]
4235                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4236                                            rust_key_paths::Kp::new(
4237                                                |root: &#name| match root {
4238                                                    #name::#v_ident(inner) => Some(inner),
4239                                                    _ => None,
4240                                                },
4241                                                |root: &mut #name| match root {
4242                                                    #name::#v_ident(inner) => Some(inner),
4243                                                    _ => None,
4244                                                },
4245                                            )
4246                                        }
4247                                    });
4248                                }
4249                                (WrapperKind::OptionAtomic, Some(inner_ty)) => {
4250                                    tokens.extend(quote! {
4251                                        #[inline(always)]
4252                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4253                                            rust_key_paths::Kp::new(
4254                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4255                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4256                                            )
4257                                        }
4258                                    });
4259                                }
4260                                (WrapperKind::Reference, Some(_inner_ty)) => {
4261                                    tokens.extend(quote! {
4262                                        #[inline(always)]
4263                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4264                                            rust_key_paths::Kp::new(
4265                                                |root: &#name| match root {
4266                                                    #name::#v_ident(inner) => Some(inner),
4267                                                    _ => None,
4268                                                },
4269                                                |_root: &mut #name| None,
4270                                            )
4271                                        }
4272                                    });
4273                                }
4274                                (WrapperKind::Weak, Some(_inner_ty)) => {
4275                                    tokens.extend(quote! {
4276                                        #[inline(always)]
4277                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4278                                            rust_key_paths::Kp::new(
4279                                                |root: &#name| match root {
4280                                                    #name::#v_ident(inner) => Some(inner),
4281                                                    _ => None,
4282                                                },
4283                                                |_root: &mut #name| None,
4284                                            )
4285                                        }
4286                                    });
4287                                }
4288                                (WrapperKind::Cow, Some(inner_ty)) => {
4289                                    tokens.extend(quote! {
4290                                        #[inline(always)]
4291                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4292                                            rust_key_paths::Kp::new(
4293                                                |root: &#name| match root {
4294                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
4295                                                    _ => None,
4296                                                },
4297                                                |root: &mut #name| match root {
4298                                                    #name::#v_ident(inner) => Some(inner.to_mut()),
4299                                                    _ => None,
4300                                                },
4301                                            )
4302                                        }
4303                                    });
4304                                }
4305                                (WrapperKind::OptionBox, Some(inner_ty)) => {
4306                                    // Option<Box<T>>: keypath to T via as_deref() / as_deref_mut()
4307                                    tokens.extend(quote! {
4308                                        #[inline(always)]
4309                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4310                                            rust_key_paths::Kp::new(
4311                                                |root: &#name| match root {
4312                                                    #name::#v_ident(inner) => inner.as_deref(),
4313                                                    _ => None,
4314                                                },
4315                                                |root: &mut #name| match root {
4316                                                    #name::#v_ident(inner) => inner.as_deref_mut(),
4317                                                    _ => None,
4318                                                },
4319                                            )
4320                                        }
4321                                    });
4322                                }
4323                                (WrapperKind::BoxOption, Some(inner_ty)) => {
4324                                    // Box<Option<T>>: keypath to T; inner is &Box<Option<T>>, deref then Option::as_ref/as_mut
4325                                    tokens.extend(quote! {
4326                                        #[inline(always)]
4327                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4328                                            rust_key_paths::Kp::new(
4329                                                |root: &#name| match root {
4330                                                    #name::#v_ident(inner) => (&*inner).as_ref(),
4331                                                    _ => None,
4332                                                },
4333                                                |root: &mut #name| match root {
4334                                                    #name::#v_ident(inner) => (&mut *inner).as_mut(),
4335                                                    _ => None,
4336                                                },
4337                                            )
4338                                        }
4339                                    });
4340                                }
4341                                (WrapperKind::RcOption, Some(inner_ty)) => {
4342                                    // Rc<Option<T>>: keypath to T; get = (&*inner).as_ref(), set = Rc::get_mut then as_mut
4343                                    tokens.extend(quote! {
4344                                        #[inline(always)]
4345                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4346                                            rust_key_paths::Kp::new(
4347                                                |root: &#name| match root {
4348                                                    #name::#v_ident(inner) => (&*inner).as_ref(),
4349                                                    _ => None,
4350                                                },
4351                                                |root: &mut #name| match root {
4352                                                    #name::#v_ident(inner) => std::rc::Rc::get_mut(inner).and_then(std::option::Option::as_mut),
4353                                                    _ => None,
4354                                                },
4355                                            )
4356                                        }
4357                                    });
4358                                }
4359                                (WrapperKind::ArcOption, Some(inner_ty)) => {
4360                                    // Arc<Option<T>>: keypath to T; get = (&*inner).as_ref(), set = Arc::get_mut then as_mut
4361                                    tokens.extend(quote! {
4362                                        #[inline(always)]
4363                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4364                                            rust_key_paths::Kp::new(
4365                                                |root: &#name| match root {
4366                                                    #name::#v_ident(inner) => (&*inner).as_ref(),
4367                                                    _ => None,
4368                                                },
4369                                                |root: &mut #name| match root {
4370                                                    #name::#v_ident(inner) => std::sync::Arc::get_mut(inner).and_then(std::option::Option::as_mut),
4371                                                    _ => None,
4372                                                },
4373                                            )
4374                                        }
4375                                    });
4376                                }
4377                                (WrapperKind::OptionRc, Some(inner_ty)) => {
4378                                    tokens.extend(quote! {
4379                                        #[inline(always)]
4380                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4381                                            rust_key_paths::Kp::new(
4382                                                |root: &#name| match root {
4383                                                    #name::#v_ident(inner) => inner.as_deref(),
4384                                                    _ => None,
4385                                                },
4386                                                |root: &mut #name| match root {
4387                                                    #name::#v_ident(inner) => inner.as_mut().and_then(std::rc::Rc::get_mut),
4388                                                    _ => None,
4389                                                },
4390                                            )
4391                                        }
4392                                    });
4393                                }
4394                                (WrapperKind::OptionArc, Some(inner_ty)) => {
4395                                    tokens.extend(quote! {
4396                                        #[inline(always)]
4397                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4398                                            rust_key_paths::Kp::new(
4399                                                |root: &#name| match root {
4400                                                    #name::#v_ident(inner) => inner.as_deref(),
4401                                                    _ => None,
4402                                                },
4403                                                |root: &mut #name| match root {
4404                                                    #name::#v_ident(inner) => inner.as_mut().and_then(std::sync::Arc::get_mut),
4405                                                    _ => None,
4406                                                },
4407                                            )
4408                                        }
4409                                    });
4410                                }
4411                                (WrapperKind::OptionCow, Some(inner_ty)) => {
4412                                    tokens.extend(quote! {
4413                                        #[inline(always)]
4414                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4415                                            rust_key_paths::Kp::new(
4416                                                |root: &#name| match root {
4417                                                    #name::#v_ident(inner) => inner.as_ref().map(|c| c.as_ref()),
4418                                                    _ => None,
4419                                                },
4420                                                |root: &mut #name| match root {
4421                                                    #name::#v_ident(inner) => inner.as_mut().map(|c| c.to_mut()),
4422                                                    _ => None,
4423                                                },
4424                                            )
4425                                        }
4426                                    });
4427                                }
4428                                (WrapperKind::OptionTagged, Some(inner_ty)) => {
4429                                    tokens.extend(quote! {
4430                                        #[inline(always)]
4431                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4432                                            rust_key_paths::Kp::new(
4433                                                |root: &#name| match root {
4434                                                    #name::#v_ident(inner) => inner.as_ref().map(|t| std::ops::Deref::deref(t)),
4435                                                    _ => None,
4436                                                },
4437                                                |root: &mut #name| match root {
4438                                                    #name::#v_ident(inner) => inner.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
4439                                                    _ => None,
4440                                                },
4441                                            )
4442                                        }
4443                                    });
4444                                }
4445                                (WrapperKind::OptionReference, Some(inner_ty)) => {
4446                                    tokens.extend(quote! {
4447                                        #[inline(always)]
4448                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4449                                            rust_key_paths::Kp::new(
4450                                                |root: &#name| match root {
4451                                                    #name::#v_ident(inner) => inner.as_ref(),
4452                                                    _ => None,
4453                                                },
4454                                                |_root: &mut #name| None,
4455                                            )
4456                                        }
4457                                    });
4458                                }
4459                                (WrapperKind::String, None) => {
4460                                    tokens.extend(quote! {
4461                                        #[inline(always)]
4462                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4463                                            rust_key_paths::Kp::new(
4464                                                |root: &#name| match root {
4465                                                    #name::#v_ident(inner) => Some(inner),
4466                                                    _ => None,
4467                                                },
4468                                                |root: &mut #name| match root {
4469                                                    #name::#v_ident(inner) => Some(inner),
4470                                                    _ => None,
4471                                                },
4472                                            )
4473                                        }
4474                                    });
4475                                }
4476                                (WrapperKind::OptionString, None) => {
4477                                    tokens.extend(quote! {
4478                                        #[inline(always)]
4479                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, std::string::String> {
4480                                            rust_key_paths::Kp::new(
4481                                                |root: &#name| match root {
4482                                                    #name::#v_ident(inner) => inner.as_ref(),
4483                                                    _ => None,
4484                                                },
4485                                                |root: &mut #name| match root {
4486                                                    #name::#v_ident(inner) => inner.as_mut(),
4487                                                    _ => None,
4488                                                },
4489                                            )
4490                                        }
4491                                    });
4492                                }
4493                                (WrapperKind::OnceCell, Some(inner_ty)) => {
4494                                    tokens.extend(quote! {
4495                                        #[inline(always)]
4496                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4497                                            rust_key_paths::Kp::new(
4498                                                |root: &#name| match root {
4499                                                    #name::#v_ident(inner) => inner.get(),
4500                                                    _ => None,
4501                                                },
4502                                                |_root: &mut #name| None,
4503                                            )
4504                                        }
4505                                    });
4506                                }
4507                                (WrapperKind::Lazy, Some(inner_ty)) => {
4508                                    tokens.extend(quote! {
4509                                        #[inline(always)]
4510                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4511                                            rust_key_paths::Kp::new(
4512                                                |root: &#name| match root {
4513                                                    #name::#v_ident(inner) => Some(inner.get()),
4514                                                    _ => None,
4515                                                },
4516                                                |_root: &mut #name| None,
4517                                            )
4518                                        }
4519                                    });
4520                                }
4521                                (WrapperKind::OptionOnceCell, Some(inner_ty)) => {
4522                                    tokens.extend(quote! {
4523                                        #[inline(always)]
4524                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4525                                            rust_key_paths::Kp::new(
4526                                                |root: &#name| match root {
4527                                                    #name::#v_ident(inner) => inner.as_ref().and_then(|c| c.get()),
4528                                                    _ => None,
4529                                                },
4530                                                |_root: &mut #name| None,
4531                                            )
4532                                        }
4533                                    });
4534                                }
4535                                (WrapperKind::OptionLazy, Some(inner_ty)) => {
4536                                    tokens.extend(quote! {
4537                                        #[inline(always)]
4538                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4539                                            rust_key_paths::Kp::new(
4540                                                |root: &#name| match root {
4541                                                    #name::#v_ident(inner) => inner.as_ref().map(|c| c.get()),
4542                                                    _ => None,
4543                                                },
4544                                                |_root: &mut #name| None,
4545                                            )
4546                                        }
4547                                    });
4548                                }
4549                                (WrapperKind::Cell, Some(_inner_ty))
4550                                | (WrapperKind::RefCell, Some(_inner_ty))
4551                                | (WrapperKind::PhantomData, Some(_inner_ty))
4552                                | (WrapperKind::Range, Some(_inner_ty))
4553                                | (WrapperKind::OptionCell, Some(_inner_ty))
4554                                | (WrapperKind::OptionPhantomData, Some(_inner_ty))
4555                                | (WrapperKind::OptionRange, Some(_inner_ty)) => {
4556                                    tokens.extend(quote! {
4557                                        #[inline(always)]
4558                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4559                                            rust_key_paths::Kp::new(
4560                                                |root: &#name| match root {
4561                                                    #name::#v_ident(inner) => Some(inner),
4562                                                    _ => None,
4563                                                },
4564                                                |root: &mut #name| match root {
4565                                                    #name::#v_ident(inner) => Some(inner),
4566                                                    _ => None,
4567                                                },
4568                                            )
4569                                        }
4570                                    });
4571                                }
4572                                (WrapperKind::OptionRefCell, Some(inner_ty)) => {
4573                                    tokens.extend(quote! {
4574                                        #[inline(always)]
4575                                        pub fn #snake() -> rust_key_paths::KpOptionRefCellType<'_, #name, #inner_ty> {
4576                                            rust_key_paths::Kp::new(
4577                                                |root: &#name| match root {
4578                                                    #name::#v_ident(inner) => inner.as_ref().map(|r| r.borrow()),
4579                                                    _ => None,
4580                                                },
4581                                                |root: &mut #name| match root {
4582                                                    #name::#v_ident(inner) => inner.as_ref().map(|r| r.borrow_mut()),
4583                                                    _ => None,
4584                                                },
4585                                            )
4586                                        }
4587                                    });
4588                                }
4589                                (WrapperKind::None, None) => {
4590                                    // Basic type
4591                                    tokens.extend(quote! {
4592                                        #[inline(always)]
4593                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4594                                            rust_key_paths::Kp::new(
4595                                                |root: &#name| match root {
4596                                                    #name::#v_ident(inner) => Some(inner),
4597                                                    _ => None,
4598                                                },
4599                                                |root: &mut #name| match root {
4600                                                    #name::#v_ident(inner) => Some(inner),
4601                                                    _ => None,
4602                                                },
4603                                            )
4604                                        }
4605                                    });
4606                                }
4607                                _ => {
4608                                    // Other wrapper types - return keypath to field
4609                                    tokens.extend(quote! {
4610                                        #[inline(always)]
4611                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4612                                            rust_key_paths::Kp::new(
4613                                                |root: &#name| match root {
4614                                                    #name::#v_ident(inner) => Some(inner),
4615                                                    _ => None,
4616                                                },
4617                                                |root: &mut #name| match root {
4618                                                    #name::#v_ident(inner) => Some(inner),
4619                                                    _ => None,
4620                                                },
4621                                            )
4622                                        }
4623                                    });
4624                                }
4625                            }
4626                        } else {
4627                            // Multi-field tuple variant - return keypath to variant itself
4628                            tokens.extend(quote! {
4629                                #[inline(always)]
4630                                pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
4631                                    rust_key_paths::Kp::new(
4632                                        |root: &#name| match root {
4633                                            #name::#v_ident(..) => Some(root),
4634                                            _ => None,
4635                                        },
4636                                        |root: &mut #name| match root {
4637                                            #name::#v_ident(..) => Some(root),
4638                                            _ => None,
4639                                        },
4640                                    )
4641                                }
4642                            });
4643                        }
4644                    }
4645                    Fields::Named(_) => {
4646                        // Named field variant - return keypath to variant itself
4647                        tokens.extend(quote! {
4648                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
4649                                rust_key_paths::Kp::new(
4650                                    |root: &#name| match root {
4651                                        #name::#v_ident { .. } => Some(root),
4652                                        _ => None,
4653                                    },
4654                                    |root: &mut #name| match root {
4655                                        #name::#v_ident { .. } => Some(root),
4656                                        _ => None,
4657                                    },
4658                                )
4659                            }
4660                        });
4661                    }
4662                }
4663            }
4664
4665            tokens
4666        }
4667        Data::Union(_) => {
4668            return syn::Error::new(input_span, "Kp derive does not support unions")
4669                .to_compile_error()
4670                .into();
4671        }
4672    };
4673
4674    let expanded = quote! {
4675        impl #name {
4676            #methods
4677        }
4678    };
4679
4680    TokenStream::from(expanded)
4681}
4682
4683/// Derive macro that generates `partial_kps() -> Vec<PKp<Self>>` returning all field/variant keypaths.
4684/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
4685///
4686/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
4687/// (using the same methods Kp generates, e.g. `some_variant()`).
4688///
4689/// # Example
4690/// ```
4691/// use key_paths_derive::{Kp, Pkp};
4692/// use rust_key_paths::PKp;
4693///
4694/// #[derive(Kp, Pkp)]
4695/// struct Person {
4696///     name: String,
4697///     age: i32,
4698/// }
4699///
4700/// let kps = Person::partial_kps();
4701/// assert_eq!(kps.len(), 2);
4702/// ```
4703#[proc_macro_derive(Pkp)]
4704pub fn derive_partial_keypaths(input: TokenStream) -> TokenStream {
4705    let input = parse_macro_input!(input as DeriveInput);
4706    let name = &input.ident;
4707
4708    let kp_calls = match &input.data {
4709        Data::Struct(data_struct) => match &data_struct.fields {
4710            Fields::Named(fields_named) => {
4711                let calls: Vec<_> = fields_named
4712                    .named
4713                    .iter()
4714                    .filter_map(|f| f.ident.as_ref())
4715                    .map(|field_ident| {
4716                        quote! { rust_key_paths::PKp::new(Self::#field_ident()) }
4717                    })
4718                    .collect();
4719                quote! { #(#calls),* }
4720            }
4721            Fields::Unnamed(unnamed) => {
4722                let calls: Vec<_> = (0..unnamed.unnamed.len())
4723                    .map(|idx| {
4724                        let kp_fn = format_ident!("f{}", idx);
4725                        quote! { rust_key_paths::PKp::new(Self::#kp_fn()) }
4726                    })
4727                    .collect();
4728                quote! { #(#calls),* }
4729            }
4730            Fields::Unit => quote! {},
4731        },
4732        Data::Enum(data_enum) => {
4733            let calls: Vec<_> = data_enum
4734                .variants
4735                .iter()
4736                .map(|variant| {
4737                    let v_ident = &variant.ident;
4738                    let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
4739                    quote! { rust_key_paths::PKp::new(Self::#snake()) }
4740                })
4741                .collect();
4742            quote! { #(#calls),* }
4743        }
4744        Data::Union(_) => {
4745            return syn::Error::new(input.ident.span(), "Pkp derive does not support unions")
4746                .to_compile_error()
4747                .into();
4748        }
4749    };
4750
4751    let expanded = quote! {
4752        impl #name {
4753            /// Returns a vec of all field keypaths as partial keypaths (type-erased).
4754            #[inline(always)]
4755            pub fn partial_kps() -> Vec<rust_key_paths::PKp<#name>> {
4756                vec![#kp_calls]
4757            }
4758        }
4759    };
4760
4761    TokenStream::from(expanded)
4762}
4763
4764/// Derive macro that generates `any_kps() -> Vec<AKp>` returning all field/variant keypaths as any keypaths.
4765/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
4766/// AKp type-erases both Root and Value, enabling heterogeneous collections of keypaths.
4767///
4768/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
4769/// (using the same methods Kp generates, e.g. `some_variant()`).
4770///
4771/// # Example
4772/// ```
4773/// use key_paths_derive::{Kp, Akp};
4774/// use rust_key_paths::AKp;
4775///
4776/// #[derive(Kp, Akp)]
4777/// struct Person {
4778///     name: String,
4779///     age: i32,
4780/// }
4781///
4782/// let kps = Person::any_kps();
4783/// assert_eq!(kps.len(), 2);
4784/// let person = Person { name: "Akash".into(), age: 30 };
4785/// let name: Option<&String> = kps[0].get(&person as &dyn std::any::Any).and_then(|v| v.downcast_ref());
4786/// assert_eq!(name, Some(&"Akash".to_string()));
4787/// ```
4788#[proc_macro_derive(Akp)]
4789pub fn derive_any_keypaths(input: TokenStream) -> TokenStream {
4790    let input = parse_macro_input!(input as DeriveInput);
4791    let name = &input.ident;
4792
4793    let kp_calls = match &input.data {
4794        Data::Struct(data_struct) => match &data_struct.fields {
4795            Fields::Named(fields_named) => {
4796                let calls: Vec<_> = fields_named
4797                    .named
4798                    .iter()
4799                    .filter_map(|f| f.ident.as_ref())
4800                    .map(|field_ident| {
4801                        quote! { rust_key_paths::AKp::new(Self::#field_ident()) }
4802                    })
4803                    .collect();
4804                quote! { #(#calls),* }
4805            }
4806            Fields::Unnamed(unnamed) => {
4807                let calls: Vec<_> = (0..unnamed.unnamed.len())
4808                    .map(|idx| {
4809                        let kp_fn = format_ident!("f{}", idx);
4810                        quote! { rust_key_paths::AKp::new(Self::#kp_fn()) }
4811                    })
4812                    .collect();
4813                quote! { #(#calls),* }
4814            }
4815            Fields::Unit => quote! {},
4816        },
4817        Data::Enum(data_enum) => {
4818            let calls: Vec<_> = data_enum
4819                .variants
4820                .iter()
4821                .map(|variant| {
4822                    let v_ident = &variant.ident;
4823                    let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
4824                    quote! { rust_key_paths::AKp::new(Self::#snake()) }
4825                })
4826                .collect();
4827            quote! { #(#calls),* }
4828        }
4829        Data::Union(_) => {
4830            return syn::Error::new(input.ident.span(), "Akp derive does not support unions")
4831                .to_compile_error()
4832                .into();
4833        }
4834    };
4835
4836    let expanded = quote! {
4837        impl #name {
4838            /// Returns a vec of all field keypaths as any keypaths (fully type-erased).
4839            #[inline(always)]
4840            pub fn any_kps() -> Vec<rust_key_paths::AKp> {
4841                vec![#kp_calls]
4842            }
4843        }
4844    };
4845
4846    TokenStream::from(expanded)
4847}