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::OptionBox, Some(inner_ty)) => {
683 // For Option<Box<T>>, keypath to T: get returns Option<&T> via as_deref()
684 tokens.extend(quote! {
685 #[inline(always)]
686 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
687 rust_key_paths::Kp::new(
688 |root: &#name| root.#field_ident.as_deref(),
689 |root: &mut #name| root.#field_ident.as_deref_mut(),
690 )
691 }
692 });
693 }
694 (WrapperKind::OptionRc, Some(inner_ty)) => {
695 // For Option<Rc<T>>, keypath to T: get returns Option<&T> via as_deref()
696 // Setter: as_mut() gives Option<&mut Rc<T>>, and_then(Rc::get_mut) gives Option<&mut T>
697 tokens.extend(quote! {
698 #[inline(always)]
699 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
700 rust_key_paths::Kp::new(
701 |root: &#name| root.#field_ident.as_deref(),
702 |root: &mut #name| root.#field_ident.as_mut().and_then(std::rc::Rc::get_mut),
703 )
704 }
705 });
706 }
707 (WrapperKind::OptionArc, Some(inner_ty)) => {
708 // For Option<Arc<T>>, keypath to T: get returns Option<&T> via as_deref()
709 // Setter: as_mut() gives Option<&mut Arc<T>>, and_then(Arc::get_mut) gives Option<&mut T>
710 tokens.extend(quote! {
711 #[inline(always)]
712 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
713 rust_key_paths::Kp::new(
714 |root: &#name| root.#field_ident.as_deref(),
715 |root: &mut #name| root.#field_ident.as_mut().and_then(std::sync::Arc::get_mut),
716 )
717 }
718 });
719 }
720 (WrapperKind::OptionVecDeque, Some(_inner_ty))
721 | (WrapperKind::OptionLinkedList, Some(_inner_ty))
722 | (WrapperKind::OptionBinaryHeap, Some(_inner_ty))
723 | (WrapperKind::OptionHashSet, Some(_inner_ty))
724 | (WrapperKind::OptionBTreeSet, Some(_inner_ty))
725 | (WrapperKind::OptionResult, Some(_inner_ty))
726 | (WrapperKind::OptionBTreeMap, Some(_inner_ty)) => {
727 // Keypath to the Option container (reference), like Vec/HashSet
728 tokens.extend(quote! {
729 #[inline(always)]
730 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
731 rust_key_paths::Kp::new(
732 |root: &#name| Some(&root.#field_ident),
733 |root: &mut #name| Some(&mut root.#field_ident),
734 )
735 }
736 });
737 }
738 (WrapperKind::Vec, Some(inner_ty)) => {
739 tokens.extend(quote! {
740 #[inline(always)]
741 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
742 rust_key_paths::Kp::new(
743 |root: &#name| Some(&root.#field_ident),
744 |root: &mut #name| Some(&mut root.#field_ident),
745 )
746 }
747 #[inline(always)]
748 pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
749 rust_key_paths::Kp::new(
750 Box::new(move |root: &#name| root.#field_ident.get(index)),
751 Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
752 )
753 }
754 });
755 }
756 (WrapperKind::HashMap, Some(inner_ty)) => {
757 if let Some((key_ty, _)) = extract_map_key_value(ty) {
758 tokens.extend(quote! {
759 #[inline(always)]
760 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
761 rust_key_paths::Kp::new(
762 |root: &#name| Some(&root.#field_ident),
763 |root: &mut #name| Some(&mut root.#field_ident),
764 )
765 }
766 #[inline(always)]
767 pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
768 where
769 #key_ty: Clone + std::hash::Hash + Eq + 'static,
770 {
771 let key2 = key.clone();
772 rust_key_paths::Kp::new(
773 Box::new(move |root: &#name| root.#field_ident.get(&key)),
774 Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
775 )
776 }
777 });
778 } else {
779 tokens.extend(quote! {
780 #[inline(always)]
781 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
782 rust_key_paths::Kp::new(
783 |root: &#name| Some(&root.#field_ident),
784 |root: &mut #name| Some(&mut root.#field_ident),
785 )
786 }
787 });
788 }
789 }
790 (WrapperKind::BTreeMap, Some(inner_ty)) | (WrapperKind::BTreeMapOption, Some(inner_ty)) => {
791 if let Some((key_ty, _)) = extract_map_key_value(ty) {
792 tokens.extend(quote! {
793 #[inline(always)]
794 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
795 rust_key_paths::Kp::new(
796 |root: &#name| Some(&root.#field_ident),
797 |root: &mut #name| Some(&mut root.#field_ident),
798 )
799 }
800 #[inline(always)]
801 pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
802 where
803 #key_ty: Clone + Ord + 'static,
804 {
805 let key2 = key.clone();
806 rust_key_paths::Kp::new(
807 Box::new(move |root: &#name| root.#field_ident.get(&key)),
808 Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
809 )
810 }
811 });
812 } else {
813 tokens.extend(quote! {
814 #[inline(always)]
815 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
816 rust_key_paths::Kp::new(
817 |root: &#name| Some(&root.#field_ident),
818 |root: &mut #name| Some(&mut root.#field_ident),
819 )
820 }
821 });
822 }
823 }
824 (WrapperKind::Box, Some(inner_ty)) => {
825 // For Box<T>, deref to inner type (returns &T / &mut T, not &Box<T>)
826 tokens.extend(quote! {
827 #[inline(always)]
828 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
829 rust_key_paths::Kp::new(
830 |root: &#name| Some(&*root.#field_ident),
831 |root: &mut #name| Some(&mut *root.#field_ident),
832 )
833 }
834 });
835 }
836 (WrapperKind::BoxOption, Some(inner_ty)) => {
837 // For Box<Option<T>>, keypath to T: deref Box to Option<T>, then Option::as_ref/as_mut
838 tokens.extend(quote! {
839 #[inline(always)]
840 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
841 rust_key_paths::Kp::new(
842 |root: &#name| (&*root.#field_ident).as_ref(),
843 |root: &mut #name| (&mut *root.#field_ident).as_mut(),
844 )
845 }
846 });
847 }
848 (WrapperKind::RcOption, Some(inner_ty)) => {
849 // For Rc<Option<T>>, keypath to T: deref Rc to &Option<T>, then Option::as_ref; set = Rc::get_mut then as_mut
850 tokens.extend(quote! {
851 #[inline(always)]
852 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
853 rust_key_paths::Kp::new(
854 |root: &#name| (&*root.#field_ident).as_ref(),
855 |root: &mut #name| std::rc::Rc::get_mut(&mut root.#field_ident).and_then(std::option::Option::as_mut),
856 )
857 }
858 });
859 }
860 (WrapperKind::ArcOption, Some(inner_ty)) => {
861 // For Arc<Option<T>>, keypath to T: deref Arc to &Option<T>, then Option::as_ref; set = Arc::get_mut then as_mut
862 tokens.extend(quote! {
863 #[inline(always)]
864 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
865 rust_key_paths::Kp::new(
866 |root: &#name| (&*root.#field_ident).as_ref(),
867 |root: &mut #name| std::sync::Arc::get_mut(&mut root.#field_ident).and_then(std::option::Option::as_mut),
868 )
869 }
870 });
871 }
872 (WrapperKind::Pin, Some(inner_ty)) => {
873 let kp_inner_fn = format_ident!("{}_inner", field_ident);
874 tokens.extend(quote! {
875 #[inline(always)]
876 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
877 rust_key_paths::Kp::new(
878 |root: &#name| Some(&root.#field_ident),
879 |root: &mut #name| Some(&mut root.#field_ident),
880 )
881 }
882 #[inline(always)]
883 pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
884 where #inner_ty: std::marker::Unpin
885 {
886 rust_key_paths::Kp::new(
887 |root: &#name| Some(std::pin::Pin::as_ref(&root.#field_ident).get_ref()),
888 |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#field_ident).get_mut()),
889 )
890 }
891 });
892 }
893 (WrapperKind::PinBox, Some(inner_ty)) => {
894 let kp_inner_fn = format_ident!("{}_inner", field_ident);
895 tokens.extend(quote! {
896 #[inline(always)]
897 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
898 rust_key_paths::Kp::new(
899 |root: &#name| Some(&root.#field_ident),
900 |root: &mut #name| Some(&mut root.#field_ident),
901 )
902 }
903 #[inline(always)]
904 pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
905 where #inner_ty: std::marker::Unpin
906 {
907 // Pin::as_ref on Pin<Box<T>> returns Pin<&T> (Box Deref target), so get_ref() already gives &T
908 rust_key_paths::Kp::new(
909 |root: &#name| Some(std::pin::Pin::as_ref(&root.#field_ident).get_ref()),
910 |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#field_ident).get_mut()),
911 )
912 }
913 });
914 }
915 (WrapperKind::PinnedField, _) => {
916 let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
917 tokens.extend(quote! {
918 #[inline(always)]
919 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
920 rust_key_paths::Kp::new(
921 |root: &#name| Some(&root.#field_ident),
922 |root: &mut #name| Some(&mut root.#field_ident),
923 )
924 }
925 /// Pinned projection for #[pin] field. Requires #[pin_project] on struct.
926 #[inline(always)]
927 pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
928 this.project().#field_ident
929 }
930 });
931 }
932 (WrapperKind::PinnedFuture, _) => {
933 let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
934 let kp_await_fn = format_ident!("{}_await", field_ident);
935 let kp_pin_future_fn = format_ident!("{}_pin_future_kp", field_ident);
936 let output_ty = quote! { <#ty as std::future::Future>::Output };
937 tokens.extend(quote! {
938 #[inline(always)]
939 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
940 rust_key_paths::Kp::new(
941 |root: &#name| Some(&root.#field_ident),
942 |root: &mut #name| Some(&mut root.#field_ident),
943 )
944 }
945 /// Pinned projection for #[pin] Future field. Requires #[pin_project] on struct.
946 #[inline(always)]
947 pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
948 this.project().#field_ident
949 }
950 /// Poll the pinned future. Requires #[pin_project] on struct.
951 pub async fn #kp_await_fn(this: std::pin::Pin<&mut #name>) -> Option<#output_ty>
952 where #ty: std::future::Future
953 {
954 use std::future::Future;
955 Some(this.project().#field_ident.await)
956 }
957 /// Keypath for [rust_key_paths::Kp::then_pin_future]. Composable pin future await.
958 #[inline(always)]
959 pub fn #kp_pin_future_fn() -> impl rust_key_paths::pin::PinFutureAwaitLike<#name, #output_ty> {
960 rust_key_paths::pin_future_await_kp!(#name, #kp_await_fn -> #output_ty)
961 }
962 });
963 }
964 (WrapperKind::PinnedBoxFuture, Some(output_ty)) => {
965 let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
966 let kp_await_fn = format_ident!("{}_await", field_ident);
967 let kp_pin_future_fn = format_ident!("{}_pin_future_kp", field_ident);
968 tokens.extend(quote! {
969 #[inline(always)]
970 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
971 rust_key_paths::Kp::new(
972 |root: &#name| Some(&root.#field_ident),
973 |root: &mut #name| Some(&mut root.#field_ident),
974 )
975 }
976 /// Pinned projection for #[pin] Box<dyn Future> field. Requires #[pin_project] on struct.
977 #[inline(always)]
978 pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
979 this.project().#field_ident
980 }
981 /// Poll the pinned boxed future. Requires #[pin_project] on struct.
982 pub async fn #kp_await_fn(this: std::pin::Pin<&mut #name>) -> Option<#output_ty> {
983 Some(this.project().#field_ident.await)
984 }
985 /// Keypath for [rust_key_paths::Kp::then_pin_future]. Composable pin future await.
986 #[inline(always)]
987 pub fn #kp_pin_future_fn() -> impl rust_key_paths::pin::PinFutureAwaitLike<#name, #output_ty> {
988 rust_key_paths::pin_future_await_kp!(#name, #kp_await_fn -> #output_ty)
989 }
990 });
991 }
992 (WrapperKind::Rc, Some(inner_ty)) => {
993 // For Rc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
994 tokens.extend(quote! {
995 #[inline(always)]
996 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
997 rust_key_paths::Kp::new(
998 |root: &#name| Some(root.#field_ident.as_ref()),
999 |root: &mut #name| std::rc::Rc::get_mut(&mut root.#field_ident),
1000 )
1001 }
1002 });
1003 }
1004 (WrapperKind::Arc, Some(inner_ty)) => {
1005 // For Arc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
1006 tokens.extend(quote! {
1007 #[inline(always)]
1008 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1009 rust_key_paths::Kp::new(
1010 |root: &#name| Some(root.#field_ident.as_ref()),
1011 |root: &mut #name| std::sync::Arc::get_mut(&mut root.#field_ident),
1012 )
1013 }
1014 });
1015 }
1016 (WrapperKind::Cow, Some(inner_ty)) => {
1017 // For Cow<'_, B>, deref to inner type (as_ref/to_mut)
1018 tokens.extend(quote! {
1019 #[inline(always)]
1020 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1021 rust_key_paths::Kp::new(
1022 |root: &#name| Some(root.#field_ident.as_ref()),
1023 |root: &mut #name| Some(root.#field_ident.to_mut()),
1024 )
1025 }
1026 });
1027 }
1028
1029 (WrapperKind::OptionCow, Some(inner_ty)) => {
1030 // For Option<Cow<'_, B>>
1031 tokens.extend(quote! {
1032 #[inline(always)]
1033 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1034 rust_key_paths::Kp::new(
1035 |root: &#name| root.#field_ident.as_ref().map(|c| c.as_ref()),
1036 |root: &mut #name| root.#field_ident.as_mut().map(|c| c.to_mut()),
1037 )
1038 }
1039 });
1040 }
1041 (WrapperKind::OptionTagged, Some(inner_ty)) => {
1042 // For Option<Tagged<Tag, T>> - Tagged implements Deref/DerefMut
1043 tokens.extend(quote! {
1044 #[inline(always)]
1045 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1046 rust_key_paths::Kp::new(
1047 |root: &#name| root.#field_ident.as_ref().map(|t| std::ops::Deref::deref(t)),
1048 |root: &mut #name| root.#field_ident.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
1049 )
1050 }
1051 });
1052 }
1053 (WrapperKind::OptionReference, Some(inner_ty)) => {
1054 // For Option<&T>, Option<&str>, Option<&[T]> - read-only, setter returns None
1055 tokens.extend(quote! {
1056 #[inline(always)]
1057 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1058 rust_key_paths::Kp::new(
1059 |root: &#name| root.#field_ident.as_ref(),
1060 |_root: &mut #name| None,
1061 )
1062 }
1063 });
1064 }
1065 (WrapperKind::HashSet, Some(inner_ty)) | (WrapperKind::HashSetOption, Some(inner_ty)) => {
1066 let kp_at_fn = format_ident!("{}_at", field_ident);
1067
1068 tokens.extend(quote! {
1069 #[inline(always)]
1070 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1071 rust_key_paths::Kp::new(
1072 |root: &#name| Some(&root.#field_ident),
1073 |root: &mut #name| Some(&mut root.#field_ident),
1074 )
1075 }
1076
1077 /// _at: check if element exists and get reference.
1078 /// HashSet does not allow mutable element access (would break hash invariant).
1079 #[inline(always)]
1080 pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1081 where
1082 #inner_ty: Clone + std::hash::Hash + Eq + 'static,
1083 {
1084 rust_key_paths::Kp::new(
1085 Box::new(move |root: &#name| root.#field_ident.get(&key)),
1086 Box::new(move |_root: &mut #name| None),
1087 )
1088 }
1089 });
1090 }
1091 (WrapperKind::BTreeSet, Some(inner_ty)) | (WrapperKind::BTreeSetOption, Some(inner_ty)) => {
1092 let kp_at_fn = format_ident!("{}_at", field_ident);
1093
1094 tokens.extend(quote! {
1095 #[inline(always)]
1096 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1097 rust_key_paths::Kp::new(
1098 |root: &#name| Some(&root.#field_ident),
1099 |root: &mut #name| Some(&mut root.#field_ident),
1100 )
1101 }
1102
1103 /// _at: check if element exists and get reference.
1104 /// BTreeSet does not allow mutable element access (would break ordering invariant).
1105 #[inline(always)]
1106 pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1107 where
1108 #inner_ty: Clone + Ord + 'static,
1109 {
1110 rust_key_paths::Kp::new(
1111 Box::new(move |root: &#name| root.#field_ident.get(&key)),
1112 Box::new(move |_root: &mut #name| None),
1113 )
1114 }
1115 });
1116 }
1117 (WrapperKind::VecDeque, Some(inner_ty)) | (WrapperKind::VecDequeOption, Some(inner_ty)) => {
1118 tokens.extend(quote! {
1119 #[inline(always)]
1120 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1121 rust_key_paths::Kp::new(
1122 |root: &#name| Some(&root.#field_ident),
1123 |root: &mut #name| Some(&mut root.#field_ident),
1124 )
1125 }
1126 #[inline(always)]
1127 pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1128 rust_key_paths::Kp::new(
1129 Box::new(move |root: &#name| root.#field_ident.get(index)),
1130 Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
1131 )
1132 }
1133 });
1134 }
1135 (WrapperKind::LinkedList, Some(_inner_ty)) | (WrapperKind::LinkedListOption, Some(_inner_ty)) => {
1136 tokens.extend(quote! {
1137 #[inline(always)]
1138 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1139 rust_key_paths::Kp::new(
1140 |root: &#name| Some(&root.#field_ident),
1141 |root: &mut #name| Some(&mut root.#field_ident),
1142 )
1143 }
1144 });
1145 }
1146 (WrapperKind::BinaryHeap, Some(_inner_ty)) | (WrapperKind::BinaryHeapOption, Some(_inner_ty)) => {
1147 tokens.extend(quote! {
1148 #[inline(always)]
1149 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1150 rust_key_paths::Kp::new(
1151 |root: &#name| Some(&root.#field_ident),
1152 |root: &mut #name| Some(&mut root.#field_ident),
1153 )
1154 }
1155 });
1156 }
1157 (WrapperKind::Result, Some(inner_ty)) => {
1158 // For Result<T, E>, access Ok value
1159 tokens.extend(quote! {
1160 #[inline(always)]
1161 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1162 rust_key_paths::Kp::new(
1163 |root: &#name| root.#field_ident.as_ref().ok(),
1164 |root: &mut #name| root.#field_ident.as_mut().ok(),
1165 )
1166 }
1167 });
1168 }
1169 (WrapperKind::StdArcMutex, Some(inner_ty)) => {
1170 // For Arc<std::sync::Mutex<T>>
1171 let kp_lock_fn = format_ident!("{}_kp", field_ident);
1172 tokens.extend(quote! {
1173 #[inline(always)]
1174 pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1175 rust_key_paths::Kp::new(
1176 |root: &#name| Some(&root.#field_ident),
1177 |root: &mut #name| Some(&mut root.#field_ident),
1178 )
1179 }
1180 pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #ty, #inner_ty> {
1181 rust_key_paths::lock::LockKp::new(
1182 rust_key_paths::Kp::new(
1183 |root: &#name| Some(&root.#field_ident),
1184 |root: &mut #name| Some(&mut root.#field_ident),
1185 ),
1186 rust_key_paths::lock::ArcMutexAccess::new(),
1187 rust_key_paths::Kp::new(
1188 |v: &#inner_ty| Some(v),
1189 |v: &mut #inner_ty| Some(v),
1190 ),
1191 )
1192 }
1193 });
1194 }
1195 (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
1196 // For Arc<std::sync::RwLock<T>>
1197 let kp_lock_fn = format_ident!("{}_kp", field_ident);
1198 tokens.extend(quote! {
1199 #[inline(always)]
1200 pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1201 rust_key_paths::Kp::new(
1202 |root: &#name| Some(&root.#field_ident),
1203 |root: &mut #name| Some(&mut root.#field_ident),
1204 )
1205 }
1206 pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #ty, #inner_ty> {
1207 rust_key_paths::lock::LockKp::new(
1208 rust_key_paths::Kp::new(
1209 |root: &#name| Some(&root.#field_ident),
1210 |root: &mut #name| Some(&mut root.#field_ident),
1211 ),
1212 rust_key_paths::lock::ArcRwLockAccess::new(),
1213 rust_key_paths::Kp::new(
1214 |v: &#inner_ty| Some(v),
1215 |v: &mut #inner_ty| Some(v),
1216 ),
1217 )
1218 }
1219 });
1220 }
1221 (WrapperKind::ArcRwLock, Some(inner_ty)) => {
1222 // For Arc<parking_lot::RwLock<T>> (requires rust-key-paths "parking_lot" feature)
1223 let kp_lock_fn = format_ident!("{}_kp", field_ident);
1224 tokens.extend(quote! {
1225 #[inline(always)]
1226 pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1227 rust_key_paths::Kp::new(
1228 |root: &#name| Some(&root.#field_ident),
1229 |root: &mut #name| Some(&mut root.#field_ident),
1230 )
1231 }
1232 pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #ty, #inner_ty> {
1233 rust_key_paths::lock::LockKp::new(
1234 rust_key_paths::Kp::new(
1235 |root: &#name| Some(&root.#field_ident),
1236 |root: &mut #name| Some(&mut root.#field_ident),
1237 ),
1238 rust_key_paths::lock::ParkingLotRwLockAccess::new(),
1239 rust_key_paths::Kp::new(
1240 |v: &#inner_ty| Some(v),
1241 |v: &mut #inner_ty| Some(v),
1242 ),
1243 )
1244 }
1245 });
1246 }
1247 (WrapperKind::ArcMutex, Some(inner_ty)) => {
1248 // For Arc<parking_lot::Mutex<T>> (requires rust-key-paths "parking_lot" feature)
1249 let kp_lock_fn = format_ident!("{}_kp", field_ident);
1250 tokens.extend(quote! {
1251 #[inline(always)]
1252 pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1253 rust_key_paths::Kp::new(
1254 |root: &#name| Some(&root.#field_ident),
1255 |root: &mut #name| Some(&mut root.#field_ident),
1256 )
1257 }
1258 pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #ty, #inner_ty> {
1259 rust_key_paths::lock::LockKp::new(
1260 rust_key_paths::Kp::new(
1261 |root: &#name| Some(&root.#field_ident),
1262 |root: &mut #name| Some(&mut root.#field_ident),
1263 ),
1264 rust_key_paths::lock::ParkingLotMutexAccess::new(),
1265 rust_key_paths::Kp::new(
1266 |v: &#inner_ty| Some(v),
1267 |v: &mut #inner_ty| Some(v),
1268 ),
1269 )
1270 }
1271 });
1272 }
1273 (WrapperKind::Mutex, Some(_inner_ty))
1274 | (WrapperKind::StdMutex, Some(_inner_ty)) => {
1275 // For Mutex<T>, return keypath to container
1276 tokens.extend(quote! {
1277 #[inline(always)]
1278 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1279 rust_key_paths::Kp::new(
1280 |root: &#name| Some(&root.#field_ident),
1281 |root: &mut #name| Some(&mut root.#field_ident),
1282 )
1283 }
1284 });
1285 }
1286 (WrapperKind::RwLock, Some(_inner_ty))
1287 | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
1288 // For RwLock<T>, return keypath to container
1289 tokens.extend(quote! {
1290 #[inline(always)]
1291 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1292 rust_key_paths::Kp::new(
1293 |root: &#name| Some(&root.#field_ident),
1294 |root: &mut #name| Some(&mut root.#field_ident),
1295 )
1296 }
1297 });
1298 }
1299 (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
1300 let kp_async_fn = format_ident!("{}_kp", field_ident);
1301 tokens.extend(quote! {
1302 #[inline(always)]
1303 pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1304 rust_key_paths::Kp::new(
1305 |root: &#name| Some(&root.#field_ident),
1306 |root: &mut #name| Some(&mut root.#field_ident),
1307 )
1308 }
1309 pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
1310 rust_key_paths::async_lock::AsyncLockKp::new(
1311 rust_key_paths::Kp::new(
1312 |root: &#name| Some(&root.#field_ident),
1313 |root: &mut #name| Some(&mut root.#field_ident),
1314 ),
1315 rust_key_paths::async_lock::TokioMutexAccess::new(),
1316 rust_key_paths::Kp::new(
1317 |v: &#inner_ty| Some(v),
1318 |v: &mut #inner_ty| Some(v),
1319 ),
1320 )
1321 }
1322 });
1323 }
1324 (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
1325 let kp_async_fn = format_ident!("{}_kp", field_ident);
1326 tokens.extend(quote! {
1327 #[inline(always)]
1328 pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1329 rust_key_paths::Kp::new(
1330 |root: &#name| Some(&root.#field_ident),
1331 |root: &mut #name| Some(&mut root.#field_ident),
1332 )
1333 }
1334 pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
1335 rust_key_paths::async_lock::AsyncLockKp::new(
1336 rust_key_paths::Kp::new(
1337 |root: &#name| Some(&root.#field_ident),
1338 |root: &mut #name| Some(&mut root.#field_ident),
1339 ),
1340 rust_key_paths::async_lock::TokioRwLockAccess::new(),
1341 rust_key_paths::Kp::new(
1342 |v: &#inner_ty| Some(v),
1343 |v: &mut #inner_ty| Some(v),
1344 ),
1345 )
1346 }
1347 });
1348 }
1349 (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
1350 let kp_async_fn = format_ident!("{}_kp", field_ident);
1351 tokens.extend(quote! {
1352 #[inline(always)]
1353 pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1354 rust_key_paths::Kp::new(
1355 |root: &#name| Some(&root.#field_ident),
1356 |root: &mut #name| Some(&mut root.#field_ident),
1357 )
1358 }
1359 pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
1360 rust_key_paths::async_lock::AsyncLockKp::new(
1361 rust_key_paths::Kp::new(
1362 |root: &#name| root.#field_ident.as_ref(),
1363 |root: &mut #name| root.#field_ident.as_mut(),
1364 ),
1365 rust_key_paths::async_lock::TokioMutexAccess::new(),
1366 rust_key_paths::Kp::new(
1367 |v: &#inner_ty| Some(v),
1368 |v: &mut #inner_ty| Some(v),
1369 ),
1370 )
1371 }
1372 });
1373 }
1374 (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
1375 let kp_async_fn = format_ident!("{}_kp", field_ident);
1376 tokens.extend(quote! {
1377 #[inline(always)]
1378 pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1379 rust_key_paths::Kp::new(
1380 |root: &#name| Some(&root.#field_ident),
1381 |root: &mut #name| Some(&mut root.#field_ident),
1382 )
1383 }
1384 pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
1385 rust_key_paths::async_lock::AsyncLockKp::new(
1386 rust_key_paths::Kp::new(
1387 |root: &#name| root.#field_ident.as_ref(),
1388 |root: &mut #name| root.#field_ident.as_mut(),
1389 ),
1390 rust_key_paths::async_lock::TokioRwLockAccess::new(),
1391 rust_key_paths::Kp::new(
1392 |v: &#inner_ty| Some(v),
1393 |v: &mut #inner_ty| Some(v),
1394 ),
1395 )
1396 }
1397 });
1398 }
1399 (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
1400 // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1401 let kp_lock_fn = format_ident!("{}_kp", field_ident);
1402 tokens.extend(quote! {
1403 #[inline(always)]
1404 pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1405 rust_key_paths::Kp::new(
1406 |root: &#name| Some(&root.#field_ident),
1407 |root: &mut #name| Some(&mut root.#field_ident),
1408 )
1409 }
1410 // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
1411 // rust_key_paths::Kp::new(
1412 // |root: &#name| root.#field_ident.as_ref(),
1413 // |root: &mut #name| root.#field_ident.as_mut(),
1414 // )
1415 // }
1416 pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
1417 rust_key_paths::lock::LockKp::new(
1418 rust_key_paths::Kp::new(
1419 |root: &#name| root.#field_ident.as_ref(),
1420 |root: &mut #name| root.#field_ident.as_mut(),
1421 ),
1422 rust_key_paths::lock::ArcMutexAccess::new(),
1423 rust_key_paths::Kp::new(
1424 |v: &#inner_ty| Some(v),
1425 |v: &mut #inner_ty| Some(v),
1426 ),
1427 )
1428 }
1429 });
1430 }
1431 (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
1432 // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1433 let kp_lock_fn = format_ident!("{}_kp", field_ident);
1434 tokens.extend(quote! {
1435 #[inline(always)]
1436 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1437 rust_key_paths::Kp::new(
1438 |root: &#name| Some(&root.#field_ident),
1439 |root: &mut #name| Some(&mut root.#field_ident),
1440 )
1441 }
1442 // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
1443 // rust_key_paths::Kp::new(
1444 // |root: &#name| root.#field_ident.as_ref(),
1445 // |root: &mut #name| root.#field_ident.as_mut(),
1446 // )
1447 // }
1448 pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>, #inner_ty> {
1449 rust_key_paths::lock::LockKp::new(
1450 rust_key_paths::Kp::new(
1451 |root: &#name| root.#field_ident.as_ref(),
1452 |root: &mut #name| root.#field_ident.as_mut(),
1453 ),
1454 rust_key_paths::lock::ParkingLotMutexAccess::new(),
1455 rust_key_paths::Kp::new(
1456 |v: &#inner_ty| Some(v),
1457 |v: &mut #inner_ty| Some(v),
1458 ),
1459 )
1460 }
1461 });
1462 }
1463 (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
1464 // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1465 let kp_lock_fn = format_ident!("{}_kp", field_ident);
1466 tokens.extend(quote! {
1467 #[inline(always)]
1468 pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1469 rust_key_paths::Kp::new(
1470 |root: &#name| Some(&root.#field_ident),
1471 |root: &mut #name| Some(&mut root.#field_ident),
1472 )
1473 }
1474 // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
1475 // rust_key_paths::Kp::new(
1476 // |root: &#name| root.#field_ident.as_ref(),
1477 // |root: &mut #name| root.#field_ident.as_mut(),
1478 // )
1479 // }
1480 pub fn #kp_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
1481 rust_key_paths::lock::LockKp::new(
1482 rust_key_paths::Kp::new(
1483 |root: &#name| root.#field_ident.as_ref(),
1484 |root: &mut #name| root.#field_ident.as_mut(),
1485 ),
1486 rust_key_paths::lock::ArcRwLockAccess::new(),
1487 rust_key_paths::Kp::new(
1488 |v: &#inner_ty| Some(v),
1489 |v: &mut #inner_ty| Some(v),
1490 ),
1491 )
1492 }
1493 });
1494 }
1495 (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
1496 // let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1497 let kp_lock_fn = format_ident!("{}_kp", field_ident);
1498 tokens.extend(quote! {
1499 #[inline(always)]
1500 pub fn #kp_lock_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1501 rust_key_paths::Kp::new(
1502 |root: &#name| Some(&root.#field_ident),
1503 |root: &mut #name| Some(&mut root.#field_ident),
1504 )
1505 }
1506 // pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
1507 // rust_key_paths::Kp::new(
1508 // |root: &#name| root.#field_ident.as_ref(),
1509 // |root: &mut #name| root.#field_ident.as_mut(),
1510 // )
1511 // }
1512 pub fn #kp_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>, #inner_ty> {
1513 rust_key_paths::lock::LockKp::new(
1514 rust_key_paths::Kp::new(
1515 |root: &#name| root.#field_ident.as_ref(),
1516 |root: &mut #name| root.#field_ident.as_mut(),
1517 ),
1518 rust_key_paths::lock::ParkingLotRwLockAccess::new(),
1519 rust_key_paths::Kp::new(
1520 |v: &#inner_ty| Some(v),
1521 |v: &mut #inner_ty| Some(v),
1522 ),
1523 )
1524 }
1525 });
1526 }
1527 (WrapperKind::OptionStdMutex, Some(inner_ty))
1528 | (WrapperKind::OptionMutex, Some(inner_ty)) => {
1529 let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1530 tokens.extend(quote! {
1531 #[inline(always)]
1532 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1533 rust_key_paths::Kp::new(
1534 |root: &#name| Some(&root.#field_ident),
1535 |root: &mut #name| Some(&mut root.#field_ident),
1536 )
1537 }
1538 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
1539 rust_key_paths::Kp::new(
1540 |root: &#name| root.#field_ident.as_ref(),
1541 |root: &mut #name| root.#field_ident.as_mut(),
1542 )
1543 }
1544 });
1545 }
1546 (WrapperKind::OptionStdRwLock, Some(inner_ty))
1547 | (WrapperKind::OptionRwLock, Some(inner_ty)) => {
1548 let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
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 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
1558 rust_key_paths::Kp::new(
1559 |root: &#name| root.#field_ident.as_ref(),
1560 |root: &mut #name| root.#field_ident.as_mut(),
1561 )
1562 }
1563 });
1564 }
1565 (WrapperKind::Weak, Some(_inner_ty)) => {
1566 // For Weak<T>, return keypath to container
1567 tokens.extend(quote! {
1568 #[inline(always)]
1569 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1570 rust_key_paths::Kp::new(
1571 |root: &#name| Some(&root.#field_ident),
1572 |_root: &mut #name| None, // Weak doesn't support mutable access
1573 )
1574 }
1575 });
1576 }
1577 (WrapperKind::Atomic, None | Some(_)) => {
1578 // For atomic types: return keypath to the atomic (user calls .load()/.store())
1579 tokens.extend(quote! {
1580 #[inline(always)]
1581 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1582 rust_key_paths::Kp::new(
1583 |root: &#name| Some(&root.#field_ident),
1584 |root: &mut #name| Some(&mut root.#field_ident),
1585 )
1586 }
1587 });
1588 }
1589 (WrapperKind::OptionAtomic, Some(inner_ty)) => {
1590 tokens.extend(quote! {
1591 #[inline(always)]
1592 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1593 rust_key_paths::Kp::new(
1594 |root: &#name| root.#field_ident.as_ref(),
1595 |root: &mut #name| root.#field_ident.as_mut(),
1596 )
1597 }
1598 });
1599 }
1600 (WrapperKind::String, None) => {
1601 tokens.extend(quote! {
1602 #[inline(always)]
1603 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1604 rust_key_paths::Kp::new(
1605 |root: &#name| Some(&root.#field_ident),
1606 |root: &mut #name| Some(&mut root.#field_ident),
1607 )
1608 }
1609 });
1610 }
1611 (WrapperKind::OptionString, None) => {
1612 tokens.extend(quote! {
1613 #[inline(always)]
1614 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, std::string::String> {
1615 rust_key_paths::Kp::new(
1616 |root: &#name| root.#field_ident.as_ref(),
1617 |root: &mut #name| root.#field_ident.as_mut(),
1618 )
1619 }
1620 });
1621 }
1622 (WrapperKind::Cell, Some(_inner_ty)) => {
1623 tokens.extend(quote! {
1624 #[inline(always)]
1625 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1626 rust_key_paths::Kp::new(
1627 |root: &#name| Some(&root.#field_ident),
1628 |root: &mut #name| Some(&mut root.#field_ident),
1629 )
1630 }
1631 });
1632 }
1633 (WrapperKind::RefCell, Some(_inner_ty)) => {
1634 tokens.extend(quote! {
1635 #[inline(always)]
1636 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1637 rust_key_paths::Kp::new(
1638 |root: &#name| Some(&root.#field_ident),
1639 |root: &mut #name| Some(&mut root.#field_ident),
1640 )
1641 }
1642 });
1643 }
1644 (WrapperKind::OnceCell, Some(inner_ty)) => {
1645 // OnceLock/OnceCell: keypath to inner value; get = .get() -> Option<&T>, set = None
1646 tokens.extend(quote! {
1647 #[inline(always)]
1648 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1649 rust_key_paths::Kp::new(
1650 |root: &#name| root.#field_ident.get(),
1651 |_root: &mut #name| None,
1652 )
1653 }
1654 });
1655 }
1656 (WrapperKind::Lazy, Some(inner_ty)) => {
1657 // Lazy/LazyLock: keypath to inner value; get = .get() -> &T wrapped in Some, set = None
1658 tokens.extend(quote! {
1659 #[inline(always)]
1660 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1661 rust_key_paths::Kp::new(
1662 |root: &#name| Some(root.#field_ident.get()),
1663 |_root: &mut #name| None,
1664 )
1665 }
1666 });
1667 }
1668 (WrapperKind::PhantomData, Some(_inner_ty)) => {
1669 tokens.extend(quote! {
1670 #[inline(always)]
1671 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1672 rust_key_paths::Kp::new(
1673 |root: &#name| Some(&root.#field_ident),
1674 |root: &mut #name| Some(&mut root.#field_ident),
1675 )
1676 }
1677 });
1678 }
1679 (WrapperKind::Range, Some(_inner_ty)) => {
1680 tokens.extend(quote! {
1681 #[inline(always)]
1682 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1683 rust_key_paths::Kp::new(
1684 |root: &#name| Some(&root.#field_ident),
1685 |root: &mut #name| Some(&mut root.#field_ident),
1686 )
1687 }
1688 });
1689 }
1690 (WrapperKind::OptionCell, Some(_inner_ty)) => {
1691 tokens.extend(quote! {
1692 #[inline(always)]
1693 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1694 rust_key_paths::Kp::new(
1695 |root: &#name| Some(&root.#field_ident),
1696 |root: &mut #name| Some(&mut root.#field_ident),
1697 )
1698 }
1699 });
1700 }
1701 (WrapperKind::OptionRefCell, Some(_inner_ty)) => {
1702 tokens.extend(quote! {
1703 #[inline(always)]
1704 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1705 rust_key_paths::Kp::new(
1706 |root: &#name| Some(&root.#field_ident),
1707 |root: &mut #name| Some(&mut root.#field_ident),
1708 )
1709 }
1710 });
1711 }
1712 (WrapperKind::OptionOnceCell, Some(inner_ty)) => {
1713 tokens.extend(quote! {
1714 #[inline(always)]
1715 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1716 rust_key_paths::Kp::new(
1717 |root: &#name| root.#field_ident.as_ref().and_then(|c| c.get()),
1718 |_root: &mut #name| None,
1719 )
1720 }
1721 });
1722 }
1723 (WrapperKind::OptionLazy, Some(inner_ty)) => {
1724 tokens.extend(quote! {
1725 #[inline(always)]
1726 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1727 rust_key_paths::Kp::new(
1728 |root: &#name| root.#field_ident.as_ref().map(|c| c.get()),
1729 |_root: &mut #name| None,
1730 )
1731 }
1732 });
1733 }
1734 (WrapperKind::OptionPhantomData, Some(_inner_ty)) => {
1735 tokens.extend(quote! {
1736 #[inline(always)]
1737 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1738 rust_key_paths::Kp::new(
1739 |root: &#name| Some(&root.#field_ident),
1740 |root: &mut #name| Some(&mut root.#field_ident),
1741 )
1742 }
1743 });
1744 }
1745 (WrapperKind::OptionRange, Some(_inner_ty)) => {
1746 tokens.extend(quote! {
1747 #[inline(always)]
1748 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1749 rust_key_paths::Kp::new(
1750 |root: &#name| Some(&root.#field_ident),
1751 |root: &mut #name| Some(&mut root.#field_ident),
1752 )
1753 }
1754 });
1755 }
1756 (WrapperKind::Reference, Some(_inner_ty)) => {
1757 // For reference types (&T, &str, &[T]): read-only, setter returns None
1758 tokens.extend(quote! {
1759 #[inline(always)]
1760 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1761 rust_key_paths::Kp::new(
1762 |root: &#name| Some(&root.#field_ident),
1763 |_root: &mut #name| None, // references: read-only
1764 )
1765 }
1766 });
1767 }
1768 (WrapperKind::None, None) => {
1769 // For basic types, direct access
1770 tokens.extend(quote! {
1771 #[inline(always)]
1772 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1773 rust_key_paths::Kp::new(
1774 |root: &#name| Some(&root.#field_ident),
1775 |root: &mut #name| Some(&mut root.#field_ident),
1776 )
1777 }
1778 });
1779 }
1780 _ => {
1781 // For unknown/complex nested types, return keypath to field itself
1782 tokens.extend(quote! {
1783 #[inline(always)]
1784 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1785 rust_key_paths::Kp::new(
1786 |root: &#name| Some(&root.#field_ident),
1787 |root: &mut #name| Some(&mut root.#field_ident),
1788 )
1789 }
1790 });
1791 }
1792 }
1793 }
1794
1795 tokens
1796 }
1797 Fields::Unnamed(unnamed) => {
1798 let mut tokens = proc_macro2::TokenStream::new();
1799
1800 // Generate identity methods for the tuple struct
1801 tokens.extend(quote! {
1802 /// Returns a generic identity keypath for this type
1803 #[inline(always)]
1804 pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
1805 #name,
1806 #name,
1807 Root,
1808 Root,
1809 MutRoot,
1810 MutRoot,
1811 fn(Root) -> Option<Root>,
1812 fn(MutRoot) -> Option<MutRoot>,
1813 >
1814 where
1815 Root: std::borrow::Borrow<#name>,
1816 MutRoot: std::borrow::BorrowMut<#name>,
1817 {
1818 rust_key_paths::Kp::new(
1819 |r: Root| Some(r),
1820 |r: MutRoot| Some(r)
1821 )
1822 }
1823
1824 /// Returns a simple identity keypath for this type
1825 #[inline(always)]
1826 pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
1827 rust_key_paths::Kp::new(
1828 |r: &#name| Some(r),
1829 |r: &mut #name| Some(r)
1830 )
1831 }
1832 });
1833
1834 for (idx, field) in unnamed.unnamed.iter().enumerate() {
1835 let idx_lit = syn::Index::from(idx);
1836 let ty = &field.ty;
1837 // Centralized keypath method names for tuple fields – change here to adjust for all types
1838 let kp_fn = format_ident!("f{}", idx);
1839 let kp_at_fn = format_ident!("f{}_at", idx);
1840
1841 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
1842
1843 match (kind, inner_ty.clone()) {
1844 (WrapperKind::Option, Some(inner_ty)) => {
1845 tokens.extend(quote! {
1846 #[inline(always)]
1847 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1848 rust_key_paths::Kp::new(
1849 |root: &#name| root.#idx_lit.as_ref(),
1850 |root: &mut #name| root.#idx_lit.as_mut(),
1851 )
1852 }
1853 });
1854 }
1855 (WrapperKind::OptionBox, Some(inner_ty)) => {
1856 tokens.extend(quote! {
1857 #[inline(always)]
1858 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1859 rust_key_paths::Kp::new(
1860 |root: &#name| root.#idx_lit.as_deref(),
1861 |root: &mut #name| root.#idx_lit.as_deref_mut(),
1862 )
1863 }
1864 });
1865 }
1866 (WrapperKind::OptionRc, Some(inner_ty)) => {
1867 tokens.extend(quote! {
1868 #[inline(always)]
1869 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1870 rust_key_paths::Kp::new(
1871 |root: &#name| root.#idx_lit.as_deref(),
1872 |root: &mut #name| root.#idx_lit.as_mut().and_then(std::rc::Rc::get_mut),
1873 )
1874 }
1875 });
1876 }
1877 (WrapperKind::OptionArc, Some(inner_ty)) => {
1878 tokens.extend(quote! {
1879 #[inline(always)]
1880 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1881 rust_key_paths::Kp::new(
1882 |root: &#name| root.#idx_lit.as_deref(),
1883 |root: &mut #name| root.#idx_lit.as_mut().and_then(std::sync::Arc::get_mut),
1884 )
1885 }
1886 });
1887 }
1888 (WrapperKind::OptionVecDeque, Some(_inner_ty))
1889 | (WrapperKind::OptionLinkedList, Some(_inner_ty))
1890 | (WrapperKind::OptionBinaryHeap, Some(_inner_ty))
1891 | (WrapperKind::OptionHashSet, Some(_inner_ty))
1892 | (WrapperKind::OptionBTreeSet, Some(_inner_ty))
1893 | (WrapperKind::OptionResult, Some(_inner_ty))
1894 | (WrapperKind::OptionBTreeMap, Some(_inner_ty)) => {
1895 tokens.extend(quote! {
1896 #[inline(always)]
1897 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1898 rust_key_paths::Kp::new(
1899 |root: &#name| Some(&root.#idx_lit),
1900 |root: &mut #name| Some(&mut root.#idx_lit),
1901 )
1902 }
1903 });
1904 }
1905 (WrapperKind::Vec, Some(inner_ty)) => {
1906 tokens.extend(quote! {
1907 #[inline(always)]
1908 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1909 rust_key_paths::Kp::new(
1910 |root: &#name| Some(&root.#idx_lit),
1911 |root: &mut #name| Some(&mut root.#idx_lit),
1912 )
1913 }
1914 #[inline(always)]
1915 pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1916 rust_key_paths::Kp::new(
1917 Box::new(move |root: &#name| root.#idx_lit.get(index)),
1918 Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
1919 )
1920 }
1921 });
1922 }
1923 (WrapperKind::HashMap, Some(inner_ty)) => {
1924 if let Some((key_ty, _)) = extract_map_key_value(ty) {
1925 tokens.extend(quote! {
1926 #[inline(always)]
1927 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1928 rust_key_paths::Kp::new(
1929 |root: &#name| Some(&root.#idx_lit),
1930 |root: &mut #name| Some(&mut root.#idx_lit),
1931 )
1932 }
1933 #[inline(always)]
1934 pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1935 where
1936 #key_ty: Clone + std::hash::Hash + Eq + 'static,
1937 {
1938 let key2 = key.clone();
1939 rust_key_paths::Kp::new(
1940 Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1941 Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
1942 )
1943 }
1944 });
1945 } else {
1946 tokens.extend(quote! {
1947 #[inline(always)]
1948 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1949 rust_key_paths::Kp::new(
1950 |root: &#name| Some(&root.#idx_lit),
1951 |root: &mut #name| Some(&mut root.#idx_lit),
1952 )
1953 }
1954 });
1955 }
1956 }
1957 (WrapperKind::BTreeMap, Some(inner_ty)) | (WrapperKind::BTreeMapOption, Some(inner_ty)) => {
1958 if let Some((key_ty, _)) = extract_map_key_value(ty) {
1959 tokens.extend(quote! {
1960 #[inline(always)]
1961 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1962 rust_key_paths::Kp::new(
1963 |root: &#name| Some(&root.#idx_lit),
1964 |root: &mut #name| Some(&mut root.#idx_lit),
1965 )
1966 }
1967 #[inline(always)]
1968 pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1969 where
1970 #key_ty: Clone + Ord + 'static,
1971 {
1972 let key2 = key.clone();
1973 rust_key_paths::Kp::new(
1974 Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1975 Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
1976 )
1977 }
1978 });
1979 } else {
1980 tokens.extend(quote! {
1981 #[inline(always)]
1982 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1983 rust_key_paths::Kp::new(
1984 |root: &#name| Some(&root.#idx_lit),
1985 |root: &mut #name| Some(&mut root.#idx_lit),
1986 )
1987 }
1988 });
1989 }
1990 }
1991 (WrapperKind::Box, Some(inner_ty)) => {
1992 // Box: deref to inner (returns &T / &mut T)
1993 tokens.extend(quote! {
1994 #[inline(always)]
1995 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1996 rust_key_paths::Kp::new(
1997 |root: &#name| Some(&*root.#idx_lit),
1998 |root: &mut #name| Some(&mut *root.#idx_lit),
1999 )
2000 }
2001 });
2002 }
2003 (WrapperKind::BoxOption, Some(inner_ty)) => {
2004 tokens.extend(quote! {
2005 #[inline(always)]
2006 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2007 rust_key_paths::Kp::new(
2008 |root: &#name| (&*root.#idx_lit).as_ref(),
2009 |root: &mut #name| (&mut *root.#idx_lit).as_mut(),
2010 )
2011 }
2012 });
2013 }
2014 (WrapperKind::RcOption, Some(inner_ty)) => {
2015 tokens.extend(quote! {
2016 #[inline(always)]
2017 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2018 rust_key_paths::Kp::new(
2019 |root: &#name| (&*root.#idx_lit).as_ref(),
2020 |root: &mut #name| std::rc::Rc::get_mut(&mut root.#idx_lit).and_then(std::option::Option::as_mut),
2021 )
2022 }
2023 });
2024 }
2025 (WrapperKind::ArcOption, Some(inner_ty)) => {
2026 tokens.extend(quote! {
2027 #[inline(always)]
2028 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2029 rust_key_paths::Kp::new(
2030 |root: &#name| (&*root.#idx_lit).as_ref(),
2031 |root: &mut #name| std::sync::Arc::get_mut(&mut root.#idx_lit).and_then(std::option::Option::as_mut),
2032 )
2033 }
2034 });
2035 }
2036 (WrapperKind::Pin, Some(inner_ty)) => {
2037 let kp_inner_fn = format_ident!("{}_inner", kp_fn);
2038 tokens.extend(quote! {
2039 #[inline(always)]
2040 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2041 rust_key_paths::Kp::new(
2042 |root: &#name| Some(&root.#idx_lit),
2043 |root: &mut #name| Some(&mut root.#idx_lit),
2044 )
2045 }
2046 #[inline(always)]
2047 pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2048 where #inner_ty: std::marker::Unpin
2049 {
2050 rust_key_paths::Kp::new(
2051 |root: &#name| Some(std::pin::Pin::as_ref(&root.#idx_lit).get_ref()),
2052 |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#idx_lit).get_mut()),
2053 )
2054 }
2055 });
2056 }
2057 (WrapperKind::PinBox, Some(inner_ty)) => {
2058 let kp_inner_fn = format_ident!("{}_inner", kp_fn);
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_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2069 where #inner_ty: std::marker::Unpin
2070 {
2071 rust_key_paths::Kp::new(
2072 |root: &#name| Some(std::pin::Pin::as_ref(&root.#idx_lit).get_ref()),
2073 |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#idx_lit).get_mut()),
2074 )
2075 }
2076 });
2077 }
2078 (WrapperKind::Rc, Some(inner_ty)) => {
2079 tokens.extend(quote! {
2080 #[inline(always)]
2081 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2082 rust_key_paths::Kp::new(
2083 |root: &#name| Some(root.#idx_lit.as_ref()),
2084 |root: &mut #name| std::rc::Rc::get_mut(&mut root.#idx_lit),
2085 )
2086 }
2087 });
2088 }
2089 (WrapperKind::Arc, Some(inner_ty)) => {
2090 tokens.extend(quote! {
2091 #[inline(always)]
2092 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2093 rust_key_paths::Kp::new(
2094 |root: &#name| Some(root.#idx_lit.as_ref()),
2095 |root: &mut #name| std::sync::Arc::get_mut(&mut root.#idx_lit),
2096 )
2097 }
2098 });
2099 }
2100
2101 (WrapperKind::Cow, Some(inner_ty)) => {
2102 tokens.extend(quote! {
2103 #[inline(always)]
2104 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2105 rust_key_paths::Kp::new(
2106 |root: &#name| Some(root.#idx_lit.as_ref()),
2107 |root: &mut #name| Some(root.#idx_lit.to_mut()),
2108 )
2109 }
2110 });
2111 }
2112
2113 (WrapperKind::OptionCow, Some(inner_ty)) => {
2114 tokens.extend(quote! {
2115 #[inline(always)]
2116 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2117 rust_key_paths::Kp::new(
2118 |root: &#name| root.#idx_lit.as_ref().map(|c| c.as_ref()),
2119 |root: &mut #name| root.#idx_lit.as_mut().map(|c| c.to_mut()),
2120 )
2121 }
2122 });
2123 }
2124 (WrapperKind::OptionTagged, Some(inner_ty)) => {
2125 tokens.extend(quote! {
2126 #[inline(always)]
2127 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2128 rust_key_paths::Kp::new(
2129 |root: &#name| root.#idx_lit.as_ref().map(|t| std::ops::Deref::deref(t)),
2130 |root: &mut #name| root.#idx_lit.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
2131 )
2132 }
2133 });
2134 }
2135 (WrapperKind::OptionReference, Some(inner_ty)) => {
2136 tokens.extend(quote! {
2137 #[inline(always)]
2138 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2139 rust_key_paths::Kp::new(
2140 |root: &#name| root.#idx_lit.as_ref(),
2141 |_root: &mut #name| None,
2142 )
2143 }
2144 });
2145 }
2146 (WrapperKind::HashSet, Some(inner_ty)) | (WrapperKind::HashSetOption, Some(inner_ty)) => {
2147 let kp_at_fn = format_ident!("f{}_at", idx);
2148
2149 tokens.extend(quote! {
2150 #[inline(always)]
2151 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2152 rust_key_paths::Kp::new(
2153 |root: &#name| Some(&root.#idx_lit),
2154 |root: &mut #name| Some(&mut root.#idx_lit),
2155 )
2156 }
2157
2158 /// _at: check if element exists and get reference.
2159 /// HashSet does not allow mutable element access (would break hash invariant).
2160 #[inline(always)]
2161 pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2162 where
2163 #inner_ty: Clone + std::hash::Hash + Eq + 'static,
2164 {
2165 rust_key_paths::Kp::new(
2166 Box::new(move |root: &#name| root.#idx_lit.get(&key)),
2167 Box::new(move |_root: &mut #name| None),
2168 )
2169 }
2170 });
2171 }
2172 (WrapperKind::BTreeSet, Some(inner_ty)) | (WrapperKind::BTreeSetOption, Some(inner_ty)) => {
2173 let kp_at_fn = format_ident!("f{}_at", idx);
2174
2175 tokens.extend(quote! {
2176 #[inline(always)]
2177 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2178 rust_key_paths::Kp::new(
2179 |root: &#name| Some(&root.#idx_lit),
2180 |root: &mut #name| Some(&mut root.#idx_lit),
2181 )
2182 }
2183
2184 /// _at: check if element exists and get reference.
2185 /// BTreeSet does not allow mutable element access (would break ordering invariant).
2186 #[inline(always)]
2187 pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
2188 where
2189 #inner_ty: Clone + Ord + 'static,
2190 {
2191 rust_key_paths::Kp::new(
2192 Box::new(move |root: &#name| root.#idx_lit.get(&key)),
2193 Box::new(move |_root: &mut #name| None),
2194 )
2195 }
2196 });
2197 }
2198 (WrapperKind::VecDeque, Some(inner_ty)) | (WrapperKind::VecDequeOption, Some(inner_ty)) => {
2199 tokens.extend(quote! {
2200 #[inline(always)]
2201 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2202 rust_key_paths::Kp::new(
2203 |root: &#name| Some(&root.#idx_lit),
2204 |root: &mut #name| Some(&mut root.#idx_lit),
2205 )
2206 }
2207 #[inline(always)]
2208 pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
2209 rust_key_paths::Kp::new(
2210 Box::new(move |root: &#name| root.#idx_lit.get(index)),
2211 Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
2212 )
2213 }
2214 });
2215 }
2216 (WrapperKind::LinkedList, Some(_inner_ty)) | (WrapperKind::LinkedListOption, Some(_inner_ty)) => {
2217 tokens.extend(quote! {
2218 #[inline(always)]
2219 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2220 rust_key_paths::Kp::new(
2221 |root: &#name| Some(&root.#idx_lit),
2222 |root: &mut #name| Some(&mut root.#idx_lit),
2223 )
2224 }
2225 });
2226 }
2227 (WrapperKind::BinaryHeap, Some(_inner_ty)) | (WrapperKind::BinaryHeapOption, Some(_inner_ty)) => {
2228 tokens.extend(quote! {
2229 #[inline(always)]
2230 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2231 rust_key_paths::Kp::new(
2232 |root: &#name| Some(&root.#idx_lit),
2233 |root: &mut #name| Some(&mut root.#idx_lit),
2234 )
2235 }
2236 });
2237 }
2238 (WrapperKind::Result, Some(inner_ty)) => {
2239 tokens.extend(quote! {
2240 #[inline(always)]
2241 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2242 rust_key_paths::Kp::new(
2243 |root: &#name| root.#idx_lit.as_ref().ok(),
2244 |root: &mut #name| root.#idx_lit.as_mut().ok(),
2245 )
2246 }
2247 });
2248 }
2249 (WrapperKind::Mutex, Some(_inner_ty))
2250 | (WrapperKind::StdMutex, Some(_inner_ty)) => {
2251 tokens.extend(quote! {
2252 #[inline(always)]
2253 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2254 rust_key_paths::Kp::new(
2255 |root: &#name| Some(&root.#idx_lit),
2256 |root: &mut #name| Some(&mut root.#idx_lit),
2257 )
2258 }
2259 });
2260 }
2261 (WrapperKind::RwLock, Some(_inner_ty))
2262 | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
2263 tokens.extend(quote! {
2264 #[inline(always)]
2265 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2266 rust_key_paths::Kp::new(
2267 |root: &#name| Some(&root.#idx_lit),
2268 |root: &mut #name| Some(&mut root.#idx_lit),
2269 )
2270 }
2271 });
2272 }
2273 (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
2274 let kp_async_fn = format_ident!("f{}_kp", idx);
2275 tokens.extend(quote! {
2276 #[inline(always)]
2277 pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2278 rust_key_paths::Kp::new(
2279 |root: &#name| Some(&root.#idx_lit),
2280 |root: &mut #name| Some(&mut root.#idx_lit),
2281 )
2282 }
2283 pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
2284 rust_key_paths::async_lock::AsyncLockKp::new(
2285 rust_key_paths::Kp::new(
2286 |root: &#name| Some(&root.#idx_lit),
2287 |root: &mut #name| Some(&mut root.#idx_lit),
2288 ),
2289 rust_key_paths::async_lock::TokioMutexAccess::new(),
2290 rust_key_paths::Kp::new(
2291 |v: &#inner_ty| Some(v),
2292 |v: &mut #inner_ty| Some(v),
2293 ),
2294 )
2295 }
2296 });
2297 }
2298 (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
2299 let kp_async_fn = format_ident!("f{}_kp", idx);
2300 tokens.extend(quote! {
2301 #[inline(always)]
2302 pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2303 rust_key_paths::Kp::new(
2304 |root: &#name| Some(&root.#idx_lit),
2305 |root: &mut #name| Some(&mut root.#idx_lit),
2306 )
2307 }
2308 pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
2309 rust_key_paths::async_lock::AsyncLockKp::new(
2310 rust_key_paths::Kp::new(
2311 |root: &#name| Some(&root.#idx_lit),
2312 |root: &mut #name| Some(&mut root.#idx_lit),
2313 ),
2314 rust_key_paths::async_lock::TokioRwLockAccess::new(),
2315 rust_key_paths::Kp::new(
2316 |v: &#inner_ty| Some(v),
2317 |v: &mut #inner_ty| Some(v),
2318 ),
2319 )
2320 }
2321 });
2322 }
2323 (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
2324 let kp_async_fn = format_ident!("f{}_kp", idx);
2325 tokens.extend(quote! {
2326 #[inline(always)]
2327 pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2328 rust_key_paths::Kp::new(
2329 |root: &#name| Some(&root.#idx_lit),
2330 |root: &mut #name| Some(&mut root.#idx_lit),
2331 )
2332 }
2333 pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
2334 rust_key_paths::async_lock::AsyncLockKp::new(
2335 rust_key_paths::Kp::new(
2336 |root: &#name| root.#idx_lit.as_ref(),
2337 |root: &mut #name| root.#idx_lit.as_mut(),
2338 ),
2339 rust_key_paths::async_lock::TokioMutexAccess::new(),
2340 rust_key_paths::Kp::new(
2341 |v: &#inner_ty| Some(v),
2342 |v: &mut #inner_ty| Some(v),
2343 ),
2344 )
2345 }
2346 });
2347 }
2348 (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
2349 let kp_async_fn = format_ident!("f{}_kp", idx);
2350 tokens.extend(quote! {
2351 #[inline(always)]
2352 pub fn #kp_async_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2353 rust_key_paths::Kp::new(
2354 |root: &#name| Some(&root.#idx_lit),
2355 |root: &mut #name| Some(&mut root.#idx_lit),
2356 )
2357 }
2358 pub fn #kp_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
2359 rust_key_paths::async_lock::AsyncLockKp::new(
2360 rust_key_paths::Kp::new(
2361 |root: &#name| root.#idx_lit.as_ref(),
2362 |root: &mut #name| root.#idx_lit.as_mut(),
2363 ),
2364 rust_key_paths::async_lock::TokioRwLockAccess::new(),
2365 rust_key_paths::Kp::new(
2366 |v: &#inner_ty| Some(v),
2367 |v: &mut #inner_ty| Some(v),
2368 ),
2369 )
2370 }
2371 });
2372 }
2373 (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
2374 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2375 tokens.extend(quote! {
2376 #[inline(always)]
2377 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2378 rust_key_paths::Kp::new(
2379 |root: &#name| Some(&root.#idx_lit),
2380 |root: &mut #name| Some(&mut root.#idx_lit),
2381 )
2382 }
2383 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
2384 rust_key_paths::Kp::new(
2385 |root: &#name| root.#idx_lit.as_ref(),
2386 |root: &mut #name| root.#idx_lit.as_mut(),
2387 )
2388 }
2389 });
2390 }
2391 (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
2392 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2393 tokens.extend(quote! {
2394 #[inline(always)]
2395 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2396 rust_key_paths::Kp::new(
2397 |root: &#name| Some(&root.#idx_lit),
2398 |root: &mut #name| Some(&mut root.#idx_lit),
2399 )
2400 }
2401 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
2402 rust_key_paths::Kp::new(
2403 |root: &#name| root.#idx_lit.as_ref(),
2404 |root: &mut #name| root.#idx_lit.as_mut(),
2405 )
2406 }
2407 });
2408 }
2409 (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
2410 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2411 tokens.extend(quote! {
2412 #[inline(always)]
2413 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2414 rust_key_paths::Kp::new(
2415 |root: &#name| Some(&root.#idx_lit),
2416 |root: &mut #name| Some(&mut root.#idx_lit),
2417 )
2418 }
2419 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
2420 rust_key_paths::Kp::new(
2421 |root: &#name| root.#idx_lit.as_ref(),
2422 |root: &mut #name| root.#idx_lit.as_mut(),
2423 )
2424 }
2425 });
2426 }
2427 (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
2428 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2429 tokens.extend(quote! {
2430 #[inline(always)]
2431 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2432 rust_key_paths::Kp::new(
2433 |root: &#name| Some(&root.#idx_lit),
2434 |root: &mut #name| Some(&mut root.#idx_lit),
2435 )
2436 }
2437 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
2438 rust_key_paths::Kp::new(
2439 |root: &#name| root.#idx_lit.as_ref(),
2440 |root: &mut #name| root.#idx_lit.as_mut(),
2441 )
2442 }
2443 });
2444 }
2445 (WrapperKind::OptionStdMutex, Some(inner_ty))
2446 | (WrapperKind::OptionMutex, Some(inner_ty)) => {
2447 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2448 tokens.extend(quote! {
2449 #[inline(always)]
2450 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2451 rust_key_paths::Kp::new(
2452 |root: &#name| Some(&root.#idx_lit),
2453 |root: &mut #name| Some(&mut root.#idx_lit),
2454 )
2455 }
2456 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
2457 rust_key_paths::Kp::new(
2458 |root: &#name| root.#idx_lit.as_ref(),
2459 |root: &mut #name| root.#idx_lit.as_mut(),
2460 )
2461 }
2462 });
2463 }
2464 (WrapperKind::OptionStdRwLock, Some(inner_ty))
2465 | (WrapperKind::OptionRwLock, Some(inner_ty)) => {
2466 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2467 tokens.extend(quote! {
2468 #[inline(always)]
2469 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2470 rust_key_paths::Kp::new(
2471 |root: &#name| Some(&root.#idx_lit),
2472 |root: &mut #name| Some(&mut root.#idx_lit),
2473 )
2474 }
2475 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
2476 rust_key_paths::Kp::new(
2477 |root: &#name| root.#idx_lit.as_ref(),
2478 |root: &mut #name| root.#idx_lit.as_mut(),
2479 )
2480 }
2481 });
2482 }
2483 (WrapperKind::Weak, Some(_inner_ty)) => {
2484 tokens.extend(quote! {
2485 #[inline(always)]
2486 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2487 rust_key_paths::Kp::new(
2488 |root: &#name| Some(&root.#idx_lit),
2489 |_root: &mut #name| None,
2490 )
2491 }
2492 });
2493 }
2494 (WrapperKind::Atomic, None | Some(_)) => {
2495 tokens.extend(quote! {
2496 #[inline(always)]
2497 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2498 rust_key_paths::Kp::new(
2499 |root: &#name| Some(&root.#idx_lit),
2500 |root: &mut #name| Some(&mut root.#idx_lit),
2501 )
2502 }
2503 });
2504 }
2505 (WrapperKind::OptionAtomic, Some(inner_ty)) => {
2506 tokens.extend(quote! {
2507 #[inline(always)]
2508 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2509 rust_key_paths::Kp::new(
2510 |root: &#name| root.#idx_lit.as_ref(),
2511 |root: &mut #name| root.#idx_lit.as_mut(),
2512 )
2513 }
2514 });
2515 }
2516 (WrapperKind::String, None) => {
2517 tokens.extend(quote! {
2518 #[inline(always)]
2519 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2520 rust_key_paths::Kp::new(
2521 |root: &#name| Some(&root.#idx_lit),
2522 |root: &mut #name| Some(&mut root.#idx_lit),
2523 )
2524 }
2525 });
2526 }
2527 (WrapperKind::OptionString, None) => {
2528 tokens.extend(quote! {
2529 #[inline(always)]
2530 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, std::string::String> {
2531 rust_key_paths::Kp::new(
2532 |root: &#name| root.#idx_lit.as_ref(),
2533 |root: &mut #name| root.#idx_lit.as_mut(),
2534 )
2535 }
2536 });
2537 }
2538 (WrapperKind::OnceCell, Some(inner_ty)) => {
2539 tokens.extend(quote! {
2540 #[inline(always)]
2541 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2542 rust_key_paths::Kp::new(
2543 |root: &#name| root.#idx_lit.get(),
2544 |_root: &mut #name| None,
2545 )
2546 }
2547 });
2548 }
2549 (WrapperKind::Lazy, Some(inner_ty)) => {
2550 tokens.extend(quote! {
2551 #[inline(always)]
2552 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2553 rust_key_paths::Kp::new(
2554 |root: &#name| Some(root.#idx_lit.get()),
2555 |_root: &mut #name| None,
2556 )
2557 }
2558 });
2559 }
2560 (WrapperKind::OptionOnceCell, Some(inner_ty)) => {
2561 tokens.extend(quote! {
2562 #[inline(always)]
2563 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2564 rust_key_paths::Kp::new(
2565 |root: &#name| root.#idx_lit.as_ref().and_then(|c| c.get()),
2566 |_root: &mut #name| None,
2567 )
2568 }
2569 });
2570 }
2571 (WrapperKind::OptionLazy, Some(inner_ty)) => {
2572 tokens.extend(quote! {
2573 #[inline(always)]
2574 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2575 rust_key_paths::Kp::new(
2576 |root: &#name| root.#idx_lit.as_ref().map(|c| c.get()),
2577 |_root: &mut #name| None,
2578 )
2579 }
2580 });
2581 }
2582 (WrapperKind::Cell, Some(_inner_ty)) | (WrapperKind::RefCell, Some(_inner_ty))
2583 | (WrapperKind::PhantomData, Some(_inner_ty)) | (WrapperKind::Range, Some(_inner_ty))
2584 | (WrapperKind::OptionCell, Some(_inner_ty)) | (WrapperKind::OptionRefCell, Some(_inner_ty))
2585 | (WrapperKind::OptionPhantomData, Some(_inner_ty)) | (WrapperKind::OptionRange, Some(_inner_ty)) => {
2586 tokens.extend(quote! {
2587 #[inline(always)]
2588 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2589 rust_key_paths::Kp::new(
2590 |root: &#name| Some(&root.#idx_lit),
2591 |root: &mut #name| Some(&mut root.#idx_lit),
2592 )
2593 }
2594 });
2595 }
2596 (WrapperKind::Reference, Some(_inner_ty)) => {
2597 tokens.extend(quote! {
2598 #[inline(always)]
2599 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2600 rust_key_paths::Kp::new(
2601 |root: &#name| Some(&root.#idx_lit),
2602 |_root: &mut #name| None,
2603 )
2604 }
2605 });
2606 }
2607 (WrapperKind::None, None) => {
2608 tokens.extend(quote! {
2609 #[inline(always)]
2610 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2611 rust_key_paths::Kp::new(
2612 |root: &#name| Some(&root.#idx_lit),
2613 |root: &mut #name| Some(&mut root.#idx_lit),
2614 )
2615 }
2616 });
2617 }
2618 _ => {
2619 tokens.extend(quote! {
2620 #[inline(always)]
2621 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2622 rust_key_paths::Kp::new(
2623 |root: &#name| Some(&root.#idx_lit),
2624 |root: &mut #name| Some(&mut root.#idx_lit),
2625 )
2626 }
2627 });
2628 }
2629 }
2630 }
2631
2632 tokens
2633 }
2634 Fields::Unit => {
2635 return syn::Error::new(input_span, "Kp derive does not support unit structs")
2636 .to_compile_error()
2637 .into();
2638 }
2639 },
2640 Data::Enum(data_enum) => {
2641 let mut tokens = proc_macro2::TokenStream::new();
2642
2643 // Generate identity methods for the enum
2644 tokens.extend(quote! {
2645 /// Returns a generic identity keypath for this type
2646 #[inline(always)]
2647 pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
2648 #name,
2649 #name,
2650 Root,
2651 Root,
2652 MutRoot,
2653 MutRoot,
2654 fn(Root) -> Option<Root>,
2655 fn(MutRoot) -> Option<MutRoot>,
2656 >
2657 where
2658 Root: std::borrow::Borrow<#name>,
2659 MutRoot: std::borrow::BorrowMut<#name>,
2660 {
2661 rust_key_paths::Kp::new(
2662 |r: Root| Some(r),
2663 |r: MutRoot| Some(r)
2664 )
2665 }
2666
2667 /// Returns a simple identity keypath for this type
2668 #[inline(always)]
2669 pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
2670 rust_key_paths::Kp::new(
2671 |r: &#name| Some(r),
2672 |r: &mut #name| Some(r)
2673 )
2674 }
2675 });
2676
2677 for variant in data_enum.variants.iter() {
2678 let v_ident = &variant.ident;
2679 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
2680
2681 match &variant.fields {
2682 Fields::Unit => {
2683 // Unit variant - return keypath that checks if enum matches variant
2684 tokens.extend(quote! {
2685 #[inline(always)]
2686 pub fn #snake() -> rust_key_paths::KpType<'static, #name, ()> {
2687 rust_key_paths::Kp::new(
2688 |root: &#name| match root {
2689 #name::#v_ident => {
2690 static UNIT: () = ();
2691 Some(&UNIT)
2692 },
2693 _ => None,
2694 },
2695 |_root: &mut #name| None, // Can't mutate unit variant
2696 )
2697 }
2698 });
2699 }
2700 Fields::Unnamed(unnamed) => {
2701 if unnamed.unnamed.len() == 1 {
2702 // Single-field tuple variant
2703 let field_ty = &unnamed.unnamed[0].ty;
2704 let (kind, inner_ty) = extract_wrapper_inner_type(field_ty);
2705
2706 match (kind, inner_ty.clone()) {
2707 (WrapperKind::Option, Some(inner_ty)) => {
2708 tokens.extend(quote! {
2709 #[inline(always)]
2710 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2711 rust_key_paths::Kp::new(
2712 |root: &#name| match root {
2713 #name::#v_ident(inner) => inner.as_ref(),
2714 _ => None,
2715 },
2716 |root: &mut #name| match root {
2717 #name::#v_ident(inner) => inner.as_mut(),
2718 _ => None,
2719 },
2720 )
2721 }
2722 });
2723 }
2724 (WrapperKind::OptionVecDeque, Some(_inner_ty))
2725 | (WrapperKind::OptionLinkedList, Some(_inner_ty))
2726 | (WrapperKind::OptionBinaryHeap, Some(_inner_ty))
2727 | (WrapperKind::OptionHashSet, Some(_inner_ty))
2728 | (WrapperKind::OptionBTreeSet, Some(_inner_ty))
2729 | (WrapperKind::OptionResult, Some(_inner_ty))
2730 | (WrapperKind::OptionBTreeMap, Some(_inner_ty)) => {
2731 tokens.extend(quote! {
2732 #[inline(always)]
2733 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2734 rust_key_paths::Kp::new(
2735 |root: &#name| match root {
2736 #name::#v_ident(inner) => Some(inner),
2737 _ => None,
2738 },
2739 |root: &mut #name| match root {
2740 #name::#v_ident(inner) => Some(inner),
2741 _ => None,
2742 },
2743 )
2744 }
2745 });
2746 }
2747 (WrapperKind::Vec, Some(inner_ty)) => {
2748 tokens.extend(quote! {
2749 #[inline(always)]
2750 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2751 rust_key_paths::Kp::new(
2752 |root: &#name| match root {
2753 #name::#v_ident(inner) => inner.first(),
2754 _ => None,
2755 },
2756 |root: &mut #name| match root {
2757 #name::#v_ident(inner) => inner.first_mut(),
2758 _ => None,
2759 },
2760 )
2761 }
2762 });
2763 }
2764 (WrapperKind::Box, Some(inner_ty)) => {
2765 // Box in enum: deref to inner (&T / &mut T)
2766 tokens.extend(quote! {
2767 #[inline(always)]
2768 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2769 rust_key_paths::Kp::new(
2770 |root: &#name| match root {
2771 #name::#v_ident(inner) => Some(&**inner),
2772 _ => None,
2773 },
2774 |root: &mut #name| match root {
2775 #name::#v_ident(inner) => Some(&mut **inner),
2776 _ => None,
2777 },
2778 )
2779 }
2780 });
2781 }
2782 (WrapperKind::Pin, Some(inner_ty)) => {
2783 let snake_inner = format_ident!("{}_inner", snake);
2784 tokens.extend(quote! {
2785 #[inline(always)]
2786 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2787 rust_key_paths::Kp::new(
2788 |root: &#name| match root {
2789 #name::#v_ident(inner) => Some(inner),
2790 _ => None,
2791 },
2792 |root: &mut #name| match root {
2793 #name::#v_ident(inner) => Some(inner),
2794 _ => None,
2795 },
2796 )
2797 }
2798 #[inline(always)]
2799 pub fn #snake_inner() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2800 where #inner_ty: std::marker::Unpin
2801 {
2802 rust_key_paths::Kp::new(
2803 |root: &#name| match root {
2804 #name::#v_ident(inner) => Some(std::pin::Pin::as_ref(inner).get_ref()),
2805 _ => None,
2806 },
2807 |root: &mut #name| match root {
2808 #name::#v_ident(inner) => Some(std::pin::Pin::as_mut(inner).get_mut()),
2809 _ => None,
2810 },
2811 )
2812 }
2813 });
2814 }
2815 (WrapperKind::PinBox, Some(inner_ty)) => {
2816 let snake_inner = format_ident!("{}_inner", snake);
2817 tokens.extend(quote! {
2818 #[inline(always)]
2819 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2820 rust_key_paths::Kp::new(
2821 |root: &#name| match root {
2822 #name::#v_ident(inner) => Some(inner),
2823 _ => None,
2824 },
2825 |root: &mut #name| match root {
2826 #name::#v_ident(inner) => Some(inner),
2827 _ => None,
2828 },
2829 )
2830 }
2831 #[inline(always)]
2832 pub fn #snake_inner() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2833 where #inner_ty: std::marker::Unpin
2834 {
2835 rust_key_paths::Kp::new(
2836 |root: &#name| match root {
2837 #name::#v_ident(inner) => Some(std::pin::Pin::as_ref(inner).get_ref()),
2838 _ => None,
2839 },
2840 |root: &mut #name| match root {
2841 #name::#v_ident(inner) => Some(std::pin::Pin::as_mut(inner).get_mut()),
2842 _ => None,
2843 },
2844 )
2845 }
2846 });
2847 }
2848 (WrapperKind::Rc, Some(inner_ty)) => {
2849 tokens.extend(quote! {
2850 #[inline(always)]
2851 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2852 rust_key_paths::Kp::new(
2853 |root: &#name| match root {
2854 #name::#v_ident(inner) => Some(inner.as_ref()),
2855 _ => None,
2856 },
2857 |root: &mut #name| match root {
2858 #name::#v_ident(inner) => std::rc::Rc::get_mut(inner),
2859 _ => None,
2860 },
2861 )
2862 }
2863 });
2864 }
2865 (WrapperKind::Arc, Some(inner_ty)) => {
2866 tokens.extend(quote! {
2867 #[inline(always)]
2868 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2869 rust_key_paths::Kp::new(
2870 |root: &#name| match root {
2871 #name::#v_ident(inner) => Some(inner.as_ref()),
2872 _ => None,
2873 },
2874 |root: &mut #name| match root {
2875 #name::#v_ident(inner) => std::sync::Arc::get_mut(inner),
2876 _ => None,
2877 },
2878 )
2879 }
2880 });
2881 }
2882 (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
2883 let snake_lock = format_ident!("{}_lock", 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_lock() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #field_ty, #inner_ty> {
2899 rust_key_paths::lock::LockKp::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::lock::ArcRwLockAccess::new(),
2905 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2906 )
2907 }
2908 });
2909 }
2910 (WrapperKind::StdArcMutex, Some(inner_ty)) => {
2911 let snake_lock = format_ident!("{}_lock", 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_lock() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #field_ty, #inner_ty> {
2927 rust_key_paths::lock::LockKp::new(
2928 rust_key_paths::Kp::new(
2929 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2930 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2931 ),
2932 rust_key_paths::lock::ArcMutexAccess::new(),
2933 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2934 )
2935 }
2936 });
2937 }
2938 (WrapperKind::ArcRwLock, Some(inner_ty)) => {
2939 let snake_lock = format_ident!("{}_lock", 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_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #field_ty, #inner_ty> {
2955 rust_key_paths::lock::LockKp::new(
2956 rust_key_paths::Kp::new(
2957 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2958 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2959 ),
2960 rust_key_paths::lock::ParkingLotRwLockAccess::new(),
2961 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2962 )
2963 }
2964 });
2965 }
2966 (WrapperKind::ArcMutex, Some(inner_ty)) => {
2967 let snake_lock = format_ident!("{}_lock", snake);
2968 tokens.extend(quote! {
2969 #[inline(always)]
2970 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2971 rust_key_paths::Kp::new(
2972 |root: &#name| match root {
2973 #name::#v_ident(inner) => Some(inner),
2974 _ => None,
2975 },
2976 |root: &mut #name| match root {
2977 #name::#v_ident(inner) => Some(inner),
2978 _ => None,
2979 },
2980 )
2981 }
2982 pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #field_ty, #inner_ty> {
2983 rust_key_paths::lock::LockKp::new(
2984 rust_key_paths::Kp::new(
2985 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2986 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2987 ),
2988 rust_key_paths::lock::ParkingLotMutexAccess::new(),
2989 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2990 )
2991 }
2992 });
2993 }
2994 (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
2995 let snake_async = format_ident!("{}_kp", snake);
2996 tokens.extend(quote! {
2997 #[inline(always)]
2998 pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2999 rust_key_paths::Kp::new(
3000 |root: &#name| match root {
3001 #name::#v_ident(inner) => Some(inner),
3002 _ => None,
3003 },
3004 |root: &mut #name| match root {
3005 #name::#v_ident(inner) => Some(inner),
3006 _ => None,
3007 },
3008 )
3009 }
3010 pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #field_ty, #inner_ty> {
3011 rust_key_paths::async_lock::AsyncLockKp::new(
3012 rust_key_paths::Kp::new(
3013 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3014 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3015 ),
3016 rust_key_paths::async_lock::TokioMutexAccess::new(),
3017 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3018 )
3019 }
3020 });
3021 }
3022 (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
3023 let snake_async = format_ident!("{}_kp", snake);
3024 tokens.extend(quote! {
3025 #[inline(always)]
3026 pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3027 rust_key_paths::Kp::new(
3028 |root: &#name| match root {
3029 #name::#v_ident(inner) => Some(inner),
3030 _ => None,
3031 },
3032 |root: &mut #name| match root {
3033 #name::#v_ident(inner) => Some(inner),
3034 _ => None,
3035 },
3036 )
3037 }
3038 pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #field_ty, #inner_ty> {
3039 rust_key_paths::async_lock::AsyncLockKp::new(
3040 rust_key_paths::Kp::new(
3041 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3042 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
3043 ),
3044 rust_key_paths::async_lock::TokioRwLockAccess::new(),
3045 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3046 )
3047 }
3048 });
3049 }
3050 (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
3051 let snake_async = format_ident!("{}_kp", snake);
3052 tokens.extend(quote! {
3053 #[inline(always)]
3054 pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3055 rust_key_paths::Kp::new(
3056 |root: &#name| match root {
3057 #name::#v_ident(inner) => Some(inner),
3058 _ => None,
3059 },
3060 |root: &mut #name| match root {
3061 #name::#v_ident(inner) => Some(inner),
3062 _ => None,
3063 },
3064 )
3065 }
3066 pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
3067 rust_key_paths::async_lock::AsyncLockKp::new(
3068 rust_key_paths::Kp::new(
3069 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3070 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3071 ),
3072 rust_key_paths::async_lock::TokioMutexAccess::new(),
3073 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3074 )
3075 }
3076 });
3077 }
3078 (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
3079 let snake_async = format_ident!("{}_kp", snake);
3080 tokens.extend(quote! {
3081 #[inline(always)]
3082 pub fn #snake_async() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3083 rust_key_paths::Kp::new(
3084 |root: &#name| match root {
3085 #name::#v_ident(inner) => Some(inner),
3086 _ => None,
3087 },
3088 |root: &mut #name| match root {
3089 #name::#v_ident(inner) => Some(inner),
3090 _ => None,
3091 },
3092 )
3093 }
3094 pub fn #snake() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
3095 rust_key_paths::async_lock::AsyncLockKp::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::async_lock::TokioRwLockAccess::new(),
3101 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3102 )
3103 }
3104 });
3105 }
3106 (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
3107 let snake_unlocked = format_ident!("{}_unlocked", snake);
3108 let snake_lock = format_ident!("{}_lock", snake);
3109 tokens.extend(quote! {
3110 #[inline(always)]
3111 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3112 rust_key_paths::Kp::new(
3113 |root: &#name| match root {
3114 #name::#v_ident(inner) => Some(inner),
3115 _ => None,
3116 },
3117 |root: &mut #name| match root {
3118 #name::#v_ident(inner) => Some(inner),
3119 _ => None,
3120 },
3121 )
3122 }
3123 pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
3124 rust_key_paths::Kp::new(
3125 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3126 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3127 )
3128 }
3129 pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
3130 rust_key_paths::lock::LockKp::new(
3131 rust_key_paths::Kp::new(
3132 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3133 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3134 ),
3135 rust_key_paths::lock::ArcMutexAccess::new(),
3136 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3137 )
3138 }
3139 });
3140 }
3141 (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
3142 let snake_unlocked = format_ident!("{}_unlocked", snake);
3143 let snake_lock = format_ident!("{}_lock", snake);
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 pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
3159 rust_key_paths::Kp::new(
3160 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3161 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3162 )
3163 }
3164 pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>, #inner_ty> {
3165 rust_key_paths::lock::LockKp::new(
3166 rust_key_paths::Kp::new(
3167 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3168 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3169 ),
3170 rust_key_paths::lock::ParkingLotMutexAccess::new(),
3171 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3172 )
3173 }
3174 });
3175 }
3176 (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
3177 let snake_unlocked = format_ident!("{}_unlocked", snake);
3178 let snake_lock = format_ident!("{}_lock", snake);
3179 tokens.extend(quote! {
3180 #[inline(always)]
3181 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3182 rust_key_paths::Kp::new(
3183 |root: &#name| match root {
3184 #name::#v_ident(inner) => Some(inner),
3185 _ => None,
3186 },
3187 |root: &mut #name| match root {
3188 #name::#v_ident(inner) => Some(inner),
3189 _ => None,
3190 },
3191 )
3192 }
3193 pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
3194 rust_key_paths::Kp::new(
3195 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3196 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3197 )
3198 }
3199 pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
3200 rust_key_paths::lock::LockKp::new(
3201 rust_key_paths::Kp::new(
3202 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3203 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3204 ),
3205 rust_key_paths::lock::ArcRwLockAccess::new(),
3206 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3207 )
3208 }
3209 });
3210 }
3211 (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
3212 let snake_unlocked = format_ident!("{}_unlocked", snake);
3213 let snake_lock = format_ident!("{}_lock", snake);
3214 tokens.extend(quote! {
3215 #[inline(always)]
3216 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3217 rust_key_paths::Kp::new(
3218 |root: &#name| match root {
3219 #name::#v_ident(inner) => Some(inner),
3220 _ => None,
3221 },
3222 |root: &mut #name| match root {
3223 #name::#v_ident(inner) => Some(inner),
3224 _ => None,
3225 },
3226 )
3227 }
3228 pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
3229 rust_key_paths::Kp::new(
3230 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3231 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3232 )
3233 }
3234 pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>, #inner_ty> {
3235 rust_key_paths::lock::LockKp::new(
3236 rust_key_paths::Kp::new(
3237 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3238 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3239 ),
3240 rust_key_paths::lock::ParkingLotRwLockAccess::new(),
3241 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
3242 )
3243 }
3244 });
3245 }
3246 (WrapperKind::StdMutex, Some(_inner_ty))
3247 | (WrapperKind::Mutex, Some(_inner_ty))
3248 | (WrapperKind::StdRwLock, Some(_inner_ty))
3249 | (WrapperKind::RwLock, Some(_inner_ty)) => {
3250 tokens.extend(quote! {
3251 #[inline(always)]
3252 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3253 rust_key_paths::Kp::new(
3254 |root: &#name| match root {
3255 #name::#v_ident(inner) => Some(inner),
3256 _ => None,
3257 },
3258 |root: &mut #name| match root {
3259 #name::#v_ident(inner) => Some(inner),
3260 _ => None,
3261 },
3262 )
3263 }
3264 });
3265 }
3266 (WrapperKind::Tagged, Some(inner_ty)) => {
3267 tokens.extend(quote! {
3268 #[inline(always)]
3269 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3270 rust_key_paths::Kp::new(
3271 |root: &#name| match root {
3272 #name::#v_ident(inner) => Some(std::ops::Deref::deref(inner)),
3273 _ => None,
3274 },
3275 |root: &mut #name| match root {
3276 #name::#v_ident(inner) => Some(std::ops::DerefMut::deref_mut(inner)),
3277 _ => None,
3278 },
3279 )
3280 }
3281 });
3282 }
3283 (WrapperKind::Atomic, None | Some(_)) => {
3284 tokens.extend(quote! {
3285 #[inline(always)]
3286 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3287 rust_key_paths::Kp::new(
3288 |root: &#name| match root {
3289 #name::#v_ident(inner) => Some(inner),
3290 _ => None,
3291 },
3292 |root: &mut #name| match root {
3293 #name::#v_ident(inner) => Some(inner),
3294 _ => None,
3295 },
3296 )
3297 }
3298 });
3299 }
3300 (WrapperKind::OptionAtomic, Some(inner_ty)) => {
3301 tokens.extend(quote! {
3302 #[inline(always)]
3303 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3304 rust_key_paths::Kp::new(
3305 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
3306 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
3307 )
3308 }
3309 });
3310 }
3311 (WrapperKind::Reference, Some(_inner_ty)) => {
3312 tokens.extend(quote! {
3313 #[inline(always)]
3314 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3315 rust_key_paths::Kp::new(
3316 |root: &#name| match root {
3317 #name::#v_ident(inner) => Some(inner),
3318 _ => None,
3319 },
3320 |_root: &mut #name| None,
3321 )
3322 }
3323 });
3324 }
3325 (WrapperKind::Weak, Some(_inner_ty)) => {
3326 tokens.extend(quote! {
3327 #[inline(always)]
3328 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3329 rust_key_paths::Kp::new(
3330 |root: &#name| match root {
3331 #name::#v_ident(inner) => Some(inner),
3332 _ => None,
3333 },
3334 |_root: &mut #name| None,
3335 )
3336 }
3337 });
3338 }
3339 (WrapperKind::Cow, Some(inner_ty)) => {
3340 tokens.extend(quote! {
3341 #[inline(always)]
3342 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3343 rust_key_paths::Kp::new(
3344 |root: &#name| match root {
3345 #name::#v_ident(inner) => Some(inner.as_ref()),
3346 _ => None,
3347 },
3348 |root: &mut #name| match root {
3349 #name::#v_ident(inner) => Some(inner.to_mut()),
3350 _ => None,
3351 },
3352 )
3353 }
3354 });
3355 }
3356 (WrapperKind::OptionBox, Some(inner_ty)) => {
3357 // Option<Box<T>>: keypath to T via as_deref() / as_deref_mut()
3358 tokens.extend(quote! {
3359 #[inline(always)]
3360 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3361 rust_key_paths::Kp::new(
3362 |root: &#name| match root {
3363 #name::#v_ident(inner) => inner.as_deref(),
3364 _ => None,
3365 },
3366 |root: &mut #name| match root {
3367 #name::#v_ident(inner) => inner.as_deref_mut(),
3368 _ => None,
3369 },
3370 )
3371 }
3372 });
3373 }
3374 (WrapperKind::BoxOption, Some(inner_ty)) => {
3375 // Box<Option<T>>: keypath to T; inner is &Box<Option<T>>, deref then Option::as_ref/as_mut
3376 tokens.extend(quote! {
3377 #[inline(always)]
3378 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3379 rust_key_paths::Kp::new(
3380 |root: &#name| match root {
3381 #name::#v_ident(inner) => (&*inner).as_ref(),
3382 _ => None,
3383 },
3384 |root: &mut #name| match root {
3385 #name::#v_ident(inner) => (&mut *inner).as_mut(),
3386 _ => None,
3387 },
3388 )
3389 }
3390 });
3391 }
3392 (WrapperKind::RcOption, Some(inner_ty)) => {
3393 // Rc<Option<T>>: keypath to T; get = (&*inner).as_ref(), set = Rc::get_mut then as_mut
3394 tokens.extend(quote! {
3395 #[inline(always)]
3396 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3397 rust_key_paths::Kp::new(
3398 |root: &#name| match root {
3399 #name::#v_ident(inner) => (&*inner).as_ref(),
3400 _ => None,
3401 },
3402 |root: &mut #name| match root {
3403 #name::#v_ident(inner) => std::rc::Rc::get_mut(inner).and_then(std::option::Option::as_mut),
3404 _ => None,
3405 },
3406 )
3407 }
3408 });
3409 }
3410 (WrapperKind::ArcOption, Some(inner_ty)) => {
3411 // Arc<Option<T>>: keypath to T; get = (&*inner).as_ref(), set = Arc::get_mut then as_mut
3412 tokens.extend(quote! {
3413 #[inline(always)]
3414 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3415 rust_key_paths::Kp::new(
3416 |root: &#name| match root {
3417 #name::#v_ident(inner) => (&*inner).as_ref(),
3418 _ => None,
3419 },
3420 |root: &mut #name| match root {
3421 #name::#v_ident(inner) => std::sync::Arc::get_mut(inner).and_then(std::option::Option::as_mut),
3422 _ => None,
3423 },
3424 )
3425 }
3426 });
3427 }
3428 (WrapperKind::OptionRc, Some(inner_ty)) => {
3429 tokens.extend(quote! {
3430 #[inline(always)]
3431 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3432 rust_key_paths::Kp::new(
3433 |root: &#name| match root {
3434 #name::#v_ident(inner) => inner.as_deref(),
3435 _ => None,
3436 },
3437 |root: &mut #name| match root {
3438 #name::#v_ident(inner) => inner.as_mut().and_then(std::rc::Rc::get_mut),
3439 _ => None,
3440 },
3441 )
3442 }
3443 });
3444 }
3445 (WrapperKind::OptionArc, Some(inner_ty)) => {
3446 tokens.extend(quote! {
3447 #[inline(always)]
3448 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3449 rust_key_paths::Kp::new(
3450 |root: &#name| match root {
3451 #name::#v_ident(inner) => inner.as_deref(),
3452 _ => None,
3453 },
3454 |root: &mut #name| match root {
3455 #name::#v_ident(inner) => inner.as_mut().and_then(std::sync::Arc::get_mut),
3456 _ => None,
3457 },
3458 )
3459 }
3460 });
3461 }
3462 (WrapperKind::OptionCow, Some(inner_ty)) => {
3463 tokens.extend(quote! {
3464 #[inline(always)]
3465 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3466 rust_key_paths::Kp::new(
3467 |root: &#name| match root {
3468 #name::#v_ident(inner) => inner.as_ref().map(|c| c.as_ref()),
3469 _ => None,
3470 },
3471 |root: &mut #name| match root {
3472 #name::#v_ident(inner) => inner.as_mut().map(|c| c.to_mut()),
3473 _ => None,
3474 },
3475 )
3476 }
3477 });
3478 }
3479 (WrapperKind::OptionTagged, Some(inner_ty)) => {
3480 tokens.extend(quote! {
3481 #[inline(always)]
3482 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3483 rust_key_paths::Kp::new(
3484 |root: &#name| match root {
3485 #name::#v_ident(inner) => inner.as_ref().map(|t| std::ops::Deref::deref(t)),
3486 _ => None,
3487 },
3488 |root: &mut #name| match root {
3489 #name::#v_ident(inner) => inner.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
3490 _ => None,
3491 },
3492 )
3493 }
3494 });
3495 }
3496 (WrapperKind::OptionReference, Some(inner_ty)) => {
3497 tokens.extend(quote! {
3498 #[inline(always)]
3499 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3500 rust_key_paths::Kp::new(
3501 |root: &#name| match root {
3502 #name::#v_ident(inner) => inner.as_ref(),
3503 _ => None,
3504 },
3505 |_root: &mut #name| None,
3506 )
3507 }
3508 });
3509 }
3510 (WrapperKind::String, None) => {
3511 tokens.extend(quote! {
3512 #[inline(always)]
3513 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3514 rust_key_paths::Kp::new(
3515 |root: &#name| match root {
3516 #name::#v_ident(inner) => Some(inner),
3517 _ => None,
3518 },
3519 |root: &mut #name| match root {
3520 #name::#v_ident(inner) => Some(inner),
3521 _ => None,
3522 },
3523 )
3524 }
3525 });
3526 }
3527 (WrapperKind::OptionString, None) => {
3528 tokens.extend(quote! {
3529 #[inline(always)]
3530 pub fn #snake() -> rust_key_paths::KpType<'static, #name, std::string::String> {
3531 rust_key_paths::Kp::new(
3532 |root: &#name| match root {
3533 #name::#v_ident(inner) => inner.as_ref(),
3534 _ => None,
3535 },
3536 |root: &mut #name| match root {
3537 #name::#v_ident(inner) => inner.as_mut(),
3538 _ => None,
3539 },
3540 )
3541 }
3542 });
3543 }
3544 (WrapperKind::OnceCell, Some(inner_ty)) => {
3545 tokens.extend(quote! {
3546 #[inline(always)]
3547 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3548 rust_key_paths::Kp::new(
3549 |root: &#name| match root {
3550 #name::#v_ident(inner) => inner.get(),
3551 _ => None,
3552 },
3553 |_root: &mut #name| None,
3554 )
3555 }
3556 });
3557 }
3558 (WrapperKind::Lazy, Some(inner_ty)) => {
3559 tokens.extend(quote! {
3560 #[inline(always)]
3561 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3562 rust_key_paths::Kp::new(
3563 |root: &#name| match root {
3564 #name::#v_ident(inner) => Some(inner.get()),
3565 _ => None,
3566 },
3567 |_root: &mut #name| None,
3568 )
3569 }
3570 });
3571 }
3572 (WrapperKind::OptionOnceCell, Some(inner_ty)) => {
3573 tokens.extend(quote! {
3574 #[inline(always)]
3575 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3576 rust_key_paths::Kp::new(
3577 |root: &#name| match root {
3578 #name::#v_ident(inner) => inner.as_ref().and_then(|c| c.get()),
3579 _ => None,
3580 },
3581 |_root: &mut #name| None,
3582 )
3583 }
3584 });
3585 }
3586 (WrapperKind::OptionLazy, Some(inner_ty)) => {
3587 tokens.extend(quote! {
3588 #[inline(always)]
3589 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
3590 rust_key_paths::Kp::new(
3591 |root: &#name| match root {
3592 #name::#v_ident(inner) => inner.as_ref().map(|c| c.get()),
3593 _ => None,
3594 },
3595 |_root: &mut #name| None,
3596 )
3597 }
3598 });
3599 }
3600 (WrapperKind::Cell, Some(_inner_ty)) | (WrapperKind::RefCell, Some(_inner_ty))
3601 | (WrapperKind::PhantomData, Some(_inner_ty)) | (WrapperKind::Range, Some(_inner_ty))
3602 | (WrapperKind::OptionCell, Some(_inner_ty)) | (WrapperKind::OptionRefCell, Some(_inner_ty))
3603 | (WrapperKind::OptionPhantomData, Some(_inner_ty)) | (WrapperKind::OptionRange, Some(_inner_ty)) => {
3604 tokens.extend(quote! {
3605 #[inline(always)]
3606 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3607 rust_key_paths::Kp::new(
3608 |root: &#name| match root {
3609 #name::#v_ident(inner) => Some(inner),
3610 _ => None,
3611 },
3612 |root: &mut #name| match root {
3613 #name::#v_ident(inner) => Some(inner),
3614 _ => None,
3615 },
3616 )
3617 }
3618 });
3619 }
3620 (WrapperKind::None, None) => {
3621 // Basic type
3622 tokens.extend(quote! {
3623 #[inline(always)]
3624 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3625 rust_key_paths::Kp::new(
3626 |root: &#name| match root {
3627 #name::#v_ident(inner) => Some(inner),
3628 _ => None,
3629 },
3630 |root: &mut #name| match root {
3631 #name::#v_ident(inner) => Some(inner),
3632 _ => None,
3633 },
3634 )
3635 }
3636 });
3637 }
3638 _ => {
3639 // Other wrapper types - return keypath to field
3640 tokens.extend(quote! {
3641 #[inline(always)]
3642 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
3643 rust_key_paths::Kp::new(
3644 |root: &#name| match root {
3645 #name::#v_ident(inner) => Some(inner),
3646 _ => None,
3647 },
3648 |root: &mut #name| match root {
3649 #name::#v_ident(inner) => Some(inner),
3650 _ => None,
3651 },
3652 )
3653 }
3654 });
3655 }
3656 }
3657 } else {
3658 // Multi-field tuple variant - return keypath to variant itself
3659 tokens.extend(quote! {
3660 #[inline(always)]
3661 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
3662 rust_key_paths::Kp::new(
3663 |root: &#name| match root {
3664 #name::#v_ident(..) => Some(root),
3665 _ => None,
3666 },
3667 |root: &mut #name| match root {
3668 #name::#v_ident(..) => Some(root),
3669 _ => None,
3670 },
3671 )
3672 }
3673 });
3674 }
3675 }
3676 Fields::Named(_) => {
3677 // Named field variant - return keypath to variant itself
3678 tokens.extend(quote! {
3679 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
3680 rust_key_paths::Kp::new(
3681 |root: &#name| match root {
3682 #name::#v_ident { .. } => Some(root),
3683 _ => None,
3684 },
3685 |root: &mut #name| match root {
3686 #name::#v_ident { .. } => Some(root),
3687 _ => None,
3688 },
3689 )
3690 }
3691 });
3692 }
3693 }
3694 }
3695
3696 tokens
3697 }
3698 Data::Union(_) => {
3699 return syn::Error::new(input_span, "Kp derive does not support unions")
3700 .to_compile_error()
3701 .into();
3702 }
3703 };
3704
3705 let expanded = quote! {
3706 impl #name {
3707 #methods
3708 }
3709 };
3710
3711 TokenStream::from(expanded)
3712}
3713
3714/// Derive macro that generates `partial_kps() -> Vec<PKp<Self>>` returning all field/variant keypaths.
3715/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
3716///
3717/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
3718/// (using the same methods Kp generates, e.g. `some_variant()`).
3719///
3720/// # Example
3721/// ```
3722/// use key_paths_derive::{Kp, Pkp};
3723/// use rust_key_paths::PKp;
3724///
3725/// #[derive(Kp, Pkp)]
3726/// struct Person {
3727/// name: String,
3728/// age: i32,
3729/// }
3730///
3731/// let kps = Person::partial_kps();
3732/// assert_eq!(kps.len(), 2);
3733/// ```
3734#[proc_macro_derive(Pkp)]
3735pub fn derive_partial_keypaths(input: TokenStream) -> TokenStream {
3736 let input = parse_macro_input!(input as DeriveInput);
3737 let name = &input.ident;
3738
3739 let kp_calls = match &input.data {
3740 Data::Struct(data_struct) => match &data_struct.fields {
3741 Fields::Named(fields_named) => {
3742 let calls: Vec<_> = fields_named
3743 .named
3744 .iter()
3745 .filter_map(|f| f.ident.as_ref())
3746 .map(|field_ident| {
3747 quote! { rust_key_paths::PKp::new(Self::#field_ident()) }
3748 })
3749 .collect();
3750 quote! { #(#calls),* }
3751 }
3752 Fields::Unnamed(unnamed) => {
3753 let calls: Vec<_> = (0..unnamed.unnamed.len())
3754 .map(|idx| {
3755 let kp_fn = format_ident!("f{}", idx);
3756 quote! { rust_key_paths::PKp::new(Self::#kp_fn()) }
3757 })
3758 .collect();
3759 quote! { #(#calls),* }
3760 }
3761 Fields::Unit => quote! {},
3762 },
3763 Data::Enum(data_enum) => {
3764 let calls: Vec<_> = data_enum
3765 .variants
3766 .iter()
3767 .map(|variant| {
3768 let v_ident = &variant.ident;
3769 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
3770 quote! { rust_key_paths::PKp::new(Self::#snake()) }
3771 })
3772 .collect();
3773 quote! { #(#calls),* }
3774 }
3775 Data::Union(_) => {
3776 return syn::Error::new(
3777 input.ident.span(),
3778 "Pkp derive does not support unions",
3779 )
3780 .to_compile_error()
3781 .into();
3782 }
3783 };
3784
3785 let expanded = quote! {
3786 impl #name {
3787 /// Returns a vec of all field keypaths as partial keypaths (type-erased).
3788 #[inline(always)]
3789 pub fn partial_kps() -> Vec<rust_key_paths::PKp<#name>> {
3790 vec![#kp_calls]
3791 }
3792 }
3793 };
3794
3795 TokenStream::from(expanded)
3796}
3797
3798/// Derive macro that generates `any_kps() -> Vec<AKp>` returning all field/variant keypaths as any keypaths.
3799/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
3800/// AKp type-erases both Root and Value, enabling heterogeneous collections of keypaths.
3801///
3802/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
3803/// (using the same methods Kp generates, e.g. `some_variant()`).
3804///
3805/// # Example
3806/// ```
3807/// use key_paths_derive::{Kp, Akp};
3808/// use rust_key_paths::AKp;
3809///
3810/// #[derive(Kp, Akp)]
3811/// struct Person {
3812/// name: String,
3813/// age: i32,
3814/// }
3815///
3816/// let kps = Person::any_kps();
3817/// assert_eq!(kps.len(), 2);
3818/// let person = Person { name: "Alice".into(), age: 30 };
3819/// let name: Option<&String> = kps[0].get(&person as &dyn std::any::Any).and_then(|v| v.downcast_ref());
3820/// assert_eq!(name, Some(&"Alice".to_string()));
3821/// ```
3822#[proc_macro_derive(Akp)]
3823pub fn derive_any_keypaths(input: TokenStream) -> TokenStream {
3824 let input = parse_macro_input!(input as DeriveInput);
3825 let name = &input.ident;
3826
3827 let kp_calls = match &input.data {
3828 Data::Struct(data_struct) => match &data_struct.fields {
3829 Fields::Named(fields_named) => {
3830 let calls: Vec<_> = fields_named
3831 .named
3832 .iter()
3833 .filter_map(|f| f.ident.as_ref())
3834 .map(|field_ident| {
3835 quote! { rust_key_paths::AKp::new(Self::#field_ident()) }
3836 })
3837 .collect();
3838 quote! { #(#calls),* }
3839 }
3840 Fields::Unnamed(unnamed) => {
3841 let calls: Vec<_> = (0..unnamed.unnamed.len())
3842 .map(|idx| {
3843 let kp_fn = format_ident!("f{}", idx);
3844 quote! { rust_key_paths::AKp::new(Self::#kp_fn()) }
3845 })
3846 .collect();
3847 quote! { #(#calls),* }
3848 }
3849 Fields::Unit => quote! {},
3850 },
3851 Data::Enum(data_enum) => {
3852 let calls: Vec<_> = data_enum
3853 .variants
3854 .iter()
3855 .map(|variant| {
3856 let v_ident = &variant.ident;
3857 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
3858 quote! { rust_key_paths::AKp::new(Self::#snake()) }
3859 })
3860 .collect();
3861 quote! { #(#calls),* }
3862 }
3863 Data::Union(_) => {
3864 return syn::Error::new(
3865 input.ident.span(),
3866 "Akp derive does not support unions",
3867 )
3868 .to_compile_error()
3869 .into();
3870 }
3871 };
3872
3873 let expanded = quote! {
3874 impl #name {
3875 /// Returns a vec of all field keypaths as any keypaths (fully type-erased).
3876 #[inline(always)]
3877 pub fn any_kps() -> Vec<rust_key_paths::AKp> {
3878 vec![#kp_calls]
3879 }
3880 }
3881 };
3882
3883 TokenStream::from(expanded)
3884}