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