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