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