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