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