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