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