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