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