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::OptionVecDeque, Some(_inner_ty))
949                        | (WrapperKind::OptionLinkedList, Some(_inner_ty))
950                        | (WrapperKind::OptionBinaryHeap, Some(_inner_ty))
951                        | (WrapperKind::OptionResult, Some(_inner_ty)) => {
952                            // Keypath to the Option container (reference), like Vec/HashSet
953                            tokens.extend(quote! {
954                                #[inline(always)]
955                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
956                                    rust_key_paths::Kp::new(
957                                        |root: &#name| Some(&root.#field_ident),
958                                        |root: &mut #name| Some(&mut root.#field_ident),
959                                    )
960                                }
961                            });
962                        }
963                        (WrapperKind::Vec, Some(inner_ty)) => {
964                            tokens.extend(quote! {
965                                #[inline(always)]
966                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
967                                    rust_key_paths::Kp::new(
968                                        |root: &#name| Some(&root.#field_ident),
969                                        |root: &mut #name| Some(&mut root.#field_ident),
970                                    )
971                                }
972                                #[inline(always)]
973                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
974                                    rust_key_paths::Kp::new(
975                                        Box::new(move |root: &#name| root.#field_ident.get(index)),
976                                        Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
977                                    )
978                                }
979                            });
980                        }
981                        (WrapperKind::HashMap, Some(inner_ty)) => {
982                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
983                                tokens.extend(quote! {
984                                    #[inline(always)]
985                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
986                                        rust_key_paths::Kp::new(
987                                            |root: &#name| Some(&root.#field_ident),
988                                            |root: &mut #name| Some(&mut root.#field_ident),
989                                        )
990                                    }
991                                    #[inline(always)]
992                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
993                                    where
994                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
995                                    {
996                                        let key2 = key.clone();
997                                        rust_key_paths::Kp::new(
998                                            Box::new(move |root: &#name| root.#field_ident.get(&key)),
999                                            Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
1000                                        )
1001                                    }
1002                                });
1003                            } else {
1004                                tokens.extend(quote! {
1005                                    #[inline(always)]
1006                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1007                                        rust_key_paths::Kp::new(
1008                                            |root: &#name| Some(&root.#field_ident),
1009                                            |root: &mut #name| Some(&mut root.#field_ident),
1010                                        )
1011                                    }
1012                                });
1013                            }
1014                        }
1015                        (WrapperKind::BTreeMap, Some(inner_ty))
1016                        | (WrapperKind::BTreeMapOption, 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 + Ord + '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::Box, Some(inner_ty)) => {
1051                            // For Box<T>, deref to inner type (returns &T / &mut T, not &Box<T>)
1052                            tokens.extend(quote! {
1053                                #[inline(always)]
1054                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1055                                    rust_key_paths::Kp::new(
1056                                        |root: &#name| Some(&*root.#field_ident),
1057                                        |root: &mut #name| Some(&mut *root.#field_ident),
1058                                    )
1059                                }
1060                            });
1061                        }
1062                        (WrapperKind::BoxOption, Some(inner_ty)) => {
1063                            // For Box<Option<T>>, keypath to T: deref Box to Option<T>, then Option::as_ref/as_mut
1064                            tokens.extend(quote! {
1065                                #[inline(always)]
1066                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1067                                    rust_key_paths::Kp::new(
1068                                        |root: &#name| (&*root.#field_ident).as_ref(),
1069                                        |root: &mut #name| (&mut *root.#field_ident).as_mut(),
1070                                    )
1071                                }
1072                            });
1073                        }
1074                        (WrapperKind::RcOption, Some(inner_ty)) => {
1075                            // For Rc<Option<T>>, keypath to T: deref Rc to &Option<T>, then Option::as_ref; set = Rc::get_mut then as_mut
1076                            tokens.extend(quote! {
1077                                #[inline(always)]
1078                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1079                                    rust_key_paths::Kp::new(
1080                                        |root: &#name| (&*root.#field_ident).as_ref(),
1081                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#field_ident).and_then(std::option::Option::as_mut),
1082                                    )
1083                                }
1084                            });
1085                        }
1086                        (WrapperKind::ArcOption, Some(inner_ty)) => {
1087                            // For Arc<Option<T>>, keypath to T: deref Arc to &Option<T>, then Option::as_ref; set = Arc::get_mut then as_mut
1088                            tokens.extend(quote! {
1089                                #[inline(always)]
1090                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1091                                    rust_key_paths::Kp::new(
1092                                        |root: &#name| (&*root.#field_ident).as_ref(),
1093                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#field_ident).and_then(std::option::Option::as_mut),
1094                                    )
1095                                }
1096                            });
1097                        }
1098                        (WrapperKind::Pin, Some(inner_ty)) => {
1099                            let kp_inner_fn = format_ident!("{}_inner", field_ident);
1100                            tokens.extend(quote! {
1101                                #[inline(always)]
1102                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1103                                    rust_key_paths::Kp::new(
1104                                        |root: &#name| Some(&root.#field_ident),
1105                                        |root: &mut #name| Some(&mut root.#field_ident),
1106                                    )
1107                                }
1108                                #[inline(always)]
1109                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
1110                                where #inner_ty: std::marker::Unpin
1111                                {
1112                                    rust_key_paths::Kp::new(
1113                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#field_ident).get_ref()),
1114                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#field_ident).get_mut()),
1115                                    )
1116                                }
1117                            });
1118                        }
1119                        (WrapperKind::PinBox, Some(inner_ty)) => {
1120                            let kp_inner_fn = format_ident!("{}_inner", field_ident);
1121                            tokens.extend(quote! {
1122                                #[inline(always)]
1123                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1124                                    rust_key_paths::Kp::new(
1125                                        |root: &#name| Some(&root.#field_ident),
1126                                        |root: &mut #name| Some(&mut root.#field_ident),
1127                                    )
1128                                }
1129                                #[inline(always)]
1130                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
1131                                where #inner_ty: std::marker::Unpin
1132                                {
1133                                    // Pin::as_ref on Pin<Box<T>> returns Pin<&T> (Box Deref target), so get_ref() already gives &T
1134                                    rust_key_paths::Kp::new(
1135                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#field_ident).get_ref()),
1136                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#field_ident).get_mut()),
1137                                    )
1138                                }
1139                            });
1140                        }
1141                        (WrapperKind::PinnedField, _) => {
1142                            let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
1143                            tokens.extend(quote! {
1144                                #[inline(always)]
1145                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1146                                    rust_key_paths::Kp::new(
1147                                        |root: &#name| Some(&root.#field_ident),
1148                                        |root: &mut #name| Some(&mut root.#field_ident),
1149                                    )
1150                                }
1151                                /// Pinned projection for #[pin] field. Requires #[pin_project] on struct.
1152                                #[inline(always)]
1153                                pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
1154                                    this.project().#field_ident
1155                                }
1156                            });
1157                        }
1158                        (WrapperKind::PinnedFuture, _) => {
1159                            let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
1160                            let kp_await_fn = format_ident!("{}_await", field_ident);
1161                            let kp_pin_future_fn = format_ident!("{}_pin_future_kp", field_ident);
1162                            let output_ty = quote! { <#ty as std::future::Future>::Output };
1163                            tokens.extend(quote! {
1164                                #[inline(always)]
1165                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1166                                    rust_key_paths::Kp::new(
1167                                        |root: &#name| Some(&root.#field_ident),
1168                                        |root: &mut #name| Some(&mut root.#field_ident),
1169                                    )
1170                                }
1171                                /// Pinned projection for #[pin] Future field. Requires #[pin_project] on struct.
1172                                #[inline(always)]
1173                                pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
1174                                    this.project().#field_ident
1175                                }
1176                                /// Poll the pinned future. Requires #[pin_project] on struct.
1177                                pub async fn #kp_await_fn(this: std::pin::Pin<&mut #name>) -> Option<#output_ty>
1178                                where #ty: std::future::Future
1179                                {
1180                                    use std::future::Future;
1181                                    Some(this.project().#field_ident.await)
1182                                }
1183                                /// Keypath for [rust_key_paths::Kp::then_pin_future]. Composable pin future await.
1184                                #[inline(always)]
1185                                pub fn #kp_pin_future_fn() -> impl rust_key_paths::pin::PinFutureAwaitLike<#name, #output_ty> {
1186                                    rust_key_paths::pin_future_await_kp!(#name, #kp_await_fn -> #output_ty)
1187                                }
1188                            });
1189                        }
1190                        (WrapperKind::PinnedBoxFuture, Some(output_ty)) => {
1191                            let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
1192                            let kp_await_fn = format_ident!("{}_await", field_ident);
1193                            let kp_pin_future_fn = format_ident!("{}_pin_future_kp", field_ident);
1194                            tokens.extend(quote! {
1195                                #[inline(always)]
1196                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1197                                    rust_key_paths::Kp::new(
1198                                        |root: &#name| Some(&root.#field_ident),
1199                                        |root: &mut #name| Some(&mut root.#field_ident),
1200                                    )
1201                                }
1202                                /// Pinned projection for #[pin] Box<dyn Future> field. Requires #[pin_project] on struct.
1203                                #[inline(always)]
1204                                pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
1205                                    this.project().#field_ident
1206                                }
1207                                /// Poll the pinned boxed future. Requires #[pin_project] on struct.
1208                                pub async fn #kp_await_fn(this: std::pin::Pin<&mut #name>) -> Option<#output_ty> {
1209                                    Some(this.project().#field_ident.await)
1210                                }
1211                                /// Keypath for [rust_key_paths::Kp::then_pin_future]. Composable pin future await.
1212                                #[inline(always)]
1213                                pub fn #kp_pin_future_fn() -> impl rust_key_paths::pin::PinFutureAwaitLike<#name, #output_ty> {
1214                                    rust_key_paths::pin_future_await_kp!(#name, #kp_await_fn -> #output_ty)
1215                                }
1216                            });
1217                        }
1218                        (WrapperKind::Rc, Some(inner_ty)) => {
1219                            // For Rc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
1220                            tokens.extend(quote! {
1221                                #[inline(always)]
1222                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1223                                    rust_key_paths::Kp::new(
1224                                        |root: &#name| Some(root.#field_ident.as_ref()),
1225                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#field_ident),
1226                                    )
1227                                }
1228                            });
1229                        }
1230                        (WrapperKind::Arc, Some(inner_ty)) => {
1231                            // For Arc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
1232                            tokens.extend(quote! {
1233                                #[inline(always)]
1234                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1235                                    rust_key_paths::Kp::new(
1236                                        |root: &#name| Some(root.#field_ident.as_ref()),
1237                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#field_ident),
1238                                    )
1239                                }
1240                            });
1241                        }
1242                        (WrapperKind::Cow, Some(inner_ty)) => {
1243                            // For Cow<'_, B>, deref to inner type (as_ref/to_mut)
1244                            tokens.extend(quote! {
1245                                #[inline(always)]
1246                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1247                                    rust_key_paths::Kp::new(
1248                                        |root: &#name| Some(root.#field_ident.as_ref()),
1249                                        |root: &mut #name| Some(root.#field_ident.to_mut()),
1250                                    )
1251                                }
1252                            });
1253                        }
1254
1255                        (WrapperKind::OptionCow, Some(inner_ty)) => {
1256                            // For Option<Cow<'_, B>>
1257                            tokens.extend(quote! {
1258                                #[inline(always)]
1259                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1260                                    rust_key_paths::Kp::new(
1261                                        |root: &#name| root.#field_ident.as_ref().map(|c| c.as_ref()),
1262                                        |root: &mut #name| root.#field_ident.as_mut().map(|c| c.to_mut()),
1263                                    )
1264                                }
1265                            });
1266                        }
1267                        (WrapperKind::OptionTagged, Some(inner_ty)) => {
1268                            // For Option<Tagged<Tag, T>> - Tagged implements Deref/DerefMut
1269                            tokens.extend(quote! {
1270                                #[inline(always)]
1271                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1272                                    rust_key_paths::Kp::new(
1273                                        |root: &#name| root.#field_ident.as_ref().map(|t| std::ops::Deref::deref(t)),
1274                                        |root: &mut #name| root.#field_ident.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
1275                                    )
1276                                }
1277                            });
1278                        }
1279                        (WrapperKind::OptionReference, Some(inner_ty)) => {
1280                            // For Option<&T>, Option<&str>, Option<&[T]> - read-only, setter returns None
1281                            tokens.extend(quote! {
1282                                #[inline(always)]
1283                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1284                                    rust_key_paths::Kp::new(
1285                                        |root: &#name| root.#field_ident.as_ref(),
1286                                        |_root: &mut #name| None,
1287                                    )
1288                                }
1289                            });
1290                        }
1291                        (WrapperKind::HashSet, Some(inner_ty))
1292                        | (WrapperKind::HashSetOption, Some(inner_ty)) => {
1293                            let kp_at_fn = format_ident!("{}_at", field_ident);
1294
1295                            tokens.extend(quote! {
1296                                #[inline(always)]
1297                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1298                                    rust_key_paths::Kp::new(
1299                                        |root: &#name| Some(&root.#field_ident),
1300                                        |root: &mut #name| Some(&mut root.#field_ident),
1301                                    )
1302                                }
1303
1304                                /// _at: check if element exists and get reference.
1305                                /// HashSet does not allow mutable element access (would break hash invariant).
1306                                #[inline(always)]
1307                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1308                                where
1309                                    #inner_ty: Clone + std::hash::Hash + Eq + 'static,
1310                                {
1311                                    rust_key_paths::Kp::new(
1312                                        Box::new(move |root: &#name| root.#field_ident.get(&key)),
1313                                        Box::new(move |_root: &mut #name| None),
1314                                    )
1315                                }
1316                            });
1317                        }
1318                        (WrapperKind::BTreeSet, Some(inner_ty))
1319                        | (WrapperKind::BTreeSetOption, Some(inner_ty)) => {
1320                            let kp_at_fn = format_ident!("{}_at", field_ident);
1321
1322                            tokens.extend(quote! {
1323                                #[inline(always)]
1324                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1325                                    rust_key_paths::Kp::new(
1326                                        |root: &#name| Some(&root.#field_ident),
1327                                        |root: &mut #name| Some(&mut root.#field_ident),
1328                                    )
1329                                }
1330
1331                                /// _at: check if element exists and get reference.
1332                                /// BTreeSet does not allow mutable element access (would break ordering invariant).
1333                                #[inline(always)]
1334                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1335                                where
1336                                    #inner_ty: Clone + Ord + 'static,
1337                                {
1338                                    rust_key_paths::Kp::new(
1339                                        Box::new(move |root: &#name| root.#field_ident.get(&key)),
1340                                        Box::new(move |_root: &mut #name| None),
1341                                    )
1342                                }
1343                            });
1344                        }
1345                        (WrapperKind::VecDeque, Some(inner_ty))
1346                        | (WrapperKind::VecDequeOption, Some(inner_ty)) => {
1347                            tokens.extend(quote! {
1348                                #[inline(always)]
1349                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1350                                    rust_key_paths::Kp::new(
1351                                        |root: &#name| Some(&root.#field_ident),
1352                                        |root: &mut #name| Some(&mut root.#field_ident),
1353                                    )
1354                                }
1355                                #[inline(always)]
1356                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1357                                    rust_key_paths::Kp::new(
1358                                        Box::new(move |root: &#name| root.#field_ident.get(index)),
1359                                        Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
1360                                    )
1361                                }
1362                            });
1363                        }
1364                        (WrapperKind::LinkedList, Some(_inner_ty))
1365                        | (WrapperKind::LinkedListOption, Some(_inner_ty)) => {
1366                            tokens.extend(quote! {
1367                                #[inline(always)]
1368                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1369                                    rust_key_paths::Kp::new(
1370                                        |root: &#name| Some(&root.#field_ident),
1371                                        |root: &mut #name| Some(&mut root.#field_ident),
1372                                    )
1373                                }
1374                            });
1375                        }
1376                        (WrapperKind::BinaryHeap, Some(_inner_ty))
1377                        | (WrapperKind::BinaryHeapOption, Some(_inner_ty)) => {
1378                            tokens.extend(quote! {
1379                                #[inline(always)]
1380                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1381                                    rust_key_paths::Kp::new(
1382                                        |root: &#name| Some(&root.#field_ident),
1383                                        |root: &mut #name| Some(&mut root.#field_ident),
1384                                    )
1385                                }
1386                            });
1387                        }
1388                        (WrapperKind::Result, Some(inner_ty)) => {
1389                            // For Result<T, E>, access Ok value
1390                            tokens.extend(quote! {
1391                                #[inline(always)]
1392                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1393                                    rust_key_paths::Kp::new(
1394                                        |root: &#name| root.#field_ident.as_ref().ok(),
1395                                        |root: &mut #name| root.#field_ident.as_mut().ok(),
1396                                    )
1397                                }
1398                            });
1399                        }
1400                        (WrapperKind::StdArcMutex, Some(inner_ty)) => {
1401                            // For Arc<std::sync::Mutex<T>>
1402                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1403                            tokens.extend(quote! {
1404                                #[inline(always)]
1405                                    pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1406                                    rust_key_paths::Kp::new(
1407                                        |root: &#name| Some(&root.#field_ident),
1408                                        |root: &mut #name| Some(&mut root.#field_ident),
1409                                    )
1410                                }
1411                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #ty, #inner_ty> {
1412                                    rust_key_paths::lock::LockKp::new(
1413                                        rust_key_paths::Kp::new(
1414                                            |root: &#name| Some(&root.#field_ident),
1415                                            |root: &mut #name| Some(&mut root.#field_ident),
1416                                        ),
1417                                        rust_key_paths::lock::ArcMutexAccess::new(),
1418                                        rust_key_paths::Kp::new(
1419                                            |v: &#inner_ty| Some(v),
1420                                            |v: &mut #inner_ty| Some(v),
1421                                        ),
1422                                    )
1423                                }
1424                            });
1425                        }
1426                        (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
1427                            // For Arc<std::sync::RwLock<T>>
1428                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1429                            tokens.extend(quote! {
1430                                #[inline(always)]
1431                                    pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1432                                    rust_key_paths::Kp::new(
1433                                        |root: &#name| Some(&root.#field_ident),
1434                                        |root: &mut #name| Some(&mut root.#field_ident),
1435                                    )
1436                                }
1437                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #ty, #inner_ty> {
1438                                    rust_key_paths::lock::LockKp::new(
1439                                        rust_key_paths::Kp::new(
1440                                            |root: &#name| Some(&root.#field_ident),
1441                                            |root: &mut #name| Some(&mut root.#field_ident),
1442                                        ),
1443                                        rust_key_paths::lock::ArcRwLockAccess::new(),
1444                                        rust_key_paths::Kp::new(
1445                                            |v: &#inner_ty| Some(v),
1446                                            |v: &mut #inner_ty| Some(v),
1447                                        ),
1448                                    )
1449                                }
1450                            });
1451                        }
1452                        (WrapperKind::StdArcMutexOption, Some(inner_ty)) => {
1453                            // For Arc<std::sync::Mutex<Option<T>>> — LockKp value T (extract from Option); guard gives &Option<T>
1454                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1455                            tokens.extend(quote! {
1456                                #[inline(always)]
1457                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1458                                    rust_key_paths::Kp::new(
1459                                        |root: &#name| Some(&root.#field_ident),
1460                                        |root: &mut #name| Some(&mut root.#field_ident),
1461                                    )
1462                                }
1463                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcMutexOptionFor<#name, #ty, #inner_ty> {
1464                                    rust_key_paths::lock::LockKp::new(
1465                                        rust_key_paths::Kp::new(
1466                                            |root: &#name| Some(&root.#field_ident),
1467                                            |root: &mut #name| Some(&mut root.#field_ident),
1468                                        ),
1469                                        rust_key_paths::lock::ArcMutexAccess::<Option<#inner_ty>>::new(),
1470                                        rust_key_paths::Kp::new(
1471                                            Option::<#inner_ty>::as_ref,
1472                                            Option::<#inner_ty>::as_mut,
1473                                        ),
1474                                    )
1475                                }
1476                            });
1477                        }
1478                        (WrapperKind::StdArcRwLockOption, Some(inner_ty)) => {
1479                            // For Arc<std::sync::RwLock<Option<T>>> — LockKp value T (extract from Option); guard gives &Option<T>
1480                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1481                            tokens.extend(quote! {
1482                                #[inline(always)]
1483                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1484                                    rust_key_paths::Kp::new(
1485                                        |root: &#name| Some(&root.#field_ident),
1486                                        |root: &mut #name| Some(&mut root.#field_ident),
1487                                    )
1488                                }
1489                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcRwLockOptionFor<#name, #ty, #inner_ty> {
1490                                    rust_key_paths::lock::LockKp::new(
1491                                        rust_key_paths::Kp::new(
1492                                            |root: &#name| Some(&root.#field_ident),
1493                                            |root: &mut #name| Some(&mut root.#field_ident),
1494                                        ),
1495                                        rust_key_paths::lock::ArcRwLockAccess::<Option<#inner_ty>>::new(),
1496                                        rust_key_paths::Kp::new(
1497                                            Option::<#inner_ty>::as_ref,
1498                                            Option::<#inner_ty>::as_mut,
1499                                        ),
1500                                    )
1501                                }
1502                            });
1503                        }
1504                        (WrapperKind::ArcRwLock, Some(inner_ty)) => {
1505                            // For Arc<parking_lot::RwLock<T>> (requires rust-key-paths "parking_lot" feature)
1506                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1507                            tokens.extend(quote! {
1508                                #[inline(always)]
1509                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1510                                    rust_key_paths::Kp::new(
1511                                        |root: &#name| Some(&root.#field_ident),
1512                                        |root: &mut #name| Some(&mut root.#field_ident),
1513                                    )
1514                                }
1515                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #ty, #inner_ty> {
1516                                    rust_key_paths::lock::LockKp::new(
1517                                        rust_key_paths::Kp::new(
1518                                            |root: &#name| Some(&root.#field_ident),
1519                                            |root: &mut #name| Some(&mut root.#field_ident),
1520                                        ),
1521                                        rust_key_paths::lock::ParkingLotRwLockAccess::new(),
1522                                        rust_key_paths::Kp::new(
1523                                            |v: &#inner_ty| Some(v),
1524                                            |v: &mut #inner_ty| Some(v),
1525                                        ),
1526                                    )
1527                                }
1528                            });
1529                        }
1530                        (WrapperKind::ArcMutex, Some(inner_ty)) => {
1531                            // For Arc<parking_lot::Mutex<T>> (requires rust-key-paths "parking_lot" feature)
1532                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1533                            tokens.extend(quote! {
1534                                #[inline(always)]
1535                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1536                                    rust_key_paths::Kp::new(
1537                                        |root: &#name| Some(&root.#field_ident),
1538                                        |root: &mut #name| Some(&mut root.#field_ident),
1539                                    )
1540                                }
1541                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #ty, #inner_ty> {
1542                                    rust_key_paths::lock::LockKp::new(
1543                                        rust_key_paths::Kp::new(
1544                                            |root: &#name| Some(&root.#field_ident),
1545                                            |root: &mut #name| Some(&mut root.#field_ident),
1546                                        ),
1547                                        rust_key_paths::lock::ParkingLotMutexAccess::new(),
1548                                        rust_key_paths::Kp::new(
1549                                            |v: &#inner_ty| Some(v),
1550                                            |v: &mut #inner_ty| Some(v),
1551                                        ),
1552                                    )
1553                                }
1554                            });
1555                        }
1556                        (WrapperKind::ArcMutexOption, Some(inner_ty)) => {
1557                            // For Arc<parking_lot::Mutex<Option<T>>> — LockKp value T (extract from Option); guard gives &Option<T>
1558                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1559                            tokens.extend(quote! {
1560                                #[inline(always)]
1561                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1562                                    rust_key_paths::Kp::new(
1563                                        |root: &#name| Some(&root.#field_ident),
1564                                        |root: &mut #name| Some(&mut root.#field_ident),
1565                                    )
1566                                }
1567                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotMutexOptionFor<#name, #ty, #inner_ty> {
1568                                    rust_key_paths::lock::LockKp::new(
1569                                        rust_key_paths::Kp::new(
1570                                            |root: &#name| Some(&root.#field_ident),
1571                                            |root: &mut #name| Some(&mut root.#field_ident),
1572                                        ),
1573                                        rust_key_paths::lock::ParkingLotMutexAccess::<Option<#inner_ty>>::new(),
1574                                        rust_key_paths::Kp::new(
1575                                            Option::<#inner_ty>::as_ref,
1576                                            Option::<#inner_ty>::as_mut,
1577                                        ),
1578                                    )
1579                                }
1580                            });
1581                        }
1582                        (WrapperKind::ArcRwLockOption, Some(inner_ty)) => {
1583                            // For Arc<parking_lot::RwLock<Option<T>>> — LockKp value T (extract from Option); guard gives &Option<T>
1584                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1585                            tokens.extend(quote! {
1586                                #[inline(always)]
1587                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1588                                    rust_key_paths::Kp::new(
1589                                        |root: &#name| Some(&root.#field_ident),
1590                                        |root: &mut #name| Some(&mut root.#field_ident),
1591                                    )
1592                                }
1593                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockOptionFor<#name, #ty, #inner_ty> {
1594                                    rust_key_paths::lock::LockKp::new(
1595                                        rust_key_paths::Kp::new(
1596                                            |root: &#name| Some(&root.#field_ident),
1597                                            |root: &mut #name| Some(&mut root.#field_ident),
1598                                        ),
1599                                        rust_key_paths::lock::ParkingLotRwLockAccess::<Option<#inner_ty>>::new(),
1600                                        rust_key_paths::Kp::new(
1601                                            Option::<#inner_ty>::as_ref,
1602                                            Option::<#inner_ty>::as_mut,
1603                                        ),
1604                                    )
1605                                }
1606                            });
1607                        }
1608                        (WrapperKind::Mutex, Some(_inner_ty))
1609                        | (WrapperKind::StdMutex, Some(_inner_ty)) => {
1610                            // For Mutex<T>, return keypath to container
1611                            tokens.extend(quote! {
1612                                #[inline(always)]
1613                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1614                                    rust_key_paths::Kp::new(
1615                                        |root: &#name| Some(&root.#field_ident),
1616                                        |root: &mut #name| Some(&mut root.#field_ident),
1617                                    )
1618                                }
1619                            });
1620                        }
1621                        (WrapperKind::RwLock, Some(_inner_ty))
1622                        | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
1623                            // For RwLock<T>, return keypath to container
1624                            tokens.extend(quote! {
1625                                #[inline(always)]
1626                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1627                                    rust_key_paths::Kp::new(
1628                                        |root: &#name| Some(&root.#field_ident),
1629                                        |root: &mut #name| Some(&mut root.#field_ident),
1630                                    )
1631                                }
1632                            });
1633                        }
1634                        (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
1635                            let kp_async_fn = format_ident!("{}_kp", field_ident);
1636                            tokens.extend(quote! {
1637                                #[inline(always)]
1638                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1639                                    rust_key_paths::Kp::new(
1640                                        |root: &#name| Some(&root.#field_ident),
1641                                        |root: &mut #name| Some(&mut root.#field_ident),
1642                                    )
1643                                }
1644                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
1645                                    rust_key_paths::async_lock::AsyncLockKp::new(
1646                                        rust_key_paths::Kp::new(
1647                                            |root: &#name| Some(&root.#field_ident),
1648                                            |root: &mut #name| Some(&mut root.#field_ident),
1649                                        ),
1650                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
1651                                        rust_key_paths::Kp::new(
1652                                            |v: &#inner_ty| Some(v),
1653                                            |v: &mut #inner_ty| Some(v),
1654                                        ),
1655                                    )
1656                                }
1657                            });
1658                        }
1659                        (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
1660                            let kp_async_fn = format_ident!("{}_kp", field_ident);
1661                            tokens.extend(quote! {
1662                                #[inline(always)]
1663                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1664                                    rust_key_paths::Kp::new(
1665                                        |root: &#name| Some(&root.#field_ident),
1666                                        |root: &mut #name| Some(&mut root.#field_ident),
1667                                    )
1668                                }
1669                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
1670                                    rust_key_paths::async_lock::AsyncLockKp::new(
1671                                        rust_key_paths::Kp::new(
1672                                            |root: &#name| Some(&root.#field_ident),
1673                                            |root: &mut #name| Some(&mut root.#field_ident),
1674                                        ),
1675                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
1676                                        rust_key_paths::Kp::new(
1677                                            |v: &#inner_ty| Some(v),
1678                                            |v: &mut #inner_ty| Some(v),
1679                                        ),
1680                                    )
1681                                }
1682                            });
1683                        }
1684                        (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
1685                            let kp_async_fn = format_ident!("{}_kp", field_ident);
1686                            tokens.extend(quote! {
1687                                #[inline(always)]
1688                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1689                                    rust_key_paths::Kp::new(
1690                                        |root: &#name| Some(&root.#field_ident),
1691                                        |root: &mut #name| Some(&mut root.#field_ident),
1692                                    )
1693                                }
1694                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
1695                                    rust_key_paths::async_lock::AsyncLockKp::new(
1696                                        rust_key_paths::Kp::new(
1697                                            |root: &#name| root.#field_ident.as_ref(),
1698                                            |root: &mut #name| root.#field_ident.as_mut(),
1699                                        ),
1700                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
1701                                        rust_key_paths::Kp::new(
1702                                            |v: &#inner_ty| Some(v),
1703                                            |v: &mut #inner_ty| Some(v),
1704                                        ),
1705                                    )
1706                                }
1707                            });
1708                        }
1709                        (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
1710                            let kp_async_fn = format_ident!("{}_kp", field_ident);
1711                            tokens.extend(quote! {
1712                                #[inline(always)]
1713                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1714                                    rust_key_paths::Kp::new(
1715                                        |root: &#name| Some(&root.#field_ident),
1716                                        |root: &mut #name| Some(&mut root.#field_ident),
1717                                    )
1718                                }
1719                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
1720                                    rust_key_paths::async_lock::AsyncLockKp::new(
1721                                        rust_key_paths::Kp::new(
1722                                            |root: &#name| root.#field_ident.as_ref(),
1723                                            |root: &mut #name| root.#field_ident.as_mut(),
1724                                        ),
1725                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
1726                                        rust_key_paths::Kp::new(
1727                                            |v: &#inner_ty| Some(v),
1728                                            |v: &mut #inner_ty| Some(v),
1729                                        ),
1730                                    )
1731                                }
1732                            });
1733                        }
1734                        (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
1735                            // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1736                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1737                            tokens.extend(quote! {
1738                                #[inline(always)]
1739                                    pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1740                                    rust_key_paths::Kp::new(
1741                                        |root: &#name| Some(&root.#field_ident),
1742                                        |root: &mut #name| Some(&mut root.#field_ident),
1743                                    )
1744                                }
1745                                // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
1746                                //     rust_key_paths::Kp::new(
1747                                //         |root: &#name| root.#field_ident.as_ref(),
1748                                //         |root: &mut #name| root.#field_ident.as_mut(),
1749                                //     )
1750                                // }
1751                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
1752                                    rust_key_paths::lock::LockKp::new(
1753                                        rust_key_paths::Kp::new(
1754                                            |root: &#name| root.#field_ident.as_ref(),
1755                                            |root: &mut #name| root.#field_ident.as_mut(),
1756                                        ),
1757                                        rust_key_paths::lock::ArcMutexAccess::new(),
1758                                        rust_key_paths::Kp::new(
1759                                            |v: &#inner_ty| Some(v),
1760                                            |v: &mut #inner_ty| Some(v),
1761                                        ),
1762                                    )
1763                                }
1764                            });
1765                        }
1766                        (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
1767                            // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1768                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1769                            tokens.extend(quote! {
1770                                #[inline(always)]
1771                                pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1772                                    rust_key_paths::Kp::new(
1773                                        |root: &#name| Some(&root.#field_ident),
1774                                        |root: &mut #name| Some(&mut root.#field_ident),
1775                                    )
1776                                }
1777                                // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
1778                                //     rust_key_paths::Kp::new(
1779                                //         |root: &#name| root.#field_ident.as_ref(),
1780                                //         |root: &mut #name| root.#field_ident.as_mut(),
1781                                //     )
1782                                // }
1783                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>, #inner_ty> {
1784                                    rust_key_paths::lock::LockKp::new(
1785                                        rust_key_paths::Kp::new(
1786                                            |root: &#name| root.#field_ident.as_ref(),
1787                                            |root: &mut #name| root.#field_ident.as_mut(),
1788                                        ),
1789                                        rust_key_paths::lock::ParkingLotMutexAccess::new(),
1790                                        rust_key_paths::Kp::new(
1791                                            |v: &#inner_ty| Some(v),
1792                                            |v: &mut #inner_ty| Some(v),
1793                                        ),
1794                                    )
1795                                }
1796                            });
1797                        }
1798                        (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
1799                            // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1800                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1801                            tokens.extend(quote! {
1802                                #[inline(always)]
1803                                    pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1804                                    rust_key_paths::Kp::new(
1805                                        |root: &#name| Some(&root.#field_ident),
1806                                        |root: &mut #name| Some(&mut root.#field_ident),
1807                                    )
1808                                }
1809                                // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
1810                                //     rust_key_paths::Kp::new(
1811                                //         |root: &#name| root.#field_ident.as_ref(),
1812                                //         |root: &mut #name| root.#field_ident.as_mut(),
1813                                //     )
1814                                // }
1815                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
1816                                    rust_key_paths::lock::LockKp::new(
1817                                        rust_key_paths::Kp::new(
1818                                            |root: &#name| root.#field_ident.as_ref(),
1819                                            |root: &mut #name| root.#field_ident.as_mut(),
1820                                        ),
1821                                        rust_key_paths::lock::ArcRwLockAccess::new(),
1822                                        rust_key_paths::Kp::new(
1823                                            |v: &#inner_ty| Some(v),
1824                                            |v: &mut #inner_ty| Some(v),
1825                                        ),
1826                                    )
1827                                }
1828                            });
1829                        }
1830                        (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
1831                            // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1832                            let kp_lock_fn = format_ident!("{}_kp", field_ident);
1833                            tokens.extend(quote! {
1834                                #[inline(always)]
1835                                    pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1836                                    rust_key_paths::Kp::new(
1837                                        |root: &#name| Some(&root.#field_ident),
1838                                        |root: &mut #name| Some(&mut root.#field_ident),
1839                                    )
1840                                }
1841                                // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
1842                                //     rust_key_paths::Kp::new(
1843                                //         |root: &#name| root.#field_ident.as_ref(),
1844                                //         |root: &mut #name| root.#field_ident.as_mut(),
1845                                //     )
1846                                // }
1847                                pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>, #inner_ty> {
1848                                    rust_key_paths::lock::LockKp::new(
1849                                        rust_key_paths::Kp::new(
1850                                            |root: &#name| root.#field_ident.as_ref(),
1851                                            |root: &mut #name| root.#field_ident.as_mut(),
1852                                        ),
1853                                        rust_key_paths::lock::ParkingLotRwLockAccess::new(),
1854                                        rust_key_paths::Kp::new(
1855                                            |v: &#inner_ty| Some(v),
1856                                            |v: &mut #inner_ty| Some(v),
1857                                        ),
1858                                    )
1859                                }
1860                            });
1861                        }
1862                        (WrapperKind::OptionStdMutex, Some(inner_ty)) => {
1863                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1864                            tokens.extend(quote! {
1865                                #[inline(always)]
1866                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1867                                    rust_key_paths::Kp::new(
1868                                        |root: &#name| Some(&root.#field_ident),
1869                                        |root: &mut #name| Some(&mut root.#field_ident),
1870                                    )
1871                                }
1872                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
1873                                    rust_key_paths::Kp::new(
1874                                        |root: &#name| root.#field_ident.as_ref(),
1875                                        |root: &mut #name| root.#field_ident.as_mut(),
1876                                    )
1877                                }
1878                            });
1879                        }
1880                        (WrapperKind::OptionMutex, Some(inner_ty)) => {
1881                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1882                            tokens.extend(quote! {
1883                                #[inline(always)]
1884                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1885                                    rust_key_paths::Kp::new(
1886                                        |root: &#name| Some(&root.#field_ident),
1887                                        |root: &mut #name| Some(&mut root.#field_ident),
1888                                    )
1889                                }
1890                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, parking_lot::Mutex<#inner_ty>> {
1891                                    rust_key_paths::Kp::new(
1892                                        |root: &#name| root.#field_ident.as_ref(),
1893                                        |root: &mut #name| root.#field_ident.as_mut(),
1894                                    )
1895                                }
1896                            });
1897                        }
1898                        (WrapperKind::OptionStdRwLock, Some(inner_ty)) => {
1899                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1900                            tokens.extend(quote! {
1901                                #[inline(always)]
1902                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1903                                    rust_key_paths::Kp::new(
1904                                        |root: &#name| Some(&root.#field_ident),
1905                                        |root: &mut #name| Some(&mut root.#field_ident),
1906                                    )
1907                                }
1908                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
1909                                    rust_key_paths::Kp::new(
1910                                        |root: &#name| root.#field_ident.as_ref(),
1911                                        |root: &mut #name| root.#field_ident.as_mut(),
1912                                    )
1913                                }
1914                            });
1915                        }
1916                        (WrapperKind::OptionRwLock, Some(inner_ty)) => {
1917                            let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1918                            tokens.extend(quote! {
1919                                #[inline(always)]
1920                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1921                                    rust_key_paths::Kp::new(
1922                                        |root: &#name| Some(&root.#field_ident),
1923                                        |root: &mut #name| Some(&mut root.#field_ident),
1924                                    )
1925                                }
1926                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, parking_lot::RwLock<#inner_ty>> {
1927                                    rust_key_paths::Kp::new(
1928                                        |root: &#name| root.#field_ident.as_ref(),
1929                                        |root: &mut #name| root.#field_ident.as_mut(),
1930                                    )
1931                                }
1932                            });
1933                        }
1934                        (WrapperKind::Weak, Some(_inner_ty)) => {
1935                            // For Weak<T>, return keypath to container
1936                            tokens.extend(quote! {
1937                                #[inline(always)]
1938                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1939                                    rust_key_paths::Kp::new(
1940                                        |root: &#name| Some(&root.#field_ident),
1941                                        |_root: &mut #name| None, // Weak doesn't support mutable access
1942                                    )
1943                                }
1944                            });
1945                        }
1946                        (WrapperKind::Atomic, None | Some(_)) => {
1947                            // For atomic types: return keypath to the atomic (user calls .load()/.store())
1948                            tokens.extend(quote! {
1949                                #[inline(always)]
1950                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1951                                    rust_key_paths::Kp::new(
1952                                        |root: &#name| Some(&root.#field_ident),
1953                                        |root: &mut #name| Some(&mut root.#field_ident),
1954                                    )
1955                                }
1956                            });
1957                        }
1958                        (WrapperKind::OptionAtomic, Some(inner_ty)) => {
1959                            tokens.extend(quote! {
1960                                #[inline(always)]
1961                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #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::String, None) => {
1970                            tokens.extend(quote! {
1971                                #[inline(always)]
1972                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1973                                    rust_key_paths::Kp::new(
1974                                        |root: &#name| Some(&root.#field_ident),
1975                                        |root: &mut #name| Some(&mut root.#field_ident),
1976                                    )
1977                                }
1978                            });
1979                        }
1980                        (WrapperKind::OptionString, None) => {
1981                            tokens.extend(quote! {
1982                                #[inline(always)]
1983                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, std::string::String> {
1984                                    rust_key_paths::Kp::new(
1985                                        |root: &#name| root.#field_ident.as_ref(),
1986                                        |root: &mut #name| root.#field_ident.as_mut(),
1987                                    )
1988                                }
1989                            });
1990                        }
1991                        (WrapperKind::Cell, Some(_inner_ty)) => {
1992                            tokens.extend(quote! {
1993                                #[inline(always)]
1994                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1995                                    rust_key_paths::Kp::new(
1996                                        |root: &#name| Some(&root.#field_ident),
1997                                        |root: &mut #name| Some(&mut root.#field_ident),
1998                                    )
1999                                }
2000                            });
2001                        }
2002                        (WrapperKind::RefCell, Some(_inner_ty)) => {
2003                            tokens.extend(quote! {
2004                                #[inline(always)]
2005                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2006                                    rust_key_paths::Kp::new(
2007                                        |root: &#name| Some(&root.#field_ident),
2008                                        |root: &mut #name| Some(&mut root.#field_ident),
2009                                    )
2010                                }
2011                            });
2012                        }
2013                        (WrapperKind::OnceCell, Some(inner_ty)) => {
2014                            // OnceLock/OnceCell: keypath to inner value; get = .get() -> Option<&T>, set = None
2015                            tokens.extend(quote! {
2016                                #[inline(always)]
2017                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2018                                    rust_key_paths::Kp::new(
2019                                        |root: &#name| root.#field_ident.get(),
2020                                        |_root: &mut #name| None,
2021                                    )
2022                                }
2023                            });
2024                        }
2025                        (WrapperKind::Lazy, Some(inner_ty)) => {
2026                            // Lazy/LazyLock: keypath to inner value; get = .get() -> &T wrapped in Some, set = None
2027                            tokens.extend(quote! {
2028                                #[inline(always)]
2029                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2030                                    rust_key_paths::Kp::new(
2031                                        |root: &#name| Some(root.#field_ident.get()),
2032                                        |_root: &mut #name| None,
2033                                    )
2034                                }
2035                            });
2036                        }
2037                        (WrapperKind::PhantomData, 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::Range, Some(_inner_ty)) => {
2049                            tokens.extend(quote! {
2050                                #[inline(always)]
2051                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2052                                    rust_key_paths::Kp::new(
2053                                        |root: &#name| Some(&root.#field_ident),
2054                                        |root: &mut #name| Some(&mut root.#field_ident),
2055                                    )
2056                                }
2057                            });
2058                        }
2059                        (WrapperKind::OptionCell, Some(_inner_ty)) => {
2060                            tokens.extend(quote! {
2061                                #[inline(always)]
2062                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2063                                    rust_key_paths::Kp::new(
2064                                        |root: &#name| Some(&root.#field_ident),
2065                                        |root: &mut #name| Some(&mut root.#field_ident),
2066                                    )
2067                                }
2068                            });
2069                        }
2070                        (WrapperKind::OptionRefCell, Some(inner_ty)) => {
2071                            // Option<RefCell<T>>: keypath to T via borrow()/borrow_mut(); get returns Option<Ref<V>> so caller holds guard (deref for &V)
2072                            tokens.extend(quote! {
2073                                #[inline(always)]
2074                                pub fn #kp_fn() -> rust_key_paths::KpOptionRefCellType<'_, #name, #inner_ty> {
2075                                    rust_key_paths::Kp::new(
2076                                        |root: &#name| root.#field_ident.as_ref().map(|r| r.borrow()),
2077                                        |root: &mut #name| root.#field_ident.as_ref().map(|r| r.borrow_mut()),
2078                                    )
2079                                }
2080                            });
2081                        }
2082                        (WrapperKind::OptionOnceCell, Some(inner_ty)) => {
2083                            tokens.extend(quote! {
2084                                #[inline(always)]
2085                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2086                                    rust_key_paths::Kp::new(
2087                                        |root: &#name| root.#field_ident.as_ref().and_then(|c| c.get()),
2088                                        |_root: &mut #name| None,
2089                                    )
2090                                }
2091                            });
2092                        }
2093                        (WrapperKind::OptionLazy, Some(inner_ty)) => {
2094                            tokens.extend(quote! {
2095                                #[inline(always)]
2096                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2097                                    rust_key_paths::Kp::new(
2098                                        |root: &#name| root.#field_ident.as_ref().map(|c| c.get()),
2099                                        |_root: &mut #name| None,
2100                                    )
2101                                }
2102                            });
2103                        }
2104                        (WrapperKind::OptionPhantomData, Some(_inner_ty)) => {
2105                            tokens.extend(quote! {
2106                                #[inline(always)]
2107                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2108                                    rust_key_paths::Kp::new(
2109                                        |root: &#name| Some(&root.#field_ident),
2110                                        |root: &mut #name| Some(&mut root.#field_ident),
2111                                    )
2112                                }
2113                            });
2114                        }
2115                        (WrapperKind::OptionRange, Some(_inner_ty)) => {
2116                            tokens.extend(quote! {
2117                                #[inline(always)]
2118                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2119                                    rust_key_paths::Kp::new(
2120                                        |root: &#name| Some(&root.#field_ident),
2121                                        |root: &mut #name| Some(&mut root.#field_ident),
2122                                    )
2123                                }
2124                            });
2125                        }
2126                        (WrapperKind::Reference, Some(_inner_ty)) => {
2127                            // For reference types (&T, &str, &[T]): read-only, setter returns None
2128                            tokens.extend(quote! {
2129                                #[inline(always)]
2130                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2131                                    rust_key_paths::Kp::new(
2132                                        |root: &#name| Some(&root.#field_ident),
2133                                        |_root: &mut #name| None, // references: read-only
2134                                    )
2135                                }
2136                            });
2137                        }
2138                        (WrapperKind::None, None) => {
2139                            // For basic types, direct access
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                        _ => {
2151                            // For unknown/complex nested types, return keypath to field itself
2152                            tokens.extend(quote! {
2153                                #[inline(always)]
2154                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2155                            rust_key_paths::Kp::new(
2156                                |root: &#name| Some(&root.#field_ident),
2157                                |root: &mut #name| Some(&mut root.#field_ident),
2158                            )
2159                        }
2160                            });
2161                        }
2162                    }
2163                }
2164
2165                tokens
2166            }
2167            Fields::Unnamed(unnamed) => {
2168                let mut tokens = proc_macro2::TokenStream::new();
2169
2170                // Generate identity methods for the tuple struct
2171                tokens.extend(quote! {
2172                    /// Returns a generic identity keypath for this type
2173                    #[inline(always)]
2174                    pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
2175                        #name,
2176                        #name,
2177                        Root,
2178                        Root,
2179                        MutRoot,
2180                        MutRoot,
2181                        fn(Root) -> Option<Root>,
2182                        fn(MutRoot) -> Option<MutRoot>,
2183                    >
2184                    where
2185                        Root: std::borrow::Borrow<#name>,
2186                        MutRoot: std::borrow::BorrowMut<#name>,
2187                    {
2188                        rust_key_paths::Kp::new(
2189                            |r: Root| Some(r),
2190                            |r: MutRoot| Some(r)
2191                        )
2192                    }
2193
2194                    /// Returns a simple identity keypath for this type
2195                    #[inline(always)]
2196                    pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
2197                        rust_key_paths::Kp::new(
2198                            |r: &#name| Some(r),
2199                            |r: &mut #name| Some(r)
2200                        )
2201                    }
2202                });
2203
2204                for (idx, field) in unnamed.unnamed.iter().enumerate() {
2205                    let idx_lit = syn::Index::from(idx);
2206                    let ty = &field.ty;
2207                    // Centralized keypath method names for tuple fields – change here to adjust for all types
2208                    let kp_fn = format_ident!("f{}", idx);
2209                    let kp_at_fn = format_ident!("f{}_at", idx);
2210
2211                    let (kind, inner_ty) = extract_wrapper_inner_type(ty);
2212
2213                    match (kind, inner_ty.clone()) {
2214                        (WrapperKind::Option, Some(inner_ty)) => {
2215                            tokens.extend(quote! {
2216                                #[inline(always)]
2217                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2218                                    rust_key_paths::Kp::new(
2219                                        |root: &#name| root.#idx_lit.as_ref(),
2220                                        |root: &mut #name| root.#idx_lit.as_mut(),
2221                                    )
2222                                }
2223                            });
2224                        }
2225                        (WrapperKind::OptionBox, Some(inner_ty)) => {
2226                            tokens.extend(quote! {
2227                                #[inline(always)]
2228                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2229                                    rust_key_paths::Kp::new(
2230                                        |root: &#name| root.#idx_lit.as_deref(),
2231                                        |root: &mut #name| root.#idx_lit.as_deref_mut(),
2232                                    )
2233                                }
2234                            });
2235                        }
2236                        (WrapperKind::OptionRc, Some(inner_ty)) => {
2237                            tokens.extend(quote! {
2238                                #[inline(always)]
2239                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2240                                    rust_key_paths::Kp::new(
2241                                        |root: &#name| root.#idx_lit.as_deref(),
2242                                        |root: &mut #name| root.#idx_lit.as_mut().and_then(std::rc::Rc::get_mut),
2243                                    )
2244                                }
2245                            });
2246                        }
2247                        (WrapperKind::OptionArc, Some(inner_ty)) => {
2248                            tokens.extend(quote! {
2249                                #[inline(always)]
2250                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2251                                    rust_key_paths::Kp::new(
2252                                        |root: &#name| root.#idx_lit.as_deref(),
2253                                        |root: &mut #name| root.#idx_lit.as_mut().and_then(std::sync::Arc::get_mut),
2254                                    )
2255                                }
2256                            });
2257                        }
2258                        (WrapperKind::OptionHashMap, Some(inner_ty)) => {
2259                            if let Some((key_ty, _)) = extract_map_key_value_through_option(ty) {
2260                                let type_name = name.to_string();
2261                                let whole_fn = kp_fn.to_string();
2262                                let at_fn = kp_at_fn.to_string();
2263                                let whole_doc = format!(
2264                                    "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)`."
2265                                );
2266                                let at_doc = format!(
2267                                    "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."
2268                                );
2269                                tokens.extend(quote! {
2270                                    #[doc = #whole_doc]
2271                                    #[inline(always)]
2272                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2273                                        rust_key_paths::Kp::new(
2274                                            |root: &#name| Some(&root.#idx_lit),
2275                                            |root: &mut #name| Some(&mut root.#idx_lit),
2276                                        )
2277                                    }
2278                                    #[doc = #at_doc]
2279                                    #[inline(always)]
2280                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2281                                    where
2282                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
2283                                    {
2284                                        let key2 = key.clone();
2285                                        rust_key_paths::Kp::new(
2286                                            Box::new(move |root: &#name| root.#idx_lit.as_ref().and_then(|m| m.get(&key))),
2287                                            Box::new(move |root: &mut #name| root.#idx_lit.as_mut().and_then(|m| m.get_mut(&key2))),
2288                                        )
2289                                    }
2290                                });
2291                            } else {
2292                                tokens.extend(quote! {
2293                                    #[inline(always)]
2294                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2295                                        rust_key_paths::Kp::new(
2296                                            |root: &#name| Some(&root.#idx_lit),
2297                                            |root: &mut #name| Some(&mut root.#idx_lit),
2298                                        )
2299                                    }
2300                                });
2301                            }
2302                        }
2303                        (WrapperKind::OptionBTreeMap, Some(inner_ty)) => {
2304                            if let Some((key_ty, _)) = extract_map_key_value_through_option(ty) {
2305                                let type_name = name.to_string();
2306                                let whole_fn = kp_fn.to_string();
2307                                let at_fn = kp_at_fn.to_string();
2308                                let whole_doc = format!(
2309                                    "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)`."
2310                                );
2311                                let at_doc = format!(
2312                                    "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."
2313                                );
2314                                tokens.extend(quote! {
2315                                    #[doc = #whole_doc]
2316                                    #[inline(always)]
2317                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2318                                        rust_key_paths::Kp::new(
2319                                            |root: &#name| Some(&root.#idx_lit),
2320                                            |root: &mut #name| Some(&mut root.#idx_lit),
2321                                        )
2322                                    }
2323                                    #[doc = #at_doc]
2324                                    #[inline(always)]
2325                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2326                                    where
2327                                        #key_ty: Clone + Ord + 'static,
2328                                    {
2329                                        let key2 = key.clone();
2330                                        rust_key_paths::Kp::new(
2331                                            Box::new(move |root: &#name| root.#idx_lit.as_ref().and_then(|m| m.get(&key))),
2332                                            Box::new(move |root: &mut #name| root.#idx_lit.as_mut().and_then(|m| m.get_mut(&key2))),
2333                                        )
2334                                    }
2335                                });
2336                            } else {
2337                                tokens.extend(quote! {
2338                                    #[inline(always)]
2339                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2340                                        rust_key_paths::Kp::new(
2341                                            |root: &#name| Some(&root.#idx_lit),
2342                                            |root: &mut #name| Some(&mut root.#idx_lit),
2343                                        )
2344                                    }
2345                                });
2346                            }
2347                        }
2348                        (WrapperKind::OptionHashSet, Some(inner_ty)) => {
2349                            tokens.extend(quote! {
2350                                #[inline(always)]
2351                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2352                                    rust_key_paths::Kp::new(
2353                                        |root: &#name| Some(&root.#idx_lit),
2354                                        |root: &mut #name| Some(&mut root.#idx_lit),
2355                                    )
2356                                }
2357
2358                                /// _at: check if element exists and get reference.
2359                                /// HashSet does not allow mutable element access (would break hash invariant).
2360                                #[inline(always)]
2361                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2362                                where
2363                                    #inner_ty: Clone + std::hash::Hash + Eq + 'static,
2364                                {
2365                                    rust_key_paths::Kp::new(
2366                                        Box::new(move |root: &#name| root.#idx_lit.as_ref().and_then(|s| s.get(&key))),
2367                                        Box::new(move |_root: &mut #name| None),
2368                                    )
2369                                }
2370                            });
2371                        }
2372                        (WrapperKind::OptionBTreeSet, Some(inner_ty)) => {
2373                            tokens.extend(quote! {
2374                                #[inline(always)]
2375                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2376                                    rust_key_paths::Kp::new(
2377                                        |root: &#name| Some(&root.#idx_lit),
2378                                        |root: &mut #name| Some(&mut root.#idx_lit),
2379                                    )
2380                                }
2381
2382                                /// _at: check if element exists and get reference.
2383                                /// BTreeSet does not allow mutable element access (would break ordering invariant).
2384                                #[inline(always)]
2385                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2386                                where
2387                                    #inner_ty: Clone + Ord + 'static,
2388                                {
2389                                    rust_key_paths::Kp::new(
2390                                        Box::new(move |root: &#name| root.#idx_lit.as_ref().and_then(|s| s.get(&key))),
2391                                        Box::new(move |_root: &mut #name| None),
2392                                    )
2393                                }
2394                            });
2395                        }
2396                        (WrapperKind::OptionVecDeque, Some(_inner_ty))
2397                        | (WrapperKind::OptionLinkedList, Some(_inner_ty))
2398                        | (WrapperKind::OptionBinaryHeap, Some(_inner_ty))
2399                        | (WrapperKind::OptionResult, Some(_inner_ty)) => {
2400                            tokens.extend(quote! {
2401                                #[inline(always)]
2402                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2403                                    rust_key_paths::Kp::new(
2404                                        |root: &#name| Some(&root.#idx_lit),
2405                                        |root: &mut #name| Some(&mut root.#idx_lit),
2406                                    )
2407                                }
2408                            });
2409                        }
2410                        (WrapperKind::Vec, Some(inner_ty)) => {
2411                            tokens.extend(quote! {
2412                                #[inline(always)]
2413                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2414                                    rust_key_paths::Kp::new(
2415                                        |root: &#name| Some(&root.#idx_lit),
2416                                        |root: &mut #name| Some(&mut root.#idx_lit),
2417                                    )
2418                                }
2419                                #[inline(always)]
2420                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
2421                                    rust_key_paths::Kp::new(
2422                                        Box::new(move |root: &#name| root.#idx_lit.get(index)),
2423                                        Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
2424                                    )
2425                                }
2426                            });
2427                        }
2428                        (WrapperKind::HashMap, Some(inner_ty)) => {
2429                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
2430                                tokens.extend(quote! {
2431                                    #[inline(always)]
2432                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2433                                        rust_key_paths::Kp::new(
2434                                            |root: &#name| Some(&root.#idx_lit),
2435                                            |root: &mut #name| Some(&mut root.#idx_lit),
2436                                        )
2437                                    }
2438                                    #[inline(always)]
2439                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2440                                    where
2441                                        #key_ty: Clone + std::hash::Hash + Eq + 'static,
2442                                    {
2443                                        let key2 = key.clone();
2444                                        rust_key_paths::Kp::new(
2445                                            Box::new(move |root: &#name| root.#idx_lit.get(&key)),
2446                                            Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
2447                                        )
2448                                    }
2449                                });
2450                            } else {
2451                                tokens.extend(quote! {
2452                                    #[inline(always)]
2453                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2454                                        rust_key_paths::Kp::new(
2455                                            |root: &#name| Some(&root.#idx_lit),
2456                                            |root: &mut #name| Some(&mut root.#idx_lit),
2457                                        )
2458                                    }
2459                                });
2460                            }
2461                        }
2462                        (WrapperKind::BTreeMap, Some(inner_ty))
2463                        | (WrapperKind::BTreeMapOption, Some(inner_ty)) => {
2464                            if let Some((key_ty, _)) = extract_map_key_value(ty) {
2465                                tokens.extend(quote! {
2466                                    #[inline(always)]
2467                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2468                                        rust_key_paths::Kp::new(
2469                                            |root: &#name| Some(&root.#idx_lit),
2470                                            |root: &mut #name| Some(&mut root.#idx_lit),
2471                                        )
2472                                    }
2473                                    #[inline(always)]
2474                                    pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2475                                    where
2476                                        #key_ty: Clone + Ord + 'static,
2477                                    {
2478                                        let key2 = key.clone();
2479                                        rust_key_paths::Kp::new(
2480                                            Box::new(move |root: &#name| root.#idx_lit.get(&key)),
2481                                            Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
2482                                        )
2483                                    }
2484                                });
2485                            } else {
2486                                tokens.extend(quote! {
2487                                    #[inline(always)]
2488                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2489                                        rust_key_paths::Kp::new(
2490                                            |root: &#name| Some(&root.#idx_lit),
2491                                            |root: &mut #name| Some(&mut root.#idx_lit),
2492                                        )
2493                                    }
2494                                });
2495                            }
2496                        }
2497                        (WrapperKind::Box, Some(inner_ty)) => {
2498                            // Box: deref to inner (returns &T / &mut T)
2499                            tokens.extend(quote! {
2500                                #[inline(always)]
2501                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2502                                    rust_key_paths::Kp::new(
2503                                        |root: &#name| Some(&*root.#idx_lit),
2504                                        |root: &mut #name| Some(&mut *root.#idx_lit),
2505                                    )
2506                                }
2507                            });
2508                        }
2509                        (WrapperKind::BoxOption, Some(inner_ty)) => {
2510                            tokens.extend(quote! {
2511                                #[inline(always)]
2512                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2513                                    rust_key_paths::Kp::new(
2514                                        |root: &#name| (&*root.#idx_lit).as_ref(),
2515                                        |root: &mut #name| (&mut *root.#idx_lit).as_mut(),
2516                                    )
2517                                }
2518                            });
2519                        }
2520                        (WrapperKind::RcOption, Some(inner_ty)) => {
2521                            tokens.extend(quote! {
2522                                #[inline(always)]
2523                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2524                                    rust_key_paths::Kp::new(
2525                                        |root: &#name| (&*root.#idx_lit).as_ref(),
2526                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#idx_lit).and_then(std::option::Option::as_mut),
2527                                    )
2528                                }
2529                            });
2530                        }
2531                        (WrapperKind::ArcOption, Some(inner_ty)) => {
2532                            tokens.extend(quote! {
2533                                #[inline(always)]
2534                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2535                                    rust_key_paths::Kp::new(
2536                                        |root: &#name| (&*root.#idx_lit).as_ref(),
2537                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#idx_lit).and_then(std::option::Option::as_mut),
2538                                    )
2539                                }
2540                            });
2541                        }
2542                        (WrapperKind::Pin, Some(inner_ty)) => {
2543                            let kp_inner_fn = format_ident!("{}_inner", kp_fn);
2544                            tokens.extend(quote! {
2545                                #[inline(always)]
2546                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2547                                    rust_key_paths::Kp::new(
2548                                        |root: &#name| Some(&root.#idx_lit),
2549                                        |root: &mut #name| Some(&mut root.#idx_lit),
2550                                    )
2551                                }
2552                                #[inline(always)]
2553                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2554                                where #inner_ty: std::marker::Unpin
2555                                {
2556                                    rust_key_paths::Kp::new(
2557                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#idx_lit).get_ref()),
2558                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#idx_lit).get_mut()),
2559                                    )
2560                                }
2561                            });
2562                        }
2563                        (WrapperKind::PinBox, Some(inner_ty)) => {
2564                            let kp_inner_fn = format_ident!("{}_inner", kp_fn);
2565                            tokens.extend(quote! {
2566                                #[inline(always)]
2567                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2568                                    rust_key_paths::Kp::new(
2569                                        |root: &#name| Some(&root.#idx_lit),
2570                                        |root: &mut #name| Some(&mut root.#idx_lit),
2571                                    )
2572                                }
2573                                #[inline(always)]
2574                                pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2575                                where #inner_ty: std::marker::Unpin
2576                                {
2577                                    rust_key_paths::Kp::new(
2578                                        |root: &#name| Some(std::pin::Pin::as_ref(&root.#idx_lit).get_ref()),
2579                                        |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#idx_lit).get_mut()),
2580                                    )
2581                                }
2582                            });
2583                        }
2584                        (WrapperKind::Rc, Some(inner_ty)) => {
2585                            tokens.extend(quote! {
2586                                #[inline(always)]
2587                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2588                                    rust_key_paths::Kp::new(
2589                                        |root: &#name| Some(root.#idx_lit.as_ref()),
2590                                        |root: &mut #name| std::rc::Rc::get_mut(&mut root.#idx_lit),
2591                                    )
2592                                }
2593                            });
2594                        }
2595                        (WrapperKind::Arc, Some(inner_ty)) => {
2596                            tokens.extend(quote! {
2597                                #[inline(always)]
2598                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2599                                    rust_key_paths::Kp::new(
2600                                        |root: &#name| Some(root.#idx_lit.as_ref()),
2601                                        |root: &mut #name| std::sync::Arc::get_mut(&mut root.#idx_lit),
2602                                    )
2603                                }
2604                            });
2605                        }
2606
2607                        (WrapperKind::Cow, Some(inner_ty)) => {
2608                            tokens.extend(quote! {
2609                                #[inline(always)]
2610                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2611                                    rust_key_paths::Kp::new(
2612                                        |root: &#name| Some(root.#idx_lit.as_ref()),
2613                                        |root: &mut #name| Some(root.#idx_lit.to_mut()),
2614                                    )
2615                                }
2616                            });
2617                        }
2618
2619                        (WrapperKind::OptionCow, Some(inner_ty)) => {
2620                            tokens.extend(quote! {
2621                                #[inline(always)]
2622                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2623                                    rust_key_paths::Kp::new(
2624                                        |root: &#name| root.#idx_lit.as_ref().map(|c| c.as_ref()),
2625                                        |root: &mut #name| root.#idx_lit.as_mut().map(|c| c.to_mut()),
2626                                    )
2627                                }
2628                            });
2629                        }
2630                        (WrapperKind::OptionTagged, Some(inner_ty)) => {
2631                            tokens.extend(quote! {
2632                                #[inline(always)]
2633                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2634                                    rust_key_paths::Kp::new(
2635                                        |root: &#name| root.#idx_lit.as_ref().map(|t| std::ops::Deref::deref(t)),
2636                                        |root: &mut #name| root.#idx_lit.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
2637                                    )
2638                                }
2639                            });
2640                        }
2641                        (WrapperKind::OptionReference, Some(inner_ty)) => {
2642                            tokens.extend(quote! {
2643                                #[inline(always)]
2644                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2645                                    rust_key_paths::Kp::new(
2646                                        |root: &#name| root.#idx_lit.as_ref(),
2647                                        |_root: &mut #name| None,
2648                                    )
2649                                }
2650                            });
2651                        }
2652                        (WrapperKind::HashSet, Some(inner_ty))
2653                        | (WrapperKind::HashSetOption, Some(inner_ty)) => {
2654                            let kp_at_fn = format_ident!("f{}_at", idx);
2655
2656                            tokens.extend(quote! {
2657                                #[inline(always)]
2658                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2659                                    rust_key_paths::Kp::new(
2660                                        |root: &#name| Some(&root.#idx_lit),
2661                                        |root: &mut #name| Some(&mut root.#idx_lit),
2662                                    )
2663                                }
2664
2665                                /// _at: check if element exists and get reference.
2666                                /// HashSet does not allow mutable element access (would break hash invariant).
2667                                #[inline(always)]
2668                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2669                                where
2670                                    #inner_ty: Clone + std::hash::Hash + Eq + 'static,
2671                                {
2672                                    rust_key_paths::Kp::new(
2673                                        Box::new(move |root: &#name| root.#idx_lit.get(&key)),
2674                                        Box::new(move |_root: &mut #name| None),
2675                                    )
2676                                }
2677                            });
2678                        }
2679                        (WrapperKind::BTreeSet, Some(inner_ty))
2680                        | (WrapperKind::BTreeSetOption, Some(inner_ty)) => {
2681                            let kp_at_fn = format_ident!("f{}_at", idx);
2682
2683                            tokens.extend(quote! {
2684                                #[inline(always)]
2685                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2686                                    rust_key_paths::Kp::new(
2687                                        |root: &#name| Some(&root.#idx_lit),
2688                                        |root: &mut #name| Some(&mut root.#idx_lit),
2689                                    )
2690                                }
2691
2692                                /// _at: check if element exists and get reference.
2693                                /// BTreeSet does not allow mutable element access (would break ordering invariant).
2694                                #[inline(always)]
2695                                pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2696                                where
2697                                    #inner_ty: Clone + Ord + 'static,
2698                                {
2699                                    rust_key_paths::Kp::new(
2700                                        Box::new(move |root: &#name| root.#idx_lit.get(&key)),
2701                                        Box::new(move |_root: &mut #name| None),
2702                                    )
2703                                }
2704                            });
2705                        }
2706                        (WrapperKind::VecDeque, Some(inner_ty))
2707                        | (WrapperKind::VecDequeOption, Some(inner_ty)) => {
2708                            tokens.extend(quote! {
2709                                #[inline(always)]
2710                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2711                                    rust_key_paths::Kp::new(
2712                                        |root: &#name| Some(&root.#idx_lit),
2713                                        |root: &mut #name| Some(&mut root.#idx_lit),
2714                                    )
2715                                }
2716                                #[inline(always)]
2717                                pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
2718                                    rust_key_paths::Kp::new(
2719                                        Box::new(move |root: &#name| root.#idx_lit.get(index)),
2720                                        Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
2721                                    )
2722                                }
2723                            });
2724                        }
2725                        (WrapperKind::LinkedList, Some(_inner_ty))
2726                        | (WrapperKind::LinkedListOption, Some(_inner_ty)) => {
2727                            tokens.extend(quote! {
2728                                #[inline(always)]
2729                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2730                                    rust_key_paths::Kp::new(
2731                                        |root: &#name| Some(&root.#idx_lit),
2732                                        |root: &mut #name| Some(&mut root.#idx_lit),
2733                                    )
2734                                }
2735                            });
2736                        }
2737                        (WrapperKind::BinaryHeap, Some(_inner_ty))
2738                        | (WrapperKind::BinaryHeapOption, Some(_inner_ty)) => {
2739                            tokens.extend(quote! {
2740                                #[inline(always)]
2741                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2742                                    rust_key_paths::Kp::new(
2743                                        |root: &#name| Some(&root.#idx_lit),
2744                                        |root: &mut #name| Some(&mut root.#idx_lit),
2745                                    )
2746                                }
2747                            });
2748                        }
2749                        (WrapperKind::Result, Some(inner_ty)) => {
2750                            tokens.extend(quote! {
2751                                #[inline(always)]
2752                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2753                                    rust_key_paths::Kp::new(
2754                                        |root: &#name| root.#idx_lit.as_ref().ok(),
2755                                        |root: &mut #name| root.#idx_lit.as_mut().ok(),
2756                                    )
2757                                }
2758                            });
2759                        }
2760                        (WrapperKind::Mutex, Some(_inner_ty))
2761                        | (WrapperKind::StdMutex, Some(_inner_ty)) => {
2762                            tokens.extend(quote! {
2763                                #[inline(always)]
2764                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2765                                    rust_key_paths::Kp::new(
2766                                        |root: &#name| Some(&root.#idx_lit),
2767                                        |root: &mut #name| Some(&mut root.#idx_lit),
2768                                    )
2769                                }
2770                            });
2771                        }
2772                        (WrapperKind::RwLock, Some(_inner_ty))
2773                        | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
2774                            tokens.extend(quote! {
2775                                #[inline(always)]
2776                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2777                                    rust_key_paths::Kp::new(
2778                                        |root: &#name| Some(&root.#idx_lit),
2779                                        |root: &mut #name| Some(&mut root.#idx_lit),
2780                                    )
2781                                }
2782                            });
2783                        }
2784                        (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
2785                            let kp_async_fn = format_ident!("f{}_kp", idx);
2786                            tokens.extend(quote! {
2787                                #[inline(always)]
2788                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2789                                    rust_key_paths::Kp::new(
2790                                        |root: &#name| Some(&root.#idx_lit),
2791                                        |root: &mut #name| Some(&mut root.#idx_lit),
2792                                    )
2793                                }
2794                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
2795                                    rust_key_paths::async_lock::AsyncLockKp::new(
2796                                        rust_key_paths::Kp::new(
2797                                            |root: &#name| Some(&root.#idx_lit),
2798                                            |root: &mut #name| Some(&mut root.#idx_lit),
2799                                        ),
2800                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
2801                                        rust_key_paths::Kp::new(
2802                                            |v: &#inner_ty| Some(v),
2803                                            |v: &mut #inner_ty| Some(v),
2804                                        ),
2805                                    )
2806                                }
2807                            });
2808                        }
2809                        (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
2810                            let kp_async_fn = format_ident!("f{}_kp", idx);
2811                            tokens.extend(quote! {
2812                                #[inline(always)]
2813                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2814                                    rust_key_paths::Kp::new(
2815                                        |root: &#name| Some(&root.#idx_lit),
2816                                        |root: &mut #name| Some(&mut root.#idx_lit),
2817                                    )
2818                                }
2819                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
2820                                    rust_key_paths::async_lock::AsyncLockKp::new(
2821                                        rust_key_paths::Kp::new(
2822                                            |root: &#name| Some(&root.#idx_lit),
2823                                            |root: &mut #name| Some(&mut root.#idx_lit),
2824                                        ),
2825                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
2826                                        rust_key_paths::Kp::new(
2827                                            |v: &#inner_ty| Some(v),
2828                                            |v: &mut #inner_ty| Some(v),
2829                                        ),
2830                                    )
2831                                }
2832                            });
2833                        }
2834                        (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
2835                            let kp_async_fn = format_ident!("f{}_kp", idx);
2836                            tokens.extend(quote! {
2837                                #[inline(always)]
2838                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2839                                    rust_key_paths::Kp::new(
2840                                        |root: &#name| Some(&root.#idx_lit),
2841                                        |root: &mut #name| Some(&mut root.#idx_lit),
2842                                    )
2843                                }
2844                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
2845                                    rust_key_paths::async_lock::AsyncLockKp::new(
2846                                        rust_key_paths::Kp::new(
2847                                            |root: &#name| root.#idx_lit.as_ref(),
2848                                            |root: &mut #name| root.#idx_lit.as_mut(),
2849                                        ),
2850                                        rust_key_paths::async_lock::TokioMutexAccess::new(),
2851                                        rust_key_paths::Kp::new(
2852                                            |v: &#inner_ty| Some(v),
2853                                            |v: &mut #inner_ty| Some(v),
2854                                        ),
2855                                    )
2856                                }
2857                            });
2858                        }
2859                        (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
2860                            let kp_async_fn = format_ident!("f{}_kp", idx);
2861                            tokens.extend(quote! {
2862                                #[inline(always)]
2863                                    pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2864                                    rust_key_paths::Kp::new(
2865                                        |root: &#name| Some(&root.#idx_lit),
2866                                        |root: &mut #name| Some(&mut root.#idx_lit),
2867                                    )
2868                                }
2869                                pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
2870                                    rust_key_paths::async_lock::AsyncLockKp::new(
2871                                        rust_key_paths::Kp::new(
2872                                            |root: &#name| root.#idx_lit.as_ref(),
2873                                            |root: &mut #name| root.#idx_lit.as_mut(),
2874                                        ),
2875                                        rust_key_paths::async_lock::TokioRwLockAccess::new(),
2876                                        rust_key_paths::Kp::new(
2877                                            |v: &#inner_ty| Some(v),
2878                                            |v: &mut #inner_ty| Some(v),
2879                                        ),
2880                                    )
2881                                }
2882                            });
2883                        }
2884                        (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
2885                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2886                            tokens.extend(quote! {
2887                                #[inline(always)]
2888                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2889                                    rust_key_paths::Kp::new(
2890                                        |root: &#name| Some(&root.#idx_lit),
2891                                        |root: &mut #name| Some(&mut root.#idx_lit),
2892                                    )
2893                                }
2894                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
2895                                    rust_key_paths::Kp::new(
2896                                        |root: &#name| root.#idx_lit.as_ref(),
2897                                        |root: &mut #name| root.#idx_lit.as_mut(),
2898                                    )
2899                                }
2900                            });
2901                        }
2902                        (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
2903                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2904                            tokens.extend(quote! {
2905                                #[inline(always)]
2906                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2907                                    rust_key_paths::Kp::new(
2908                                        |root: &#name| Some(&root.#idx_lit),
2909                                        |root: &mut #name| Some(&mut root.#idx_lit),
2910                                    )
2911                                }
2912                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
2913                                    rust_key_paths::Kp::new(
2914                                        |root: &#name| root.#idx_lit.as_ref(),
2915                                        |root: &mut #name| root.#idx_lit.as_mut(),
2916                                    )
2917                                }
2918                            });
2919                        }
2920                        (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
2921                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2922                            tokens.extend(quote! {
2923                                #[inline(always)]
2924                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2925                                    rust_key_paths::Kp::new(
2926                                        |root: &#name| Some(&root.#idx_lit),
2927                                        |root: &mut #name| Some(&mut root.#idx_lit),
2928                                    )
2929                                }
2930                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
2931                                    rust_key_paths::Kp::new(
2932                                        |root: &#name| root.#idx_lit.as_ref(),
2933                                        |root: &mut #name| root.#idx_lit.as_mut(),
2934                                    )
2935                                }
2936                            });
2937                        }
2938                        (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
2939                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2940                            tokens.extend(quote! {
2941                                #[inline(always)]
2942                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2943                                    rust_key_paths::Kp::new(
2944                                        |root: &#name| Some(&root.#idx_lit),
2945                                        |root: &mut #name| Some(&mut root.#idx_lit),
2946                                    )
2947                                }
2948                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
2949                                    rust_key_paths::Kp::new(
2950                                        |root: &#name| root.#idx_lit.as_ref(),
2951                                        |root: &mut #name| root.#idx_lit.as_mut(),
2952                                    )
2953                                }
2954                            });
2955                        }
2956                        (WrapperKind::OptionStdMutex, Some(inner_ty)) => {
2957                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2958                            tokens.extend(quote! {
2959                                #[inline(always)]
2960                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2961                                    rust_key_paths::Kp::new(
2962                                        |root: &#name| Some(&root.#idx_lit),
2963                                        |root: &mut #name| Some(&mut root.#idx_lit),
2964                                    )
2965                                }
2966                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
2967                                    rust_key_paths::Kp::new(
2968                                        |root: &#name| root.#idx_lit.as_ref(),
2969                                        |root: &mut #name| root.#idx_lit.as_mut(),
2970                                    )
2971                                }
2972                            });
2973                        }
2974                        (WrapperKind::OptionMutex, Some(inner_ty)) => {
2975                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2976                            tokens.extend(quote! {
2977                                #[inline(always)]
2978                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2979                                    rust_key_paths::Kp::new(
2980                                        |root: &#name| Some(&root.#idx_lit),
2981                                        |root: &mut #name| Some(&mut root.#idx_lit),
2982                                    )
2983                                }
2984                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, parking_lot::Mutex<#inner_ty>> {
2985                                    rust_key_paths::Kp::new(
2986                                        |root: &#name| root.#idx_lit.as_ref(),
2987                                        |root: &mut #name| root.#idx_lit.as_mut(),
2988                                    )
2989                                }
2990                            });
2991                        }
2992                        (WrapperKind::OptionStdRwLock, Some(inner_ty)) => {
2993                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2994                            tokens.extend(quote! {
2995                                #[inline(always)]
2996                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2997                                    rust_key_paths::Kp::new(
2998                                        |root: &#name| Some(&root.#idx_lit),
2999                                        |root: &mut #name| Some(&mut root.#idx_lit),
3000                                    )
3001                                }
3002                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
3003                                    rust_key_paths::Kp::new(
3004                                        |root: &#name| root.#idx_lit.as_ref(),
3005                                        |root: &mut #name| root.#idx_lit.as_mut(),
3006                                    )
3007                                }
3008                            });
3009                        }
3010                        (WrapperKind::OptionRwLock, Some(inner_ty)) => {
3011                            let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
3012                            tokens.extend(quote! {
3013                                #[inline(always)]
3014                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3015                                    rust_key_paths::Kp::new(
3016                                        |root: &#name| Some(&root.#idx_lit),
3017                                        |root: &mut #name| Some(&mut root.#idx_lit),
3018                                    )
3019                                }
3020                                pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, parking_lot::RwLock<#inner_ty>> {
3021                                    rust_key_paths::Kp::new(
3022                                        |root: &#name| root.#idx_lit.as_ref(),
3023                                        |root: &mut #name| root.#idx_lit.as_mut(),
3024                                    )
3025                                }
3026                            });
3027                        }
3028                        (WrapperKind::Weak, Some(_inner_ty)) => {
3029                            tokens.extend(quote! {
3030                                #[inline(always)]
3031                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3032                                    rust_key_paths::Kp::new(
3033                                        |root: &#name| Some(&root.#idx_lit),
3034                                        |_root: &mut #name| None,
3035                                    )
3036                                }
3037                            });
3038                        }
3039                        (WrapperKind::Atomic, None | Some(_)) => {
3040                            tokens.extend(quote! {
3041                                #[inline(always)]
3042                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3043                                    rust_key_paths::Kp::new(
3044                                        |root: &#name| Some(&root.#idx_lit),
3045                                        |root: &mut #name| Some(&mut root.#idx_lit),
3046                                    )
3047                                }
3048                            });
3049                        }
3050                        (WrapperKind::OptionAtomic, Some(inner_ty)) => {
3051                            tokens.extend(quote! {
3052                                #[inline(always)]
3053                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3054                                    rust_key_paths::Kp::new(
3055                                        |root: &#name| root.#idx_lit.as_ref(),
3056                                        |root: &mut #name| root.#idx_lit.as_mut(),
3057                                    )
3058                                }
3059                            });
3060                        }
3061                        (WrapperKind::String, None) => {
3062                            tokens.extend(quote! {
3063                                #[inline(always)]
3064                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3065                                    rust_key_paths::Kp::new(
3066                                        |root: &#name| Some(&root.#idx_lit),
3067                                        |root: &mut #name| Some(&mut root.#idx_lit),
3068                                    )
3069                                }
3070                            });
3071                        }
3072                        (WrapperKind::OptionString, None) => {
3073                            tokens.extend(quote! {
3074                                #[inline(always)]
3075                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, std::string::String> {
3076                                    rust_key_paths::Kp::new(
3077                                        |root: &#name| root.#idx_lit.as_ref(),
3078                                        |root: &mut #name| root.#idx_lit.as_mut(),
3079                                    )
3080                                }
3081                            });
3082                        }
3083                        (WrapperKind::OnceCell, Some(inner_ty)) => {
3084                            tokens.extend(quote! {
3085                                #[inline(always)]
3086                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3087                                    rust_key_paths::Kp::new(
3088                                        |root: &#name| root.#idx_lit.get(),
3089                                        |_root: &mut #name| None,
3090                                    )
3091                                }
3092                            });
3093                        }
3094                        (WrapperKind::Lazy, Some(inner_ty)) => {
3095                            tokens.extend(quote! {
3096                                #[inline(always)]
3097                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3098                                    rust_key_paths::Kp::new(
3099                                        |root: &#name| Some(root.#idx_lit.get()),
3100                                        |_root: &mut #name| None,
3101                                    )
3102                                }
3103                            });
3104                        }
3105                        (WrapperKind::OptionOnceCell, Some(inner_ty)) => {
3106                            tokens.extend(quote! {
3107                                #[inline(always)]
3108                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3109                                    rust_key_paths::Kp::new(
3110                                        |root: &#name| root.#idx_lit.as_ref().and_then(|c| c.get()),
3111                                        |_root: &mut #name| None,
3112                                    )
3113                                }
3114                            });
3115                        }
3116                        (WrapperKind::OptionLazy, Some(inner_ty)) => {
3117                            tokens.extend(quote! {
3118                                #[inline(always)]
3119                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3120                                    rust_key_paths::Kp::new(
3121                                        |root: &#name| root.#idx_lit.as_ref().map(|c| c.get()),
3122                                        |_root: &mut #name| None,
3123                                    )
3124                                }
3125                            });
3126                        }
3127                        (WrapperKind::Cell, Some(_inner_ty))
3128                        | (WrapperKind::RefCell, Some(_inner_ty))
3129                        | (WrapperKind::PhantomData, Some(_inner_ty))
3130                        | (WrapperKind::Range, Some(_inner_ty))
3131                        | (WrapperKind::OptionCell, Some(_inner_ty))
3132                        | (WrapperKind::OptionPhantomData, Some(_inner_ty))
3133                        | (WrapperKind::OptionRange, Some(_inner_ty)) => {
3134                            tokens.extend(quote! {
3135                                #[inline(always)]
3136                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3137                                    rust_key_paths::Kp::new(
3138                                        |root: &#name| Some(&root.#idx_lit),
3139                                        |root: &mut #name| Some(&mut root.#idx_lit),
3140                                    )
3141                                }
3142                            });
3143                        }
3144                        (WrapperKind::OptionRefCell, Some(inner_ty)) => {
3145                            tokens.extend(quote! {
3146                                #[inline(always)]
3147                                pub fn #kp_fn() -> rust_key_paths::KpOptionRefCellType<'_, #name, #inner_ty> {
3148                                    rust_key_paths::Kp::new(
3149                                        |root: &#name| root.#idx_lit.as_ref().map(|r| r.borrow()),
3150                                        |root: &mut #name| root.#idx_lit.as_ref().map(|r| r.borrow_mut()),
3151                                    )
3152                                }
3153                            });
3154                        }
3155                        (WrapperKind::Reference, Some(_inner_ty)) => {
3156                            tokens.extend(quote! {
3157                                #[inline(always)]
3158                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3159                                    rust_key_paths::Kp::new(
3160                                        |root: &#name| Some(&root.#idx_lit),
3161                                        |_root: &mut #name| None,
3162                                    )
3163                                }
3164                            });
3165                        }
3166                        (WrapperKind::None, None) => {
3167                            tokens.extend(quote! {
3168                                #[inline(always)]
3169                                pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3170                                    rust_key_paths::Kp::new(
3171                                        |root: &#name| Some(&root.#idx_lit),
3172                                        |root: &mut #name| Some(&mut root.#idx_lit),
3173                                    )
3174                                }
3175                            });
3176                        }
3177                        _ => {
3178                            tokens.extend(quote! {
3179                                #[inline(always)]
3180                                    pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
3181                                    rust_key_paths::Kp::new(
3182                                        |root: &#name| Some(&root.#idx_lit),
3183                                        |root: &mut #name| Some(&mut root.#idx_lit),
3184                                    )
3185                                }
3186                            });
3187                        }
3188                    }
3189                }
3190
3191                tokens
3192            }
3193            Fields::Unit => {
3194                return syn::Error::new(input_span, "Kp derive does not support unit structs")
3195                    .to_compile_error()
3196                    .into();
3197            }
3198        },
3199        Data::Enum(data_enum) => {
3200            let mut tokens = proc_macro2::TokenStream::new();
3201
3202            // Generate identity methods for the enum
3203            tokens.extend(quote! {
3204                /// Returns a generic identity keypath for this type
3205                #[inline(always)]
3206                pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
3207                    #name,
3208                    #name,
3209                    Root,
3210                    Root,
3211                    MutRoot,
3212                    MutRoot,
3213                    fn(Root) -> Option<Root>,
3214                    fn(MutRoot) -> Option<MutRoot>,
3215                >
3216                where
3217                    Root: std::borrow::Borrow<#name>,
3218                    MutRoot: std::borrow::BorrowMut<#name>,
3219                {
3220                    rust_key_paths::Kp::new(
3221                        |r: Root| Some(r),
3222                        |r: MutRoot| Some(r)
3223                    )
3224                }
3225
3226                /// Returns a simple identity keypath for this type
3227                #[inline(always)]
3228                pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
3229                    rust_key_paths::Kp::new(
3230                        |r: &#name| Some(r),
3231                        |r: &mut #name| Some(r)
3232                    )
3233                }
3234            });
3235
3236            for variant in data_enum.variants.iter() {
3237                let v_ident = &variant.ident;
3238                let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
3239
3240                match &variant.fields {
3241                    Fields::Unit => {
3242                        // Unit variant - return keypath that checks if enum matches variant
3243                        tokens.extend(quote! {
3244                            #[inline(always)]
3245                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, ()> {
3246                                rust_key_paths::Kp::new(
3247                                    |root: &#name| match root {
3248                                        #name::#v_ident => {
3249                                            static UNIT: () = ();
3250                                            Some(&UNIT)
3251                                        },
3252                                        _ => None,
3253                                    },
3254                                    |_root: &mut #name| None, // Can't mutate unit variant
3255                                )
3256                            }
3257                        });
3258                    }
3259                    Fields::Unnamed(unnamed) => {
3260                        if unnamed.unnamed.len() == 1 {
3261                            // Single-field tuple variant
3262                            let field_ty = &unnamed.unnamed[0].ty;
3263                            let (kind, inner_ty) = extract_wrapper_inner_type(field_ty);
3264
3265                            match (kind, inner_ty.clone()) {
3266                                (WrapperKind::Option, Some(inner_ty)) => {
3267                                    tokens.extend(quote! {
3268                                        #[inline(always)]
3269                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3270                                            rust_key_paths::Kp::new(
3271                                                |root: &#name| match root {
3272                                                    #name::#v_ident(inner) => inner.as_ref(),
3273                                                    _ => None,
3274                                                },
3275                                                |root: &mut #name| match root {
3276                                                    #name::#v_ident(inner) => inner.as_mut(),
3277                                                    _ => None,
3278                                                },
3279                                            )
3280                                        }
3281                                    });
3282                                }
3283                                (WrapperKind::OptionHashMap, Some(inner_ty)) => {
3284                                    let snake_at = format_ident!("{}_at", snake);
3285                                    if let Some((key_ty, _)) = extract_map_key_value_through_option(field_ty) {
3286                                        tokens.extend(quote! {
3287                                            #[inline(always)]
3288                                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3289                                                rust_key_paths::Kp::new(
3290                                                    |root: &#name| match root {
3291                                                        #name::#v_ident(inner) => Some(inner),
3292                                                        _ => None,
3293                                                    },
3294                                                    |root: &mut #name| match root {
3295                                                        #name::#v_ident(inner) => Some(inner),
3296                                                        _ => None,
3297                                                    },
3298                                                )
3299                                            }
3300                                            #[inline(always)]
3301                                            pub fn #snake_at(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
3302                                            where
3303                                                #key_ty: Clone + std::hash::Hash + Eq + 'static,
3304                                            {
3305                                                let key2 = key.clone();
3306                                                rust_key_paths::Kp::new(
3307                                                    Box::new(move |root: &#name| match root {
3308                                                        #name::#v_ident(inner) => inner.as_ref().and_then(|m| m.get(&key)),
3309                                                        _ => None,
3310                                                    }),
3311                                                    Box::new(move |root: &mut #name| match root {
3312                                                        #name::#v_ident(inner) => inner.as_mut().and_then(|m| m.get_mut(&key2)),
3313                                                        _ => None,
3314                                                    }),
3315                                                )
3316                                            }
3317                                        });
3318                                    } else {
3319                                        tokens.extend(quote! {
3320                                            #[inline(always)]
3321                                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3322                                                rust_key_paths::Kp::new(
3323                                                    |root: &#name| match root {
3324                                                        #name::#v_ident(inner) => Some(inner),
3325                                                        _ => None,
3326                                                    },
3327                                                    |root: &mut #name| match root {
3328                                                        #name::#v_ident(inner) => Some(inner),
3329                                                        _ => None,
3330                                                    },
3331                                                )
3332                                            }
3333                                        });
3334                                    }
3335                                }
3336                                (WrapperKind::OptionBTreeMap, Some(inner_ty)) => {
3337                                    let snake_at = format_ident!("{}_at", snake);
3338                                    if let Some((key_ty, _)) = extract_map_key_value_through_option(field_ty) {
3339                                        tokens.extend(quote! {
3340                                            #[inline(always)]
3341                                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3342                                                rust_key_paths::Kp::new(
3343                                                    |root: &#name| match root {
3344                                                        #name::#v_ident(inner) => Some(inner),
3345                                                        _ => None,
3346                                                    },
3347                                                    |root: &mut #name| match root {
3348                                                        #name::#v_ident(inner) => Some(inner),
3349                                                        _ => None,
3350                                                    },
3351                                                )
3352                                            }
3353                                            #[inline(always)]
3354                                            pub fn #snake_at(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
3355                                            where
3356                                                #key_ty: Clone + Ord + 'static,
3357                                            {
3358                                                let key2 = key.clone();
3359                                                rust_key_paths::Kp::new(
3360                                                    Box::new(move |root: &#name| match root {
3361                                                        #name::#v_ident(inner) => inner.as_ref().and_then(|m| m.get(&key)),
3362                                                        _ => None,
3363                                                    }),
3364                                                    Box::new(move |root: &mut #name| match root {
3365                                                        #name::#v_ident(inner) => inner.as_mut().and_then(|m| m.get_mut(&key2)),
3366                                                        _ => None,
3367                                                    }),
3368                                                )
3369                                            }
3370                                        });
3371                                    } else {
3372                                        tokens.extend(quote! {
3373                                            #[inline(always)]
3374                                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3375                                                rust_key_paths::Kp::new(
3376                                                    |root: &#name| match root {
3377                                                        #name::#v_ident(inner) => Some(inner),
3378                                                        _ => None,
3379                                                    },
3380                                                    |root: &mut #name| match root {
3381                                                        #name::#v_ident(inner) => Some(inner),
3382                                                        _ => None,
3383                                                    },
3384                                                )
3385                                            }
3386                                        });
3387                                    }
3388                                }
3389                                (WrapperKind::OptionHashSet, Some(inner_ty)) => {
3390                                    let snake_at = format_ident!("{}_at", snake);
3391                                    tokens.extend(quote! {
3392                                        #[inline(always)]
3393                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3394                                            rust_key_paths::Kp::new(
3395                                                |root: &#name| match root {
3396                                                    #name::#v_ident(inner) => Some(inner),
3397                                                    _ => None,
3398                                                },
3399                                                |root: &mut #name| match root {
3400                                                    #name::#v_ident(inner) => Some(inner),
3401                                                    _ => None,
3402                                                },
3403                                            )
3404                                        }
3405
3406                                        /// _at: check if element exists and get reference.
3407                                        /// HashSet does not allow mutable element access (would break hash invariant).
3408                                        #[inline(always)]
3409                                        pub fn #snake_at(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
3410                                        where
3411                                            #inner_ty: Clone + std::hash::Hash + Eq + 'static,
3412                                        {
3413                                            rust_key_paths::Kp::new(
3414                                                Box::new(move |root: &#name| match root {
3415                                                    #name::#v_ident(inner) => inner.as_ref().and_then(|s| s.get(&key)),
3416                                                    _ => None,
3417                                                }),
3418                                                Box::new(move |_root: &mut #name| None),
3419                                            )
3420                                        }
3421                                    });
3422                                }
3423                                (WrapperKind::OptionBTreeSet, Some(inner_ty)) => {
3424                                    let snake_at = format_ident!("{}_at", snake);
3425                                    tokens.extend(quote! {
3426                                        #[inline(always)]
3427                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3428                                            rust_key_paths::Kp::new(
3429                                                |root: &#name| match root {
3430                                                    #name::#v_ident(inner) => Some(inner),
3431                                                    _ => None,
3432                                                },
3433                                                |root: &mut #name| match root {
3434                                                    #name::#v_ident(inner) => Some(inner),
3435                                                    _ => None,
3436                                                },
3437                                            )
3438                                        }
3439
3440                                        /// _at: check if element exists and get reference.
3441                                        /// BTreeSet does not allow mutable element access (would break ordering invariant).
3442                                        #[inline(always)]
3443                                        pub fn #snake_at(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
3444                                        where
3445                                            #inner_ty: Clone + Ord + 'static,
3446                                        {
3447                                            rust_key_paths::Kp::new(
3448                                                Box::new(move |root: &#name| match root {
3449                                                    #name::#v_ident(inner) => inner.as_ref().and_then(|s| s.get(&key)),
3450                                                    _ => None,
3451                                                }),
3452                                                Box::new(move |_root: &mut #name| None),
3453                                            )
3454                                        }
3455                                    });
3456                                }
3457                                (WrapperKind::OptionVecDeque, Some(_inner_ty))
3458                                | (WrapperKind::OptionLinkedList, Some(_inner_ty))
3459                                | (WrapperKind::OptionBinaryHeap, Some(_inner_ty))
3460                                | (WrapperKind::OptionResult, Some(_inner_ty)) => {
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                                }
3477                                (WrapperKind::Vec, Some(inner_ty)) => {
3478                                    tokens.extend(quote! {
3479                                        #[inline(always)]
3480                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3481                                            rust_key_paths::Kp::new(
3482                                                |root: &#name| match root {
3483                                                    #name::#v_ident(inner) => inner.first(),
3484                                                    _ => None,
3485                                                },
3486                                                |root: &mut #name| match root {
3487                                                    #name::#v_ident(inner) => inner.first_mut(),
3488                                                    _ => None,
3489                                                },
3490                                            )
3491                                        }
3492                                    });
3493                                }
3494                                (WrapperKind::Box, Some(inner_ty)) => {
3495                                    // Box in enum: deref to inner (&T / &mut T)
3496                                    tokens.extend(quote! {
3497                                        #[inline(always)]
3498                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3499                                            rust_key_paths::Kp::new(
3500                                                |root: &#name| match root {
3501                                                    #name::#v_ident(inner) => Some(&**inner),
3502                                                    _ => None,
3503                                                },
3504                                                |root: &mut #name| match root {
3505                                                    #name::#v_ident(inner) => Some(&mut **inner),
3506                                                    _ => None,
3507                                                },
3508                                            )
3509                                        }
3510                                    });
3511                                }
3512                                (WrapperKind::Pin, Some(inner_ty)) => {
3513                                    let snake_inner = format_ident!("{}_inner", snake);
3514                                    tokens.extend(quote! {
3515                                        #[inline(always)]
3516                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3517                                            rust_key_paths::Kp::new(
3518                                                |root: &#name| match root {
3519                                                    #name::#v_ident(inner) => Some(inner),
3520                                                    _ => None,
3521                                                },
3522                                                |root: &mut #name| match root {
3523                                                    #name::#v_ident(inner) => Some(inner),
3524                                                    _ => None,
3525                                                },
3526                                            )
3527                                        }
3528                                        #[inline(always)]
3529                                        pub fn #snake_inner() -> rust_key_paths::KpType<'static, #name, #inner_ty>
3530                                        where #inner_ty: std::marker::Unpin
3531                                        {
3532                                            rust_key_paths::Kp::new(
3533                                                |root: &#name| match root {
3534                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_ref(inner).get_ref()),
3535                                                    _ => None,
3536                                                },
3537                                                |root: &mut #name| match root {
3538                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_mut(inner).get_mut()),
3539                                                    _ => None,
3540                                                },
3541                                            )
3542                                        }
3543                                    });
3544                                }
3545                                (WrapperKind::PinBox, Some(inner_ty)) => {
3546                                    let snake_inner = format_ident!("{}_inner", snake);
3547                                    tokens.extend(quote! {
3548                                        #[inline(always)]
3549                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3550                                            rust_key_paths::Kp::new(
3551                                                |root: &#name| match root {
3552                                                    #name::#v_ident(inner) => Some(inner),
3553                                                    _ => None,
3554                                                },
3555                                                |root: &mut #name| match root {
3556                                                    #name::#v_ident(inner) => Some(inner),
3557                                                    _ => None,
3558                                                },
3559                                            )
3560                                        }
3561                                        #[inline(always)]
3562                                        pub fn #snake_inner() -> rust_key_paths::KpType<'static, #name, #inner_ty>
3563                                        where #inner_ty: std::marker::Unpin
3564                                        {
3565                                            rust_key_paths::Kp::new(
3566                                                |root: &#name| match root {
3567                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_ref(inner).get_ref()),
3568                                                    _ => None,
3569                                                },
3570                                                |root: &mut #name| match root {
3571                                                    #name::#v_ident(inner) => Some(std::pin::Pin::as_mut(inner).get_mut()),
3572                                                    _ => None,
3573                                                },
3574                                            )
3575                                        }
3576                                    });
3577                                }
3578                                (WrapperKind::Rc, Some(inner_ty)) => {
3579                                    tokens.extend(quote! {
3580                                        #[inline(always)]
3581                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3582                                            rust_key_paths::Kp::new(
3583                                                |root: &#name| match root {
3584                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
3585                                                    _ => None,
3586                                                },
3587                                                |root: &mut #name| match root {
3588                                                    #name::#v_ident(inner) => std::rc::Rc::get_mut(inner),
3589                                                    _ => None,
3590                                                },
3591                                            )
3592                                        }
3593                                    });
3594                                }
3595                                (WrapperKind::Arc, Some(inner_ty)) => {
3596                                    tokens.extend(quote! {
3597                                        #[inline(always)]
3598                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3599                                            rust_key_paths::Kp::new(
3600                                                |root: &#name| match root {
3601                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
3602                                                    _ => None,
3603                                                },
3604                                                |root: &mut #name| match root {
3605                                                    #name::#v_ident(inner) => std::sync::Arc::get_mut(inner),
3606                                                    _ => None,
3607                                                },
3608                                            )
3609                                        }
3610                                    });
3611                                }
3612                                (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
3613                                    let snake_lock = format_ident!("{}_lock", snake);
3614                                    tokens.extend(quote! {
3615                                        #[inline(always)]
3616                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3617                                            rust_key_paths::Kp::new(
3618                                                |root: &#name| match root {
3619                                                    #name::#v_ident(inner) => Some(inner),
3620                                                    _ => None,
3621                                                },
3622                                                |root: &mut #name| match root {
3623                                                    #name::#v_ident(inner) => Some(inner),
3624                                                    _ => None,
3625                                                },
3626                                            )
3627                                        }
3628                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #field_ty, #inner_ty> {
3629                                            rust_key_paths::lock::LockKp::new(
3630                                                rust_key_paths::Kp::new(
3631                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3632                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3633                                                ),
3634                                                rust_key_paths::lock::ArcRwLockAccess::new(),
3635                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3636                                            )
3637                                        }
3638                                    });
3639                                }
3640                                (WrapperKind::StdArcMutex, Some(inner_ty)) => {
3641                                    let snake_lock = format_ident!("{}_lock", snake);
3642                                    tokens.extend(quote! {
3643                                        #[inline(always)]
3644                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3645                                            rust_key_paths::Kp::new(
3646                                                |root: &#name| match root {
3647                                                    #name::#v_ident(inner) => Some(inner),
3648                                                    _ => None,
3649                                                },
3650                                                |root: &mut #name| match root {
3651                                                    #name::#v_ident(inner) => Some(inner),
3652                                                    _ => None,
3653                                                },
3654                                            )
3655                                        }
3656                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #field_ty, #inner_ty> {
3657                                            rust_key_paths::lock::LockKp::new(
3658                                                rust_key_paths::Kp::new(
3659                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3660                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3661                                                ),
3662                                                rust_key_paths::lock::ArcMutexAccess::new(),
3663                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3664                                            )
3665                                        }
3666                                    });
3667                                }
3668                                (WrapperKind::ArcRwLock, Some(inner_ty)) => {
3669                                    let snake_lock = format_ident!("{}_lock", snake);
3670                                    tokens.extend(quote! {
3671                                        #[inline(always)]
3672                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3673                                            rust_key_paths::Kp::new(
3674                                                |root: &#name| match root {
3675                                                    #name::#v_ident(inner) => Some(inner),
3676                                                    _ => None,
3677                                                },
3678                                                |root: &mut #name| match root {
3679                                                    #name::#v_ident(inner) => Some(inner),
3680                                                    _ => None,
3681                                                },
3682                                            )
3683                                        }
3684                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #field_ty, #inner_ty> {
3685                                            rust_key_paths::lock::LockKp::new(
3686                                                rust_key_paths::Kp::new(
3687                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3688                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3689                                                ),
3690                                                rust_key_paths::lock::ParkingLotRwLockAccess::new(),
3691                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3692                                            )
3693                                        }
3694                                    });
3695                                }
3696                                (WrapperKind::ArcMutex, Some(inner_ty)) => {
3697                                    let snake_lock = format_ident!("{}_lock", snake);
3698                                    tokens.extend(quote! {
3699                                        #[inline(always)]
3700                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3701                                            rust_key_paths::Kp::new(
3702                                                |root: &#name| match root {
3703                                                    #name::#v_ident(inner) => Some(inner),
3704                                                    _ => None,
3705                                                },
3706                                                |root: &mut #name| match root {
3707                                                    #name::#v_ident(inner) => Some(inner),
3708                                                    _ => None,
3709                                                },
3710                                            )
3711                                        }
3712                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #field_ty, #inner_ty> {
3713                                            rust_key_paths::lock::LockKp::new(
3714                                                rust_key_paths::Kp::new(
3715                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3716                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3717                                                ),
3718                                                rust_key_paths::lock::ParkingLotMutexAccess::new(),
3719                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3720                                            )
3721                                        }
3722                                    });
3723                                }
3724                                (WrapperKind::StdArcMutexOption, Some(inner_ty)) => {
3725                                    let snake_lock = format_ident!("{}_lock", snake);
3726                                    tokens.extend(quote! {
3727                                        #[inline(always)]
3728                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3729                                            rust_key_paths::Kp::new(
3730                                                |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3731                                                |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3732                                            )
3733                                        }
3734                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexOptionFor<#name, #field_ty, #inner_ty> {
3735                                            rust_key_paths::lock::LockKp::new(
3736                                                rust_key_paths::Kp::new(
3737                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3738                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3739                                                ),
3740                                                rust_key_paths::lock::ArcMutexAccess::<Option<#inner_ty>>::new(),
3741                                                rust_key_paths::Kp::new(Option::<#inner_ty>::as_ref, Option::<#inner_ty>::as_mut),
3742                                            )
3743                                        }
3744                                    });
3745                                }
3746                                (WrapperKind::StdArcRwLockOption, Some(inner_ty)) => {
3747                                    let snake_lock = format_ident!("{}_lock", snake);
3748                                    tokens.extend(quote! {
3749                                        #[inline(always)]
3750                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3751                                            rust_key_paths::Kp::new(
3752                                                |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3753                                                |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3754                                            )
3755                                        }
3756                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockOptionFor<#name, #field_ty, #inner_ty> {
3757                                            rust_key_paths::lock::LockKp::new(
3758                                                rust_key_paths::Kp::new(
3759                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3760                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3761                                                ),
3762                                                rust_key_paths::lock::ArcRwLockAccess::<Option<#inner_ty>>::new(),
3763                                                rust_key_paths::Kp::new(Option::<#inner_ty>::as_ref, Option::<#inner_ty>::as_mut),
3764                                            )
3765                                        }
3766                                    });
3767                                }
3768                                (WrapperKind::ArcMutexOption, Some(inner_ty)) => {
3769                                    let snake_lock = format_ident!("{}_lock", snake);
3770                                    tokens.extend(quote! {
3771                                        #[inline(always)]
3772                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3773                                            rust_key_paths::Kp::new(
3774                                                |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3775                                                |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3776                                            )
3777                                        }
3778                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexOptionFor<#name, #field_ty, #inner_ty> {
3779                                            rust_key_paths::lock::LockKp::new(
3780                                                rust_key_paths::Kp::new(
3781                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3782                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3783                                                ),
3784                                                rust_key_paths::lock::ParkingLotMutexAccess::<Option<#inner_ty>>::new(),
3785                                                rust_key_paths::Kp::new(Option::<#inner_ty>::as_ref, Option::<#inner_ty>::as_mut),
3786                                            )
3787                                        }
3788                                    });
3789                                }
3790                                (WrapperKind::ArcRwLockOption, Some(inner_ty)) => {
3791                                    let snake_lock = format_ident!("{}_lock", snake);
3792                                    tokens.extend(quote! {
3793                                        #[inline(always)]
3794                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3795                                            rust_key_paths::Kp::new(
3796                                                |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3797                                                |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3798                                            )
3799                                        }
3800                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockOptionFor<#name, #field_ty, #inner_ty> {
3801                                            rust_key_paths::lock::LockKp::new(
3802                                                rust_key_paths::Kp::new(
3803                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3804                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3805                                                ),
3806                                                rust_key_paths::lock::ParkingLotRwLockAccess::<Option<#inner_ty>>::new(),
3807                                                rust_key_paths::Kp::new(Option::<#inner_ty>::as_ref, Option::<#inner_ty>::as_mut),
3808                                            )
3809                                        }
3810                                    });
3811                                }
3812                                (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
3813                                    let snake_async = format_ident!("{}_kp", snake);
3814                                    tokens.extend(quote! {
3815                                        #[inline(always)]
3816                                        pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3817                                            rust_key_paths::Kp::new(
3818                                                |root: &#name| match root {
3819                                                    #name::#v_ident(inner) => Some(inner),
3820                                                    _ => None,
3821                                                },
3822                                                |root: &mut #name| match root {
3823                                                    #name::#v_ident(inner) => Some(inner),
3824                                                    _ => None,
3825                                                },
3826                                            )
3827                                        }
3828                                        pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #field_ty, #inner_ty> {
3829                                            rust_key_paths::async_lock::AsyncLockKp::new(
3830                                                rust_key_paths::Kp::new(
3831                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3832                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3833                                                ),
3834                                                rust_key_paths::async_lock::TokioMutexAccess::new(),
3835                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3836                                            )
3837                                        }
3838                                    });
3839                                }
3840                                (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
3841                                    let snake_async = format_ident!("{}_kp", snake);
3842                                    tokens.extend(quote! {
3843                                        #[inline(always)]
3844                                        pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3845                                            rust_key_paths::Kp::new(
3846                                                |root: &#name| match root {
3847                                                    #name::#v_ident(inner) => Some(inner),
3848                                                    _ => None,
3849                                                },
3850                                                |root: &mut #name| match root {
3851                                                    #name::#v_ident(inner) => Some(inner),
3852                                                    _ => None,
3853                                                },
3854                                            )
3855                                        }
3856                                        pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #field_ty, #inner_ty> {
3857                                            rust_key_paths::async_lock::AsyncLockKp::new(
3858                                                rust_key_paths::Kp::new(
3859                                                    |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3860                                                    |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3861                                                ),
3862                                                rust_key_paths::async_lock::TokioRwLockAccess::new(),
3863                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3864                                            )
3865                                        }
3866                                    });
3867                                }
3868                                (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
3869                                    let snake_async = format_ident!("{}_kp", snake);
3870                                    tokens.extend(quote! {
3871                                        #[inline(always)]
3872                                        pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3873                                            rust_key_paths::Kp::new(
3874                                                |root: &#name| match root {
3875                                                    #name::#v_ident(inner) => Some(inner),
3876                                                    _ => None,
3877                                                },
3878                                                |root: &mut #name| match root {
3879                                                    #name::#v_ident(inner) => Some(inner),
3880                                                    _ => None,
3881                                                },
3882                                            )
3883                                        }
3884                                        pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
3885                                            rust_key_paths::async_lock::AsyncLockKp::new(
3886                                                rust_key_paths::Kp::new(
3887                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3888                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3889                                                ),
3890                                                rust_key_paths::async_lock::TokioMutexAccess::new(),
3891                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3892                                            )
3893                                        }
3894                                    });
3895                                }
3896                                (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
3897                                    let snake_async = format_ident!("{}_kp", snake);
3898                                    tokens.extend(quote! {
3899                                        #[inline(always)]
3900                                        pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3901                                            rust_key_paths::Kp::new(
3902                                                |root: &#name| match root {
3903                                                    #name::#v_ident(inner) => Some(inner),
3904                                                    _ => None,
3905                                                },
3906                                                |root: &mut #name| match root {
3907                                                    #name::#v_ident(inner) => Some(inner),
3908                                                    _ => None,
3909                                                },
3910                                            )
3911                                        }
3912                                        pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
3913                                            rust_key_paths::async_lock::AsyncLockKp::new(
3914                                                rust_key_paths::Kp::new(
3915                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3916                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3917                                                ),
3918                                                rust_key_paths::async_lock::TokioRwLockAccess::new(),
3919                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3920                                            )
3921                                        }
3922                                    });
3923                                }
3924                                (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
3925                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
3926                                    let snake_lock = format_ident!("{}_lock", snake);
3927                                    tokens.extend(quote! {
3928                                        #[inline(always)]
3929                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3930                                            rust_key_paths::Kp::new(
3931                                                |root: &#name| match root {
3932                                                    #name::#v_ident(inner) => Some(inner),
3933                                                    _ => None,
3934                                                },
3935                                                |root: &mut #name| match root {
3936                                                    #name::#v_ident(inner) => Some(inner),
3937                                                    _ => None,
3938                                                },
3939                                            )
3940                                        }
3941                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
3942                                            rust_key_paths::Kp::new(
3943                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3944                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3945                                            )
3946                                        }
3947                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
3948                                            rust_key_paths::lock::LockKp::new(
3949                                                rust_key_paths::Kp::new(
3950                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3951                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3952                                                ),
3953                                                rust_key_paths::lock::ArcMutexAccess::new(),
3954                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3955                                            )
3956                                        }
3957                                    });
3958                                }
3959                                (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
3960                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
3961                                    let snake_lock = format_ident!("{}_lock", snake);
3962                                    tokens.extend(quote! {
3963                                        #[inline(always)]
3964                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3965                                            rust_key_paths::Kp::new(
3966                                                |root: &#name| match root {
3967                                                    #name::#v_ident(inner) => Some(inner),
3968                                                    _ => None,
3969                                                },
3970                                                |root: &mut #name| match root {
3971                                                    #name::#v_ident(inner) => Some(inner),
3972                                                    _ => None,
3973                                                },
3974                                            )
3975                                        }
3976                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
3977                                            rust_key_paths::Kp::new(
3978                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3979                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3980                                            )
3981                                        }
3982                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>, #inner_ty> {
3983                                            rust_key_paths::lock::LockKp::new(
3984                                                rust_key_paths::Kp::new(
3985                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3986                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3987                                                ),
3988                                                rust_key_paths::lock::ParkingLotMutexAccess::new(),
3989                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3990                                            )
3991                                        }
3992                                    });
3993                                }
3994                                (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
3995                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
3996                                    let snake_lock = format_ident!("{}_lock", snake);
3997                                    tokens.extend(quote! {
3998                                        #[inline(always)]
3999                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4000                                            rust_key_paths::Kp::new(
4001                                                |root: &#name| match root {
4002                                                    #name::#v_ident(inner) => Some(inner),
4003                                                    _ => None,
4004                                                },
4005                                                |root: &mut #name| match root {
4006                                                    #name::#v_ident(inner) => Some(inner),
4007                                                    _ => None,
4008                                                },
4009                                            )
4010                                        }
4011                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
4012                                            rust_key_paths::Kp::new(
4013                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4014                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4015                                            )
4016                                        }
4017                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
4018                                            rust_key_paths::lock::LockKp::new(
4019                                                rust_key_paths::Kp::new(
4020                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4021                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4022                                                ),
4023                                                rust_key_paths::lock::ArcRwLockAccess::new(),
4024                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
4025                                            )
4026                                        }
4027                                    });
4028                                }
4029                                (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
4030                                    let snake_unlocked = format_ident!("{}_unlocked", snake);
4031                                    let snake_lock = format_ident!("{}_lock", snake);
4032                                    tokens.extend(quote! {
4033                                        #[inline(always)]
4034                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4035                                            rust_key_paths::Kp::new(
4036                                                |root: &#name| match root {
4037                                                    #name::#v_ident(inner) => Some(inner),
4038                                                    _ => None,
4039                                                },
4040                                                |root: &mut #name| match root {
4041                                                    #name::#v_ident(inner) => Some(inner),
4042                                                    _ => None,
4043                                                },
4044                                            )
4045                                        }
4046                                        pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
4047                                            rust_key_paths::Kp::new(
4048                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4049                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4050                                            )
4051                                        }
4052                                        pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>, #inner_ty> {
4053                                            rust_key_paths::lock::LockKp::new(
4054                                                rust_key_paths::Kp::new(
4055                                                    |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4056                                                    |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4057                                                ),
4058                                                rust_key_paths::lock::ParkingLotRwLockAccess::new(),
4059                                                rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
4060                                            )
4061                                        }
4062                                    });
4063                                }
4064                                (WrapperKind::StdMutex, Some(_inner_ty))
4065                                | (WrapperKind::Mutex, Some(_inner_ty))
4066                                | (WrapperKind::StdRwLock, Some(_inner_ty))
4067                                | (WrapperKind::RwLock, Some(_inner_ty)) => {
4068                                    tokens.extend(quote! {
4069                                        #[inline(always)]
4070                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4071                                            rust_key_paths::Kp::new(
4072                                                |root: &#name| match root {
4073                                                    #name::#v_ident(inner) => Some(inner),
4074                                                    _ => None,
4075                                                },
4076                                                |root: &mut #name| match root {
4077                                                    #name::#v_ident(inner) => Some(inner),
4078                                                    _ => None,
4079                                                },
4080                                            )
4081                                        }
4082                                    });
4083                                }
4084                                (WrapperKind::Tagged, Some(inner_ty)) => {
4085                                    tokens.extend(quote! {
4086                                        #[inline(always)]
4087                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4088                                            rust_key_paths::Kp::new(
4089                                                |root: &#name| match root {
4090                                                    #name::#v_ident(inner) => Some(std::ops::Deref::deref(inner)),
4091                                                    _ => None,
4092                                                },
4093                                                |root: &mut #name| match root {
4094                                                    #name::#v_ident(inner) => Some(std::ops::DerefMut::deref_mut(inner)),
4095                                                    _ => None,
4096                                                },
4097                                            )
4098                                        }
4099                                    });
4100                                }
4101                                (WrapperKind::Atomic, None | Some(_)) => {
4102                                    tokens.extend(quote! {
4103                                        #[inline(always)]
4104                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4105                                            rust_key_paths::Kp::new(
4106                                                |root: &#name| match root {
4107                                                    #name::#v_ident(inner) => Some(inner),
4108                                                    _ => None,
4109                                                },
4110                                                |root: &mut #name| match root {
4111                                                    #name::#v_ident(inner) => Some(inner),
4112                                                    _ => None,
4113                                                },
4114                                            )
4115                                        }
4116                                    });
4117                                }
4118                                (WrapperKind::OptionAtomic, Some(inner_ty)) => {
4119                                    tokens.extend(quote! {
4120                                        #[inline(always)]
4121                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4122                                            rust_key_paths::Kp::new(
4123                                                |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
4124                                                |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
4125                                            )
4126                                        }
4127                                    });
4128                                }
4129                                (WrapperKind::Reference, Some(_inner_ty)) => {
4130                                    tokens.extend(quote! {
4131                                        #[inline(always)]
4132                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4133                                            rust_key_paths::Kp::new(
4134                                                |root: &#name| match root {
4135                                                    #name::#v_ident(inner) => Some(inner),
4136                                                    _ => None,
4137                                                },
4138                                                |_root: &mut #name| None,
4139                                            )
4140                                        }
4141                                    });
4142                                }
4143                                (WrapperKind::Weak, Some(_inner_ty)) => {
4144                                    tokens.extend(quote! {
4145                                        #[inline(always)]
4146                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4147                                            rust_key_paths::Kp::new(
4148                                                |root: &#name| match root {
4149                                                    #name::#v_ident(inner) => Some(inner),
4150                                                    _ => None,
4151                                                },
4152                                                |_root: &mut #name| None,
4153                                            )
4154                                        }
4155                                    });
4156                                }
4157                                (WrapperKind::Cow, Some(inner_ty)) => {
4158                                    tokens.extend(quote! {
4159                                        #[inline(always)]
4160                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4161                                            rust_key_paths::Kp::new(
4162                                                |root: &#name| match root {
4163                                                    #name::#v_ident(inner) => Some(inner.as_ref()),
4164                                                    _ => None,
4165                                                },
4166                                                |root: &mut #name| match root {
4167                                                    #name::#v_ident(inner) => Some(inner.to_mut()),
4168                                                    _ => None,
4169                                                },
4170                                            )
4171                                        }
4172                                    });
4173                                }
4174                                (WrapperKind::OptionBox, Some(inner_ty)) => {
4175                                    // Option<Box<T>>: keypath to T via as_deref() / as_deref_mut()
4176                                    tokens.extend(quote! {
4177                                        #[inline(always)]
4178                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4179                                            rust_key_paths::Kp::new(
4180                                                |root: &#name| match root {
4181                                                    #name::#v_ident(inner) => inner.as_deref(),
4182                                                    _ => None,
4183                                                },
4184                                                |root: &mut #name| match root {
4185                                                    #name::#v_ident(inner) => inner.as_deref_mut(),
4186                                                    _ => None,
4187                                                },
4188                                            )
4189                                        }
4190                                    });
4191                                }
4192                                (WrapperKind::BoxOption, Some(inner_ty)) => {
4193                                    // Box<Option<T>>: keypath to T; inner is &Box<Option<T>>, deref then Option::as_ref/as_mut
4194                                    tokens.extend(quote! {
4195                                        #[inline(always)]
4196                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4197                                            rust_key_paths::Kp::new(
4198                                                |root: &#name| match root {
4199                                                    #name::#v_ident(inner) => (&*inner).as_ref(),
4200                                                    _ => None,
4201                                                },
4202                                                |root: &mut #name| match root {
4203                                                    #name::#v_ident(inner) => (&mut *inner).as_mut(),
4204                                                    _ => None,
4205                                                },
4206                                            )
4207                                        }
4208                                    });
4209                                }
4210                                (WrapperKind::RcOption, Some(inner_ty)) => {
4211                                    // Rc<Option<T>>: keypath to T; get = (&*inner).as_ref(), set = Rc::get_mut then as_mut
4212                                    tokens.extend(quote! {
4213                                        #[inline(always)]
4214                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4215                                            rust_key_paths::Kp::new(
4216                                                |root: &#name| match root {
4217                                                    #name::#v_ident(inner) => (&*inner).as_ref(),
4218                                                    _ => None,
4219                                                },
4220                                                |root: &mut #name| match root {
4221                                                    #name::#v_ident(inner) => std::rc::Rc::get_mut(inner).and_then(std::option::Option::as_mut),
4222                                                    _ => None,
4223                                                },
4224                                            )
4225                                        }
4226                                    });
4227                                }
4228                                (WrapperKind::ArcOption, Some(inner_ty)) => {
4229                                    // Arc<Option<T>>: keypath to T; get = (&*inner).as_ref(), set = Arc::get_mut then as_mut
4230                                    tokens.extend(quote! {
4231                                        #[inline(always)]
4232                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4233                                            rust_key_paths::Kp::new(
4234                                                |root: &#name| match root {
4235                                                    #name::#v_ident(inner) => (&*inner).as_ref(),
4236                                                    _ => None,
4237                                                },
4238                                                |root: &mut #name| match root {
4239                                                    #name::#v_ident(inner) => std::sync::Arc::get_mut(inner).and_then(std::option::Option::as_mut),
4240                                                    _ => None,
4241                                                },
4242                                            )
4243                                        }
4244                                    });
4245                                }
4246                                (WrapperKind::OptionRc, Some(inner_ty)) => {
4247                                    tokens.extend(quote! {
4248                                        #[inline(always)]
4249                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4250                                            rust_key_paths::Kp::new(
4251                                                |root: &#name| match root {
4252                                                    #name::#v_ident(inner) => inner.as_deref(),
4253                                                    _ => None,
4254                                                },
4255                                                |root: &mut #name| match root {
4256                                                    #name::#v_ident(inner) => inner.as_mut().and_then(std::rc::Rc::get_mut),
4257                                                    _ => None,
4258                                                },
4259                                            )
4260                                        }
4261                                    });
4262                                }
4263                                (WrapperKind::OptionArc, Some(inner_ty)) => {
4264                                    tokens.extend(quote! {
4265                                        #[inline(always)]
4266                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4267                                            rust_key_paths::Kp::new(
4268                                                |root: &#name| match root {
4269                                                    #name::#v_ident(inner) => inner.as_deref(),
4270                                                    _ => None,
4271                                                },
4272                                                |root: &mut #name| match root {
4273                                                    #name::#v_ident(inner) => inner.as_mut().and_then(std::sync::Arc::get_mut),
4274                                                    _ => None,
4275                                                },
4276                                            )
4277                                        }
4278                                    });
4279                                }
4280                                (WrapperKind::OptionCow, Some(inner_ty)) => {
4281                                    tokens.extend(quote! {
4282                                        #[inline(always)]
4283                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4284                                            rust_key_paths::Kp::new(
4285                                                |root: &#name| match root {
4286                                                    #name::#v_ident(inner) => inner.as_ref().map(|c| c.as_ref()),
4287                                                    _ => None,
4288                                                },
4289                                                |root: &mut #name| match root {
4290                                                    #name::#v_ident(inner) => inner.as_mut().map(|c| c.to_mut()),
4291                                                    _ => None,
4292                                                },
4293                                            )
4294                                        }
4295                                    });
4296                                }
4297                                (WrapperKind::OptionTagged, Some(inner_ty)) => {
4298                                    tokens.extend(quote! {
4299                                        #[inline(always)]
4300                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4301                                            rust_key_paths::Kp::new(
4302                                                |root: &#name| match root {
4303                                                    #name::#v_ident(inner) => inner.as_ref().map(|t| std::ops::Deref::deref(t)),
4304                                                    _ => None,
4305                                                },
4306                                                |root: &mut #name| match root {
4307                                                    #name::#v_ident(inner) => inner.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
4308                                                    _ => None,
4309                                                },
4310                                            )
4311                                        }
4312                                    });
4313                                }
4314                                (WrapperKind::OptionReference, Some(inner_ty)) => {
4315                                    tokens.extend(quote! {
4316                                        #[inline(always)]
4317                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4318                                            rust_key_paths::Kp::new(
4319                                                |root: &#name| match root {
4320                                                    #name::#v_ident(inner) => inner.as_ref(),
4321                                                    _ => None,
4322                                                },
4323                                                |_root: &mut #name| None,
4324                                            )
4325                                        }
4326                                    });
4327                                }
4328                                (WrapperKind::String, None) => {
4329                                    tokens.extend(quote! {
4330                                        #[inline(always)]
4331                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4332                                            rust_key_paths::Kp::new(
4333                                                |root: &#name| match root {
4334                                                    #name::#v_ident(inner) => Some(inner),
4335                                                    _ => None,
4336                                                },
4337                                                |root: &mut #name| match root {
4338                                                    #name::#v_ident(inner) => Some(inner),
4339                                                    _ => None,
4340                                                },
4341                                            )
4342                                        }
4343                                    });
4344                                }
4345                                (WrapperKind::OptionString, None) => {
4346                                    tokens.extend(quote! {
4347                                        #[inline(always)]
4348                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, std::string::String> {
4349                                            rust_key_paths::Kp::new(
4350                                                |root: &#name| match root {
4351                                                    #name::#v_ident(inner) => inner.as_ref(),
4352                                                    _ => None,
4353                                                },
4354                                                |root: &mut #name| match root {
4355                                                    #name::#v_ident(inner) => inner.as_mut(),
4356                                                    _ => None,
4357                                                },
4358                                            )
4359                                        }
4360                                    });
4361                                }
4362                                (WrapperKind::OnceCell, Some(inner_ty)) => {
4363                                    tokens.extend(quote! {
4364                                        #[inline(always)]
4365                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4366                                            rust_key_paths::Kp::new(
4367                                                |root: &#name| match root {
4368                                                    #name::#v_ident(inner) => inner.get(),
4369                                                    _ => None,
4370                                                },
4371                                                |_root: &mut #name| None,
4372                                            )
4373                                        }
4374                                    });
4375                                }
4376                                (WrapperKind::Lazy, Some(inner_ty)) => {
4377                                    tokens.extend(quote! {
4378                                        #[inline(always)]
4379                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4380                                            rust_key_paths::Kp::new(
4381                                                |root: &#name| match root {
4382                                                    #name::#v_ident(inner) => Some(inner.get()),
4383                                                    _ => None,
4384                                                },
4385                                                |_root: &mut #name| None,
4386                                            )
4387                                        }
4388                                    });
4389                                }
4390                                (WrapperKind::OptionOnceCell, Some(inner_ty)) => {
4391                                    tokens.extend(quote! {
4392                                        #[inline(always)]
4393                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4394                                            rust_key_paths::Kp::new(
4395                                                |root: &#name| match root {
4396                                                    #name::#v_ident(inner) => inner.as_ref().and_then(|c| c.get()),
4397                                                    _ => None,
4398                                                },
4399                                                |_root: &mut #name| None,
4400                                            )
4401                                        }
4402                                    });
4403                                }
4404                                (WrapperKind::OptionLazy, Some(inner_ty)) => {
4405                                    tokens.extend(quote! {
4406                                        #[inline(always)]
4407                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
4408                                            rust_key_paths::Kp::new(
4409                                                |root: &#name| match root {
4410                                                    #name::#v_ident(inner) => inner.as_ref().map(|c| c.get()),
4411                                                    _ => None,
4412                                                },
4413                                                |_root: &mut #name| None,
4414                                            )
4415                                        }
4416                                    });
4417                                }
4418                                (WrapperKind::Cell, Some(_inner_ty))
4419                                | (WrapperKind::RefCell, Some(_inner_ty))
4420                                | (WrapperKind::PhantomData, Some(_inner_ty))
4421                                | (WrapperKind::Range, Some(_inner_ty))
4422                                | (WrapperKind::OptionCell, Some(_inner_ty))
4423                                | (WrapperKind::OptionPhantomData, Some(_inner_ty))
4424                                | (WrapperKind::OptionRange, Some(_inner_ty)) => {
4425                                    tokens.extend(quote! {
4426                                        #[inline(always)]
4427                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4428                                            rust_key_paths::Kp::new(
4429                                                |root: &#name| match root {
4430                                                    #name::#v_ident(inner) => Some(inner),
4431                                                    _ => None,
4432                                                },
4433                                                |root: &mut #name| match root {
4434                                                    #name::#v_ident(inner) => Some(inner),
4435                                                    _ => None,
4436                                                },
4437                                            )
4438                                        }
4439                                    });
4440                                }
4441                                (WrapperKind::OptionRefCell, Some(inner_ty)) => {
4442                                    tokens.extend(quote! {
4443                                        #[inline(always)]
4444                                        pub fn #snake() -> rust_key_paths::KpOptionRefCellType<'_, #name, #inner_ty> {
4445                                            rust_key_paths::Kp::new(
4446                                                |root: &#name| match root {
4447                                                    #name::#v_ident(inner) => inner.as_ref().map(|r| r.borrow()),
4448                                                    _ => None,
4449                                                },
4450                                                |root: &mut #name| match root {
4451                                                    #name::#v_ident(inner) => inner.as_ref().map(|r| r.borrow_mut()),
4452                                                    _ => None,
4453                                                },
4454                                            )
4455                                        }
4456                                    });
4457                                }
4458                                (WrapperKind::None, None) => {
4459                                    // Basic type
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                                _ => {
4477                                    // Other wrapper types - return keypath to field
4478                                    tokens.extend(quote! {
4479                                        #[inline(always)]
4480                                        pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
4481                                            rust_key_paths::Kp::new(
4482                                                |root: &#name| match root {
4483                                                    #name::#v_ident(inner) => Some(inner),
4484                                                    _ => None,
4485                                                },
4486                                                |root: &mut #name| match root {
4487                                                    #name::#v_ident(inner) => Some(inner),
4488                                                    _ => None,
4489                                                },
4490                                            )
4491                                        }
4492                                    });
4493                                }
4494                            }
4495                        } else {
4496                            // Multi-field tuple variant - return keypath to variant itself
4497                            tokens.extend(quote! {
4498                                #[inline(always)]
4499                                pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
4500                                    rust_key_paths::Kp::new(
4501                                        |root: &#name| match root {
4502                                            #name::#v_ident(..) => Some(root),
4503                                            _ => None,
4504                                        },
4505                                        |root: &mut #name| match root {
4506                                            #name::#v_ident(..) => Some(root),
4507                                            _ => None,
4508                                        },
4509                                    )
4510                                }
4511                            });
4512                        }
4513                    }
4514                    Fields::Named(_) => {
4515                        // Named field variant - return keypath to variant itself
4516                        tokens.extend(quote! {
4517                            pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
4518                                rust_key_paths::Kp::new(
4519                                    |root: &#name| match root {
4520                                        #name::#v_ident { .. } => Some(root),
4521                                        _ => None,
4522                                    },
4523                                    |root: &mut #name| match root {
4524                                        #name::#v_ident { .. } => Some(root),
4525                                        _ => None,
4526                                    },
4527                                )
4528                            }
4529                        });
4530                    }
4531                }
4532            }
4533
4534            tokens
4535        }
4536        Data::Union(_) => {
4537            return syn::Error::new(input_span, "Kp derive does not support unions")
4538                .to_compile_error()
4539                .into();
4540        }
4541    };
4542
4543    let expanded = quote! {
4544        impl #name {
4545            #methods
4546        }
4547    };
4548
4549    TokenStream::from(expanded)
4550}
4551
4552/// Derive macro that generates `partial_kps() -> Vec<PKp<Self>>` returning all field/variant keypaths.
4553/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
4554///
4555/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
4556/// (using the same methods Kp generates, e.g. `some_variant()`).
4557///
4558/// # Example
4559/// ```
4560/// use key_paths_derive::{Kp, Pkp};
4561/// use rust_key_paths::PKp;
4562///
4563/// #[derive(Kp, Pkp)]
4564/// struct Person {
4565///     name: String,
4566///     age: i32,
4567/// }
4568///
4569/// let kps = Person::partial_kps();
4570/// assert_eq!(kps.len(), 2);
4571/// ```
4572#[proc_macro_derive(Pkp)]
4573pub fn derive_partial_keypaths(input: TokenStream) -> TokenStream {
4574    let input = parse_macro_input!(input as DeriveInput);
4575    let name = &input.ident;
4576
4577    let kp_calls = match &input.data {
4578        Data::Struct(data_struct) => match &data_struct.fields {
4579            Fields::Named(fields_named) => {
4580                let calls: Vec<_> = fields_named
4581                    .named
4582                    .iter()
4583                    .filter_map(|f| f.ident.as_ref())
4584                    .map(|field_ident| {
4585                        quote! { rust_key_paths::PKp::new(Self::#field_ident()) }
4586                    })
4587                    .collect();
4588                quote! { #(#calls),* }
4589            }
4590            Fields::Unnamed(unnamed) => {
4591                let calls: Vec<_> = (0..unnamed.unnamed.len())
4592                    .map(|idx| {
4593                        let kp_fn = format_ident!("f{}", idx);
4594                        quote! { rust_key_paths::PKp::new(Self::#kp_fn()) }
4595                    })
4596                    .collect();
4597                quote! { #(#calls),* }
4598            }
4599            Fields::Unit => quote! {},
4600        },
4601        Data::Enum(data_enum) => {
4602            let calls: Vec<_> = data_enum
4603                .variants
4604                .iter()
4605                .map(|variant| {
4606                    let v_ident = &variant.ident;
4607                    let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
4608                    quote! { rust_key_paths::PKp::new(Self::#snake()) }
4609                })
4610                .collect();
4611            quote! { #(#calls),* }
4612        }
4613        Data::Union(_) => {
4614            return syn::Error::new(input.ident.span(), "Pkp derive does not support unions")
4615                .to_compile_error()
4616                .into();
4617        }
4618    };
4619
4620    let expanded = quote! {
4621        impl #name {
4622            /// Returns a vec of all field keypaths as partial keypaths (type-erased).
4623            #[inline(always)]
4624            pub fn partial_kps() -> Vec<rust_key_paths::PKp<#name>> {
4625                vec![#kp_calls]
4626            }
4627        }
4628    };
4629
4630    TokenStream::from(expanded)
4631}
4632
4633/// Derive macro that generates `any_kps() -> Vec<AKp>` returning all field/variant keypaths as any keypaths.
4634/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
4635/// AKp type-erases both Root and Value, enabling heterogeneous collections of keypaths.
4636///
4637/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
4638/// (using the same methods Kp generates, e.g. `some_variant()`).
4639///
4640/// # Example
4641/// ```
4642/// use key_paths_derive::{Kp, Akp};
4643/// use rust_key_paths::AKp;
4644///
4645/// #[derive(Kp, Akp)]
4646/// struct Person {
4647///     name: String,
4648///     age: i32,
4649/// }
4650///
4651/// let kps = Person::any_kps();
4652/// assert_eq!(kps.len(), 2);
4653/// let person = Person { name: "Akash".into(), age: 30 };
4654/// let name: Option<&String> = kps[0].get(&person as &dyn std::any::Any).and_then(|v| v.downcast_ref());
4655/// assert_eq!(name, Some(&"Akash".to_string()));
4656/// ```
4657#[proc_macro_derive(Akp)]
4658pub fn derive_any_keypaths(input: TokenStream) -> TokenStream {
4659    let input = parse_macro_input!(input as DeriveInput);
4660    let name = &input.ident;
4661
4662    let kp_calls = match &input.data {
4663        Data::Struct(data_struct) => match &data_struct.fields {
4664            Fields::Named(fields_named) => {
4665                let calls: Vec<_> = fields_named
4666                    .named
4667                    .iter()
4668                    .filter_map(|f| f.ident.as_ref())
4669                    .map(|field_ident| {
4670                        quote! { rust_key_paths::AKp::new(Self::#field_ident()) }
4671                    })
4672                    .collect();
4673                quote! { #(#calls),* }
4674            }
4675            Fields::Unnamed(unnamed) => {
4676                let calls: Vec<_> = (0..unnamed.unnamed.len())
4677                    .map(|idx| {
4678                        let kp_fn = format_ident!("f{}", idx);
4679                        quote! { rust_key_paths::AKp::new(Self::#kp_fn()) }
4680                    })
4681                    .collect();
4682                quote! { #(#calls),* }
4683            }
4684            Fields::Unit => quote! {},
4685        },
4686        Data::Enum(data_enum) => {
4687            let calls: Vec<_> = data_enum
4688                .variants
4689                .iter()
4690                .map(|variant| {
4691                    let v_ident = &variant.ident;
4692                    let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
4693                    quote! { rust_key_paths::AKp::new(Self::#snake()) }
4694                })
4695                .collect();
4696            quote! { #(#calls),* }
4697        }
4698        Data::Union(_) => {
4699            return syn::Error::new(input.ident.span(), "Akp derive does not support unions")
4700                .to_compile_error()
4701                .into();
4702        }
4703    };
4704
4705    let expanded = quote! {
4706        impl #name {
4707            /// Returns a vec of all field keypaths as any keypaths (fully type-erased).
4708            #[inline(always)]
4709            pub fn any_kps() -> Vec<rust_key_paths::AKp> {
4710                vec![#kp_calls]
4711            }
4712        }
4713    };
4714
4715    TokenStream::from(expanded)
4716}