Skip to main content

key_paths_derive/
lib.rs

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