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