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)
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))
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).clone())
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).clone()))
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 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
1028 // Only providing container-level access
1029 push_method(
1030 &mut tokens,
1031 method_scope,
1032 MethodKind::Owned,
1033 quote! {
1034 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1035 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1036 }
1037 },
1038 );
1039 }
1040 (WrapperKind::RwLock, Some(_inner_ty)) => {
1041 push_method(
1042 &mut tokens,
1043 method_scope,
1044 MethodKind::Readable,
1045 quote! {
1046 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1047 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1048 }
1049 },
1050 );
1051 push_method(
1052 &mut tokens,
1053 method_scope,
1054 MethodKind::Writable,
1055 quote! {
1056 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1057 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
1058 }
1059 },
1060 );
1061 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
1062 // Only providing container-level access
1063 push_method(
1064 &mut tokens,
1065 method_scope,
1066 MethodKind::Owned,
1067 quote! {
1068 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1069 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1070 }
1071 },
1072 );
1073 }
1074 (WrapperKind::ArcMutex, Some(_inner_ty)) => {
1075 push_method(
1076 &mut tokens,
1077 method_scope,
1078 MethodKind::Readable,
1079 quote! {
1080 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1081 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1082 }
1083 },
1084 );
1085 // Note: Arc<Mutex<T>> doesn't support writable access (Arc is immutable)
1086 // Note: Arc<Mutex<T>> doesn't support direct access to inner type due to lifetime constraints
1087 // Only providing container-level access
1088 push_method(
1089 &mut tokens,
1090 method_scope,
1091 MethodKind::Owned,
1092 quote! {
1093 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1094 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1095 }
1096 },
1097 );
1098 }
1099 (WrapperKind::ArcRwLock, Some(_inner_ty)) => {
1100 push_method(
1101 &mut tokens,
1102 method_scope,
1103 MethodKind::Readable,
1104 quote! {
1105 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1106 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1107 }
1108 },
1109 );
1110 // Note: Arc<RwLock<T>> doesn't support writable access (Arc is immutable)
1111 // Note: Arc<RwLock<T>> doesn't support direct access to inner type due to lifetime constraints
1112 // Only providing container-level access
1113 push_method(
1114 &mut tokens,
1115 method_scope,
1116 MethodKind::Owned,
1117 quote! {
1118 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1119 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1120 }
1121 },
1122 );
1123 }
1124 (WrapperKind::Weak, Some(_inner_ty)) => {
1125 push_method(
1126 &mut tokens,
1127 method_scope,
1128 MethodKind::Readable,
1129 quote! {
1130 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1131 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1132 }
1133 },
1134 );
1135 // Note: Weak<T> doesn't support writable access (it's immutable)
1136 // Note: Weak<T> doesn't support direct access to inner type due to lifetime constraints
1137 // Only providing container-level access
1138 push_method(
1139 &mut tokens,
1140 method_scope,
1141 MethodKind::Owned,
1142 quote! {
1143 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1144 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1145 }
1146 },
1147 );
1148 }
1149 // Nested container combinations
1150 (WrapperKind::OptionBox, Some(inner_ty)) => {
1151 push_method(
1152 &mut tokens,
1153 method_scope,
1154 MethodKind::Readable,
1155 quote! {
1156 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1157 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1158 }
1159 },
1160 );
1161 let inner_ty_fr = inner_ty.clone();
1162 push_method(
1163 &mut tokens,
1164 method_scope,
1165 MethodKind::Readable,
1166 quote! {
1167 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
1168 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref().map(|b| &**b))
1169 }
1170 },
1171 );
1172 push_method(
1173 &mut tokens,
1174 method_scope,
1175 MethodKind::Writable,
1176 quote! {
1177 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1178 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
1179 }
1180 },
1181 );
1182 let inner_ty_fw = inner_ty.clone();
1183 push_method(
1184 &mut tokens,
1185 method_scope,
1186 MethodKind::Writable,
1187 quote! {
1188 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
1189 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut().map(|b| &mut **b))
1190 }
1191 },
1192 );
1193 push_method(
1194 &mut tokens,
1195 method_scope,
1196 MethodKind::Owned,
1197 quote! {
1198 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1199 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1200 }
1201 },
1202 );
1203 let inner_ty_fo = inner_ty.clone();
1204 push_method(
1205 &mut tokens,
1206 method_scope,
1207 MethodKind::Owned,
1208 quote! {
1209 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
1210 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.map(|b| *b))
1211 }
1212 },
1213 );
1214 }
1215 (WrapperKind::OptionRc, Some(inner_ty)) => {
1216 push_method(
1217 &mut tokens,
1218 method_scope,
1219 MethodKind::Readable,
1220 quote! {
1221 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1222 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1223 }
1224 },
1225 );
1226 let inner_ty_fr = inner_ty.clone();
1227 push_method(
1228 &mut tokens,
1229 method_scope,
1230 MethodKind::Readable,
1231 quote! {
1232 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
1233 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref().map(|r| &**r))
1234 }
1235 },
1236 );
1237 push_method(
1238 &mut tokens,
1239 method_scope,
1240 MethodKind::Owned,
1241 quote! {
1242 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1243 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1244 }
1245 },
1246 );
1247 let inner_ty_fo = inner_ty.clone();
1248 push_method(
1249 &mut tokens,
1250 method_scope,
1251 MethodKind::Owned,
1252 quote! {
1253 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
1254 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.map(|r| (*r).clone()))
1255 }
1256 },
1257 );
1258 }
1259 (WrapperKind::OptionArc, Some(inner_ty)) => {
1260 push_method(
1261 &mut tokens,
1262 method_scope,
1263 MethodKind::Readable,
1264 quote! {
1265 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1266 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1267 }
1268 },
1269 );
1270 let inner_ty_fr = inner_ty.clone();
1271 push_method(
1272 &mut tokens,
1273 method_scope,
1274 MethodKind::Readable,
1275 quote! {
1276 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
1277 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref().map(|a| &**a))
1278 }
1279 },
1280 );
1281 push_method(
1282 &mut tokens,
1283 method_scope,
1284 MethodKind::Owned,
1285 quote! {
1286 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1287 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1288 }
1289 },
1290 );
1291 let inner_ty_fo = inner_ty.clone();
1292 push_method(
1293 &mut tokens,
1294 method_scope,
1295 MethodKind::Owned,
1296 quote! {
1297 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
1298 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.map(|a| (*a).clone()))
1299 }
1300 },
1301 );
1302 }
1303 (WrapperKind::BoxOption, Some(inner_ty)) => {
1304 let inner_ty_fr = inner_ty.clone();
1305 push_method(
1306 &mut tokens,
1307 method_scope,
1308 MethodKind::Readable,
1309 quote! {
1310 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
1311 rust_keypaths::OptionalKeyPath::new(|s: &#name| (*s.#field_ident).as_ref())
1312 }
1313 },
1314 );
1315 let inner_ty_fw = inner_ty.clone();
1316 push_method(
1317 &mut tokens,
1318 method_scope,
1319 MethodKind::Writable,
1320 quote! {
1321 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
1322 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| (*s.#field_ident).as_mut())
1323 }
1324 },
1325 );
1326 }
1327 (WrapperKind::RcOption, Some(inner_ty)) => {
1328 let inner_ty_fr = inner_ty.clone();
1329 push_method(
1330 &mut tokens,
1331 method_scope,
1332 MethodKind::Readable,
1333 quote! {
1334 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
1335 rust_keypaths::OptionalKeyPath::new(|s: &#name| (*s.#field_ident).as_ref())
1336 }
1337 },
1338 );
1339 }
1340 (WrapperKind::ArcOption, Some(inner_ty)) => {
1341 let inner_ty_fr = inner_ty.clone();
1342 push_method(
1343 &mut tokens,
1344 method_scope,
1345 MethodKind::Readable,
1346 quote! {
1347 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
1348 rust_keypaths::OptionalKeyPath::new(|s: &#name| (*s.#field_ident).as_ref())
1349 }
1350 },
1351 );
1352 }
1353 (WrapperKind::VecOption, Some(inner_ty)) => {
1354 push_method(
1355 &mut tokens,
1356 method_scope,
1357 MethodKind::Readable,
1358 quote! {
1359 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1360 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1361 }
1362 },
1363 );
1364 let inner_ty_fr = inner_ty.clone();
1365 push_method(
1366 &mut tokens,
1367 method_scope,
1368 MethodKind::Readable,
1369 quote! {
1370 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
1371 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first().and_then(|opt| opt.as_ref()))
1372 }
1373 },
1374 );
1375 let inner_ty_fr_at = inner_ty.clone();
1376 push_method(
1377 &mut tokens,
1378 method_scope,
1379 MethodKind::Readable,
1380 quote! {
1381 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>> {
1382 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index).and_then(|opt| opt.as_ref()))
1383 }
1384 },
1385 );
1386 push_method(
1387 &mut tokens,
1388 method_scope,
1389 MethodKind::Writable,
1390 quote! {
1391 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1392 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
1393 }
1394 },
1395 );
1396 let inner_ty_fw = inner_ty.clone();
1397 push_method(
1398 &mut tokens,
1399 method_scope,
1400 MethodKind::Writable,
1401 quote! {
1402 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
1403 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.first_mut().and_then(|opt| opt.as_mut()))
1404 }
1405 },
1406 );
1407 let inner_ty_fw_at = inner_ty.clone();
1408 push_method(
1409 &mut tokens,
1410 method_scope,
1411 MethodKind::Writable,
1412 quote! {
1413 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>> {
1414 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index).and_then(|opt| opt.as_mut()))
1415 }
1416 },
1417 );
1418 push_method(
1419 &mut tokens,
1420 method_scope,
1421 MethodKind::Owned,
1422 quote! {
1423 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1424 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1425 }
1426 },
1427 );
1428 let inner_ty_fo = inner_ty.clone();
1429 push_method(
1430 &mut tokens,
1431 method_scope,
1432 MethodKind::Owned,
1433 quote! {
1434 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
1435 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.into_iter().flatten().next())
1436 }
1437 },
1438 );
1439 }
1440 (WrapperKind::OptionVec, Some(inner_ty)) => {
1441 push_method(
1442 &mut tokens,
1443 method_scope,
1444 MethodKind::Readable,
1445 quote! {
1446 pub fn #r_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_fr = inner_ty.clone();
1452 push_method(
1453 &mut tokens,
1454 method_scope,
1455 MethodKind::Readable,
1456 quote! {
1457 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
1458 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref().and_then(|v| v.first()))
1459 }
1460 },
1461 );
1462 let inner_ty_fr_at = inner_ty.clone();
1463 push_method(
1464 &mut tokens,
1465 method_scope,
1466 MethodKind::Readable,
1467 quote! {
1468 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>> {
1469 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.as_ref().and_then(|v| v.get(index)))
1470 }
1471 },
1472 );
1473 push_method(
1474 &mut tokens,
1475 method_scope,
1476 MethodKind::Writable,
1477 quote! {
1478 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1479 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
1480 }
1481 },
1482 );
1483 let inner_ty_fw = inner_ty.clone();
1484 push_method(
1485 &mut tokens,
1486 method_scope,
1487 MethodKind::Writable,
1488 quote! {
1489 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
1490 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut().and_then(|v| v.first_mut()))
1491 }
1492 },
1493 );
1494 let inner_ty_fw_at = inner_ty.clone();
1495 push_method(
1496 &mut tokens,
1497 method_scope,
1498 MethodKind::Writable,
1499 quote! {
1500 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>> {
1501 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.as_mut().and_then(|v| v.get_mut(index)))
1502 }
1503 },
1504 );
1505 push_method(
1506 &mut tokens,
1507 method_scope,
1508 MethodKind::Owned,
1509 quote! {
1510 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1511 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1512 }
1513 },
1514 );
1515 let inner_ty_fo = inner_ty.clone();
1516 push_method(
1517 &mut tokens,
1518 method_scope,
1519 MethodKind::Owned,
1520 quote! {
1521 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
1522 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.and_then(|v| v.into_iter().next()))
1523 }
1524 },
1525 );
1526 }
1527 (WrapperKind::HashMapOption, Some(inner_ty)) => {
1528 push_method(
1529 &mut tokens,
1530 method_scope,
1531 MethodKind::Readable,
1532 quote! {
1533 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1534 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1535 }
1536 },
1537 );
1538 let inner_ty_fr = inner_ty.clone();
1539 push_method(
1540 &mut tokens,
1541 method_scope,
1542 MethodKind::Readable,
1543 quote! {
1544 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>> {
1545 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key).and_then(|opt| opt.as_ref()))
1546 }
1547 },
1548 );
1549 let inner_ty_fr_at = inner_ty.clone();
1550 push_method(
1551 &mut tokens,
1552 method_scope,
1553 MethodKind::Readable,
1554 quote! {
1555 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>> {
1556 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key).and_then(|opt| opt.as_ref()))
1557 }
1558 },
1559 );
1560 push_method(
1561 &mut tokens,
1562 method_scope,
1563 MethodKind::Writable,
1564 quote! {
1565 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1566 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
1567 }
1568 },
1569 );
1570 let inner_ty_fw = inner_ty.clone();
1571 push_method(
1572 &mut tokens,
1573 method_scope,
1574 MethodKind::Writable,
1575 quote! {
1576 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>> {
1577 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key).and_then(|opt| opt.as_mut()))
1578 }
1579 },
1580 );
1581 let inner_ty_fw_at = inner_ty.clone();
1582 push_method(
1583 &mut tokens,
1584 method_scope,
1585 MethodKind::Writable,
1586 quote! {
1587 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>> {
1588 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key).and_then(|opt| opt.as_mut()))
1589 }
1590 },
1591 );
1592 push_method(
1593 &mut tokens,
1594 method_scope,
1595 MethodKind::Owned,
1596 quote! {
1597 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1598 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1599 }
1600 },
1601 );
1602 let inner_ty_fo = inner_ty.clone();
1603 push_method(
1604 &mut tokens,
1605 method_scope,
1606 MethodKind::Owned,
1607 quote! {
1608 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
1609 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.into_values().flatten().next())
1610 }
1611 },
1612 );
1613 }
1614 (WrapperKind::OptionHashMap, Some(inner_ty)) => {
1615 push_method(
1616 &mut tokens,
1617 method_scope,
1618 MethodKind::Readable,
1619 quote! {
1620 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1621 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1622 }
1623 },
1624 );
1625 let inner_ty_fr = inner_ty.clone();
1626 push_method(
1627 &mut tokens,
1628 method_scope,
1629 MethodKind::Readable,
1630 quote! {
1631 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>> {
1632 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.as_ref().and_then(|m| m.get(&key)))
1633 }
1634 },
1635 );
1636 let inner_ty_fr_at = inner_ty.clone();
1637 push_method(
1638 &mut tokens,
1639 method_scope,
1640 MethodKind::Readable,
1641 quote! {
1642 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>> {
1643 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.as_ref().and_then(|m| m.get(&key)))
1644 }
1645 },
1646 );
1647 push_method(
1648 &mut tokens,
1649 method_scope,
1650 MethodKind::Writable,
1651 quote! {
1652 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1653 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
1654 }
1655 },
1656 );
1657 let inner_ty_fw = inner_ty.clone();
1658 push_method(
1659 &mut tokens,
1660 method_scope,
1661 MethodKind::Writable,
1662 quote! {
1663 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>> {
1664 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.as_mut().and_then(|m| m.get_mut(&key)))
1665 }
1666 },
1667 );
1668 let inner_ty_fw_at = inner_ty.clone();
1669 push_method(
1670 &mut tokens,
1671 method_scope,
1672 MethodKind::Writable,
1673 quote! {
1674 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>> {
1675 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.as_mut().and_then(|m| m.get_mut(&key)))
1676 }
1677 },
1678 );
1679 push_method(
1680 &mut tokens,
1681 method_scope,
1682 MethodKind::Owned,
1683 quote! {
1684 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1685 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1686 }
1687 },
1688 );
1689 let inner_ty_fo = inner_ty.clone();
1690 push_method(
1691 &mut tokens,
1692 method_scope,
1693 MethodKind::Owned,
1694 quote! {
1695 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
1696 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.and_then(|m| m.into_values().next()))
1697 }
1698 },
1699 );
1700 }
1701 (WrapperKind::None, None) => {
1702 push_method(
1703 &mut tokens,
1704 method_scope,
1705 MethodKind::Readable,
1706 quote! {
1707 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1708 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1709 }
1710 },
1711 );
1712 push_method(
1713 &mut tokens,
1714 method_scope,
1715 MethodKind::Readable,
1716 quote! {
1717 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
1718 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
1719 }
1720 },
1721 );
1722 push_method(
1723 &mut tokens,
1724 method_scope,
1725 MethodKind::Writable,
1726 quote! {
1727 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1728 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
1729 }
1730 },
1731 );
1732 push_method(
1733 &mut tokens,
1734 method_scope,
1735 MethodKind::Writable,
1736 quote! {
1737 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #ty>> {
1738 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#field_ident))
1739 }
1740 },
1741 );
1742 push_method(
1743 &mut tokens,
1744 method_scope,
1745 MethodKind::Owned,
1746 quote! {
1747 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1748 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1749 }
1750 },
1751 );
1752 push_method(
1753 &mut tokens,
1754 method_scope,
1755 MethodKind::Owned,
1756 quote! {
1757 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
1758 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
1759 }
1760 },
1761 );
1762 }
1763 _ => {
1764 push_method(
1765 &mut tokens,
1766 method_scope,
1767 MethodKind::Readable,
1768 quote! {
1769 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1770 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1771 }
1772 },
1773 );
1774 push_method(
1775 &mut tokens,
1776 method_scope,
1777 MethodKind::Writable,
1778 quote! {
1779 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1780 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
1781 }
1782 },
1783 );
1784 push_method(
1785 &mut tokens,
1786 method_scope,
1787 MethodKind::Owned,
1788 quote! {
1789 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1790 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1791 }
1792 },
1793 );
1794 }
1795 }
1796 }
1797 tokens
1798 }
1799 Fields::Unnamed(unnamed) => {
1800 let mut tokens = proc_macro2::TokenStream::new();
1801 for (idx, field) in unnamed.unnamed.iter().enumerate() {
1802 let idx_lit = syn::Index::from(idx);
1803 let ty = &field.ty;
1804
1805 let r_fn = format_ident!("f{}_r", idx);
1806 let w_fn = format_ident!("f{}_w", idx);
1807 let fr_fn = format_ident!("f{}_fr", idx);
1808 let fw_fn = format_ident!("f{}_fw", idx);
1809 let fr_at_fn = format_ident!("f{}_fr_at", idx);
1810 let fw_at_fn = format_ident!("f{}_fw_at", idx);
1811 // Owned keypath method names
1812 let o_fn = format_ident!("f{}_o", idx);
1813 let fo_fn = format_ident!("f{}_fo", idx);
1814
1815 let method_scope = match method_scope_from_attrs(&field.attrs) {
1816 Ok(Some(scope)) => scope,
1817 Ok(None) => default_scope,
1818 Err(err) => return err.to_compile_error().into(),
1819 };
1820
1821 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
1822
1823 match (kind, inner_ty.clone()) {
1824 (WrapperKind::Option, Some(inner_ty)) => {
1825 push_method(
1826 &mut tokens,
1827 method_scope,
1828 MethodKind::Readable,
1829 quote! {
1830 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1831 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
1832 }
1833 },
1834 );
1835 push_method(
1836 &mut tokens,
1837 method_scope,
1838 MethodKind::Writable,
1839 quote! {
1840 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1841 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
1842 }
1843 },
1844 );
1845 let inner_ty_fr = inner_ty.clone();
1846 push_method(
1847 &mut tokens,
1848 method_scope,
1849 MethodKind::Readable,
1850 quote! {
1851 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
1852 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref())
1853 }
1854 },
1855 );
1856 let inner_ty_fw = inner_ty.clone();
1857 push_method(
1858 &mut tokens,
1859 method_scope,
1860 MethodKind::Writable,
1861 quote! {
1862 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
1863 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.as_mut())
1864 }
1865 },
1866 );
1867 push_method(
1868 &mut tokens,
1869 method_scope,
1870 MethodKind::Owned,
1871 quote! {
1872 // Owned keypath methods
1873 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1874 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
1875 }
1876 },
1877 );
1878 let inner_ty_fo = inner_ty.clone();
1879 push_method(
1880 &mut tokens,
1881 method_scope,
1882 MethodKind::Owned,
1883 quote! {
1884 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
1885 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref())
1886 }
1887 },
1888 );
1889 }
1890 (WrapperKind::Vec, Some(inner_ty)) => {
1891 push_method(
1892 &mut tokens,
1893 method_scope,
1894 MethodKind::Readable,
1895 quote! {
1896 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1897 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
1898 }
1899 },
1900 );
1901 push_method(
1902 &mut tokens,
1903 method_scope,
1904 MethodKind::Writable,
1905 quote! {
1906 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1907 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
1908 }
1909 },
1910 );
1911 let inner_ty_fr = inner_ty.clone();
1912 push_method(
1913 &mut tokens,
1914 method_scope,
1915 MethodKind::Readable,
1916 quote! {
1917 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
1918 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
1919 }
1920 },
1921 );
1922 let inner_ty_fw = inner_ty.clone();
1923 push_method(
1924 &mut tokens,
1925 method_scope,
1926 MethodKind::Writable,
1927 quote! {
1928 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
1929 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.first_mut())
1930 }
1931 },
1932 );
1933 let inner_ty_fr_at = inner_ty.clone();
1934 push_method(
1935 &mut tokens,
1936 method_scope,
1937 MethodKind::Readable,
1938 quote! {
1939 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>> {
1940 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.get(*index))
1941 }
1942 },
1943 );
1944 let inner_ty_fw_at = inner_ty.clone();
1945 push_method(
1946 &mut tokens,
1947 method_scope,
1948 MethodKind::Writable,
1949 quote! {
1950 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>> {
1951 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.get_mut(*index))
1952 }
1953 },
1954 );
1955 push_method(
1956 &mut tokens,
1957 method_scope,
1958 MethodKind::Owned,
1959 quote! {
1960 // Owned keypath methods
1961 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1962 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
1963 }
1964 },
1965 );
1966 let inner_ty_fo = inner_ty.clone();
1967 push_method(
1968 &mut tokens,
1969 method_scope,
1970 MethodKind::Owned,
1971 quote! {
1972 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
1973 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
1974 }
1975 },
1976 );
1977 }
1978 (WrapperKind::HashMap, Some(inner_ty)) => {
1979 push_method(
1980 &mut tokens,
1981 method_scope,
1982 MethodKind::Readable,
1983 quote! {
1984 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1985 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
1986 }
1987 },
1988 );
1989 push_method(
1990 &mut tokens,
1991 method_scope,
1992 MethodKind::Writable,
1993 quote! {
1994 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1995 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
1996 }
1997 },
1998 );
1999 let inner_ty_fr = inner_ty.clone();
2000 push_method(
2001 &mut tokens,
2002 method_scope,
2003 MethodKind::Readable,
2004 quote! {
2005 pub fn #fr_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
2006 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key))
2007 }
2008 },
2009 );
2010 let inner_ty_fw = inner_ty.clone();
2011 push_method(
2012 &mut tokens,
2013 method_scope,
2014 MethodKind::Writable,
2015 quote! {
2016 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>> {
2017 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key))
2018 }
2019 },
2020 );
2021 let inner_ty_fr_at = inner_ty.clone();
2022 push_method(
2023 &mut tokens,
2024 method_scope,
2025 MethodKind::Readable,
2026 quote! {
2027 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>> {
2028 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key))
2029 }
2030 },
2031 );
2032 let inner_ty_fw_at = inner_ty.clone();
2033 push_method(
2034 &mut tokens,
2035 method_scope,
2036 MethodKind::Writable,
2037 quote! {
2038 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>> {
2039 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key))
2040 }
2041 },
2042 );
2043 push_method(
2044 &mut tokens,
2045 method_scope,
2046 MethodKind::Owned,
2047 quote! {
2048 // Owned keypath methods
2049 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2050 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
2051 }
2052 },
2053 );
2054 let inner_ty_fo = inner_ty.clone();
2055 push_method(
2056 &mut tokens,
2057 method_scope,
2058 MethodKind::Owned,
2059 quote! {
2060 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
2061 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.into_values().next())
2062 }
2063 },
2064 );
2065 }
2066 (WrapperKind::Box, Some(inner_ty)) => {
2067 let inner_ty_read = inner_ty.clone();
2068 push_method(
2069 &mut tokens,
2070 method_scope,
2071 MethodKind::Readable,
2072 quote! {
2073 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty_read, impl for<'r> Fn(&'r #name) -> &'r #inner_ty_read> {
2074 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
2075 }
2076 },
2077 );
2078 let inner_ty_write = inner_ty.clone();
2079 push_method(
2080 &mut tokens,
2081 method_scope,
2082 MethodKind::Writable,
2083 quote! {
2084 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty_write, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty_write> {
2085 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut *s.#idx_lit)
2086 }
2087 },
2088 );
2089 let inner_ty_fr = inner_ty.clone();
2090 push_method(
2091 &mut tokens,
2092 method_scope,
2093 MethodKind::Readable,
2094 quote! {
2095 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
2096 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#idx_lit))
2097 }
2098 },
2099 );
2100 let inner_ty_fw = inner_ty.clone();
2101 push_method(
2102 &mut tokens,
2103 method_scope,
2104 MethodKind::Writable,
2105 quote! {
2106 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
2107 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut *s.#idx_lit))
2108 }
2109 },
2110 );
2111 let inner_ty_owned = inner_ty.clone();
2112 push_method(
2113 &mut tokens,
2114 method_scope,
2115 MethodKind::Owned,
2116 quote! {
2117 // Owned keypath methods
2118 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #inner_ty_owned, impl for<'r> Fn(&'r #name) -> &'r #inner_ty_owned> {
2119 rust_keypaths::KeyPath::new(|s: &#name| *s.#idx_lit)
2120 }
2121 },
2122 );
2123 let inner_ty_fo = inner_ty.clone();
2124 push_method(
2125 &mut tokens,
2126 method_scope,
2127 MethodKind::Owned,
2128 quote! {
2129 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
2130 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(*s.#idx_lit))
2131 }
2132 },
2133 );
2134 }
2135 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
2136 let inner_ty_read = inner_ty.clone();
2137 push_method(
2138 &mut tokens,
2139 method_scope,
2140 MethodKind::Readable,
2141 quote! {
2142 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty_read, impl for<'r> Fn(&'r #name) -> &'r #inner_ty_read> {
2143 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
2144 }
2145 },
2146 );
2147 let inner_ty_fr = inner_ty.clone();
2148 push_method(
2149 &mut tokens,
2150 method_scope,
2151 MethodKind::Readable,
2152 quote! {
2153 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
2154 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#idx_lit))
2155 }
2156 },
2157 );
2158 let inner_ty_owned = inner_ty.clone();
2159 push_method(
2160 &mut tokens,
2161 method_scope,
2162 MethodKind::Owned,
2163 quote! {
2164 // Owned keypath methods
2165 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #inner_ty_owned, impl for<'r> Fn(&'r #name) -> &'r #inner_ty_owned> {
2166 rust_keypaths::KeyPath::new(|s: &#name| (*s.#idx_lit).clone())
2167 }
2168 },
2169 );
2170 let inner_ty_fo = inner_ty.clone();
2171 push_method(
2172 &mut tokens,
2173 method_scope,
2174 MethodKind::Owned,
2175 quote! {
2176 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
2177 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some((*s.#idx_lit).clone()))
2178 }
2179 },
2180 );
2181 }
2182 (WrapperKind::BTreeMap, Some(inner_ty)) => {
2183 push_method(
2184 &mut tokens,
2185 method_scope,
2186 MethodKind::Readable,
2187 quote! {
2188 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2189 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2190 }
2191 },
2192 );
2193 push_method(
2194 &mut tokens,
2195 method_scope,
2196 MethodKind::Writable,
2197 quote! {
2198 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2199 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
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 // Note: Key-based access methods for BTreeMap require the exact key type
2224 // For now, we'll skip generating these methods to avoid generic constraint issues
2225 },
2226 );
2227 }
2228 (WrapperKind::HashSet, Some(inner_ty)) => {
2229 push_method(
2230 &mut tokens,
2231 method_scope,
2232 MethodKind::Readable,
2233 quote! {
2234 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2235 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2236 }
2237 },
2238 );
2239 push_method(
2240 &mut tokens,
2241 method_scope,
2242 MethodKind::Writable,
2243 quote! {
2244 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
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| s.#idx_lit.iter().next())
2257 }
2258 },
2259 );
2260 push_method(
2261 &mut tokens,
2262 method_scope,
2263 MethodKind::Owned,
2264 quote! {
2265 // Owned keypath methods
2266 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2267 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
2268 }
2269 },
2270 );
2271 let inner_ty_fo = inner_ty.clone();
2272 push_method(
2273 &mut tokens,
2274 method_scope,
2275 MethodKind::Owned,
2276 quote! {
2277 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
2278 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
2279 }
2280 },
2281 );
2282 }
2283 (WrapperKind::BTreeSet, Some(inner_ty)) => {
2284 push_method(
2285 &mut tokens,
2286 method_scope,
2287 MethodKind::Readable,
2288 quote! {
2289 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2290 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2291 }
2292 },
2293 );
2294 push_method(
2295 &mut tokens,
2296 method_scope,
2297 MethodKind::Writable,
2298 quote! {
2299 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2300 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2301 }
2302 },
2303 );
2304 let inner_ty_fr = inner_ty.clone();
2305 push_method(
2306 &mut tokens,
2307 method_scope,
2308 MethodKind::Readable,
2309 quote! {
2310 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
2311 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.iter().next())
2312 }
2313 },
2314 );
2315 push_method(
2316 &mut tokens,
2317 method_scope,
2318 MethodKind::Owned,
2319 quote! {
2320 // Owned keypath methods
2321 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2322 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
2323 }
2324 },
2325 );
2326 let inner_ty_fo = inner_ty.clone();
2327 push_method(
2328 &mut tokens,
2329 method_scope,
2330 MethodKind::Owned,
2331 quote! {
2332 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
2333 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
2334 }
2335 },
2336 );
2337 }
2338 (WrapperKind::VecDeque, Some(inner_ty)) => {
2339 push_method(
2340 &mut tokens,
2341 method_scope,
2342 MethodKind::Readable,
2343 quote! {
2344 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2345 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2346 }
2347 },
2348 );
2349 push_method(
2350 &mut tokens,
2351 method_scope,
2352 MethodKind::Writable,
2353 quote! {
2354 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2355 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2356 }
2357 },
2358 );
2359 let inner_ty_fr = inner_ty.clone();
2360 push_method(
2361 &mut tokens,
2362 method_scope,
2363 MethodKind::Readable,
2364 quote! {
2365 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
2366 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.front())
2367 }
2368 },
2369 );
2370 let inner_ty_fw = inner_ty.clone();
2371 push_method(
2372 &mut tokens,
2373 method_scope,
2374 MethodKind::Writable,
2375 quote! {
2376 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
2377 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.front_mut())
2378 }
2379 },
2380 );
2381 push_method(
2382 &mut tokens,
2383 method_scope,
2384 MethodKind::Owned,
2385 quote! {
2386 // Owned keypath methods
2387 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2388 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
2389 }
2390 },
2391 );
2392 let inner_ty_fo = inner_ty.clone();
2393 push_method(
2394 &mut tokens,
2395 method_scope,
2396 MethodKind::Owned,
2397 quote! {
2398 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
2399 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
2400 }
2401 },
2402 );
2403 }
2404 (WrapperKind::LinkedList, Some(inner_ty)) => {
2405 push_method(
2406 &mut tokens,
2407 method_scope,
2408 MethodKind::Readable,
2409 quote! {
2410 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2411 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2412 }
2413 },
2414 );
2415 push_method(
2416 &mut tokens,
2417 method_scope,
2418 MethodKind::Writable,
2419 quote! {
2420 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2421 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2422 }
2423 },
2424 );
2425 let inner_ty_fr = inner_ty.clone();
2426 push_method(
2427 &mut tokens,
2428 method_scope,
2429 MethodKind::Readable,
2430 quote! {
2431 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
2432 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.front())
2433 }
2434 },
2435 );
2436 let inner_ty_fw = inner_ty.clone();
2437 push_method(
2438 &mut tokens,
2439 method_scope,
2440 MethodKind::Writable,
2441 quote! {
2442 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
2443 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.front_mut())
2444 }
2445 },
2446 );
2447 push_method(
2448 &mut tokens,
2449 method_scope,
2450 MethodKind::Owned,
2451 quote! {
2452 // Owned keypath methods
2453 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2454 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
2455 }
2456 },
2457 );
2458 let inner_ty_fo = inner_ty.clone();
2459 push_method(
2460 &mut tokens,
2461 method_scope,
2462 MethodKind::Owned,
2463 quote! {
2464 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
2465 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
2466 }
2467 },
2468 );
2469 }
2470 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
2471 push_method(
2472 &mut tokens,
2473 method_scope,
2474 MethodKind::Readable,
2475 quote! {
2476 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2477 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2478 }
2479 },
2480 );
2481 push_method(
2482 &mut tokens,
2483 method_scope,
2484 MethodKind::Writable,
2485 quote! {
2486 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2487 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2488 }
2489 },
2490 );
2491 let inner_ty_fr = inner_ty.clone();
2492 push_method(
2493 &mut tokens,
2494 method_scope,
2495 MethodKind::Readable,
2496 quote! {
2497 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
2498 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.peek())
2499 }
2500 },
2501 );
2502 let inner_ty_fw = inner_ty.clone();
2503 push_method(
2504 &mut tokens,
2505 method_scope,
2506 MethodKind::Writable,
2507 quote! {
2508 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
2509 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.peek_mut().map(|v| &mut **v))
2510 }
2511 },
2512 );
2513 push_method(
2514 &mut tokens,
2515 method_scope,
2516 MethodKind::Owned,
2517 quote! {
2518 // Owned keypath methods
2519 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2520 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
2521 }
2522 },
2523 );
2524 let inner_ty_fo = inner_ty.clone();
2525 push_method(
2526 &mut tokens,
2527 method_scope,
2528 MethodKind::Owned,
2529 quote! {
2530 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
2531 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
2532 }
2533 },
2534 );
2535 }
2536 (WrapperKind::Result, Some(inner_ty)) => {
2537 push_method(
2538 &mut tokens,
2539 method_scope,
2540 MethodKind::Readable,
2541 quote! {
2542 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2543 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2544 }
2545 },
2546 );
2547 push_method(
2548 &mut tokens,
2549 method_scope,
2550 MethodKind::Writable,
2551 quote! {
2552 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2553 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2554 }
2555 },
2556 );
2557 let inner_ty_fr = inner_ty.clone();
2558 push_method(
2559 &mut tokens,
2560 method_scope,
2561 MethodKind::Readable,
2562 quote! {
2563 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
2564 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref().ok())
2565 }
2566 },
2567 );
2568 push_method(
2569 &mut tokens,
2570 method_scope,
2571 MethodKind::Owned,
2572 quote! {
2573 // Note: Result<T, E> doesn't support failable_writable for inner type
2574 // Only providing container-level writable access
2575 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2576 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
2577 }
2578 },
2579 );
2580 let inner_ty_fo = inner_ty.clone();
2581 push_method(
2582 &mut tokens,
2583 method_scope,
2584 MethodKind::Owned,
2585 quote! {
2586 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
2587 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.ok())
2588 }
2589 },
2590 );
2591 }
2592 (WrapperKind::Mutex, Some(_inner_ty)) => {
2593 push_method(
2594 &mut tokens,
2595 method_scope,
2596 MethodKind::Readable,
2597 quote! {
2598 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2599 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2600 }
2601 },
2602 );
2603 push_method(
2604 &mut tokens,
2605 method_scope,
2606 MethodKind::Writable,
2607 quote! {
2608 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2609 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2610 }
2611 },
2612 );
2613 push_method(
2614 &mut tokens,
2615 method_scope,
2616 MethodKind::Owned,
2617 quote! {
2618 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
2619 // Only providing container-level access
2620 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2621 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
2622 }
2623 },
2624 );
2625 }
2626 (WrapperKind::RwLock, Some(_inner_ty)) => {
2627 push_method(
2628 &mut tokens,
2629 method_scope,
2630 MethodKind::Readable,
2631 quote! {
2632 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2633 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2634 }
2635 },
2636 );
2637 push_method(
2638 &mut tokens,
2639 method_scope,
2640 MethodKind::Writable,
2641 quote! {
2642 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2643 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2644 }
2645 },
2646 );
2647 push_method(
2648 &mut tokens,
2649 method_scope,
2650 MethodKind::Owned,
2651 quote! {
2652 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
2653 // Only providing container-level access
2654 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2655 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
2656 }
2657 },
2658 );
2659 }
2660 (WrapperKind::Weak, Some(_inner_ty)) => {
2661 push_method(
2662 &mut tokens,
2663 method_scope,
2664 MethodKind::Readable,
2665 quote! {
2666 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2667 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2668 }
2669 },
2670 );
2671 push_method(
2672 &mut tokens,
2673 method_scope,
2674 MethodKind::Owned,
2675 quote! {
2676 // Note: Weak<T> doesn't support writable access (it's immutable)
2677 // Note: Weak<T> doesn't support direct access to inner type due to lifetime constraints
2678 // Only providing container-level access
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 }
2685 // Nested container combinations for tuple structs - COMMENTED OUT FOR NOW
2686 /*
2687 (WrapperKind::OptionBox, Some(inner_ty)) => {
2688 tokens.extend(quote! {
2689 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2690 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2691 }
2692 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2693 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2694 }
2695 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
2696 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref().map(|b| &**b))
2697 }
2698 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
2699 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.as_mut().map(|b| &mut **b))
2700 }
2701 });
2702 }
2703 (WrapperKind::OptionRc, Some(inner_ty)) => {
2704 tokens.extend(quote! {
2705 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2706 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2707 }
2708 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
2709 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref().map(|r| &**r))
2710 }
2711 });
2712 }
2713 (WrapperKind::OptionArc, Some(inner_ty)) => {
2714 tokens.extend(quote! {
2715 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2716 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2717 }
2718 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
2719 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref().map(|a| &**a))
2720 }
2721 });
2722 }
2723 (WrapperKind::BoxOption, Some(inner_ty)) => {
2724 tokens.extend(quote! {
2725 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2726 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
2727 }
2728 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2729 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut *s.#idx_lit)
2730 }
2731 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
2732 rust_keypaths::OptionalKeyPath::new(|s: &#name| (*s.#idx_lit).as_ref())
2733 }
2734 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
2735 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| (*s.#idx_lit).as_mut())
2736 }
2737 });
2738 }
2739 (WrapperKind::RcOption, Some(inner_ty)) => {
2740 tokens.extend(quote! {
2741 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2742 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
2743 }
2744 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
2745 rust_keypaths::OptionalKeyPath::new(|s: &#name| (*s.#idx_lit).as_ref())
2746 }
2747 });
2748 }
2749 (WrapperKind::ArcOption, Some(inner_ty)) => {
2750 tokens.extend(quote! {
2751 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2752 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
2753 }
2754 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
2755 rust_keypaths::OptionalKeyPath::new(|s: &#name| (*s.#idx_lit).as_ref())
2756 }
2757 });
2758 }
2759 (WrapperKind::VecOption, Some(inner_ty)) => {
2760 tokens.extend(quote! {
2761 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2762 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2763 }
2764 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2765 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2766 }
2767 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
2768 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first().and_then(|opt| opt.as_ref()))
2769 }
2770 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
2771 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.first_mut().and_then(|opt| opt.as_mut()))
2772 }
2773 });
2774 }
2775 (WrapperKind::OptionVec, Some(inner_ty)) => {
2776 tokens.extend(quote! {
2777 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2778 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2779 }
2780 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2781 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2782 }
2783 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
2784 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref().and_then(|v| v.first()))
2785 }
2786 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
2787 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.as_mut().and_then(|v| v.first_mut()))
2788 }
2789 });
2790 }
2791 (WrapperKind::HashMapOption, Some(inner_ty)) => {
2792 tokens.extend(quote! {
2793 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2794 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2795 }
2796 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2797 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2798 }
2799 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>> {
2800 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key).and_then(|opt| opt.as_ref()))
2801 }
2802 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>> {
2803 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key).and_then(|opt| opt.as_mut()))
2804 }
2805 });
2806 }
2807 (WrapperKind::OptionHashMap, Some(inner_ty)) => {
2808 tokens.extend(quote! {
2809 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2810 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2811 }
2812 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2813 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2814 }
2815 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>> {
2816 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.as_ref().and_then(|m| m.get(&key)))
2817 }
2818 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>> {
2819 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.as_mut().and_then(|m| m.get_mut(&key)))
2820 }
2821 });
2822 }
2823 */
2824 (WrapperKind::None, None) => {
2825 push_method(
2826 &mut tokens,
2827 method_scope,
2828 MethodKind::Readable,
2829 quote! {
2830 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2831 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2832 }
2833 },
2834 );
2835 push_method(
2836 &mut tokens,
2837 method_scope,
2838 MethodKind::Writable,
2839 quote! {
2840 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
2841 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
2842 }
2843 },
2844 );
2845 push_method(
2846 &mut tokens,
2847 method_scope,
2848 MethodKind::Readable,
2849 quote! {
2850 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
2851 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
2852 }
2853 },
2854 );
2855 push_method(
2856 &mut tokens,
2857 method_scope,
2858 MethodKind::Writable,
2859 quote! {
2860 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #ty>> {
2861 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#idx_lit))
2862 }
2863 },
2864 );
2865 push_method(
2866 &mut tokens,
2867 method_scope,
2868 MethodKind::Owned,
2869 quote! {
2870 // Owned keypath methods
2871 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2872 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2873 }
2874 },
2875 );
2876 push_method(
2877 &mut tokens,
2878 method_scope,
2879 MethodKind::Owned,
2880 quote! {
2881 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
2882 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
2883 }
2884 },
2885 );
2886 }
2887 _ => {
2888 push_method(
2889 &mut tokens,
2890 method_scope,
2891 MethodKind::Readable,
2892 quote! {
2893 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2894 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
2895 }
2896 },
2897 );
2898 push_method(
2899 &mut tokens,
2900 method_scope,
2901 MethodKind::Owned,
2902 quote! {
2903 // Owned keypath methods
2904 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
2905 rust_keypaths::KeyPath::new(|s: &#name| s.#idx_lit)
2906 }
2907 },
2908 );
2909 }
2910 }
2911 }
2912 tokens
2913 }
2914 _ => quote! {
2915 compile_error!("Keypaths derive supports only structs with named or unnamed fields");
2916 },
2917 },
2918 Data::Enum(data_enum) => {
2919 let mut tokens = proc_macro2::TokenStream::new();
2920 for variant in data_enum.variants.iter() {
2921 let v_ident = &variant.ident;
2922 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
2923 let r_fn = format_ident!("{}_case_r", snake);
2924 let w_fn = format_ident!("{}_case_w", snake);
2925 let _fr_fn = format_ident!("{}_case_fr", snake);
2926 let _fw_fn = format_ident!("{}_case_fw", snake);
2927 let fr_at_fn = format_ident!("{}_case_fr_at", snake);
2928 let fw_at_fn = format_ident!("{}_case_fw_at", snake);
2929
2930 match &variant.fields {
2931 Fields::Unit => {
2932 tokens.extend(quote! {
2933 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, (), impl for<'r> Fn(&'r #name) -> &'r ()> {
2934 static UNIT: () = ();
2935 rust_keypaths::KeyPaths::readable_enum(
2936 |_| #name::#v_ident,
2937 |e: &#name| match e { #name::#v_ident => Some(&UNIT), _ => None }
2938 )
2939 }
2940 });
2941 }
2942 Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
2943 let field_ty = &unnamed.unnamed.first().unwrap().ty;
2944 let (kind, inner_ty_opt) = extract_wrapper_inner_type(field_ty);
2945
2946 match (kind, inner_ty_opt) {
2947 (WrapperKind::Option, Some(inner_ty)) => {
2948 tokens.extend(quote! {
2949 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
2950 rust_keypaths::KeyPaths::readable_enum(
2951 #name::#v_ident,
2952 |e: &#name| match e { #name::#v_ident(v) => v.as_ref(), _ => None }
2953 )
2954 }
2955 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
2956 rust_keypaths::KeyPaths::writable_enum(
2957 #name::#v_ident,
2958 |e: &#name| match e { #name::#v_ident(v) => v.as_ref(), _ => None },
2959 |e: &mut #name| match e { #name::#v_ident(v) => v.as_mut(), _ => None },
2960 )
2961 }
2962 });
2963 }
2964 (WrapperKind::Vec, Some(inner_ty)) => {
2965 tokens.extend(quote! {
2966 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
2967 rust_keypaths::KeyPaths::readable_enum(
2968 #name::#v_ident,
2969 |e: &#name| match e { #name::#v_ident(v) => v.first(), _ => None }
2970 )
2971 }
2972 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
2973 rust_keypaths::KeyPaths::writable_enum(
2974 #name::#v_ident,
2975 |e: &#name| match e { #name::#v_ident(v) => v.first(), _ => None },
2976 |e: &mut #name| match e { #name::#v_ident(v) => v.first_mut(), _ => None },
2977 )
2978 }
2979 pub fn #fr_at_fn(index: &'static usize) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
2980 rust_keypaths::KeyPaths::readable_enum(
2981 #name::#v_ident,
2982 |e: &#name| match e { #name::#v_ident(v) => v.get(*index), _ => None }
2983 )
2984 }
2985 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>> {
2986 rust_keypaths::KeyPaths::writable_enum(
2987 #name::#v_ident,
2988 |e: &#name| match e { #name::#v_ident(v) => v.get(*index), _ => None },
2989 |e: &mut #name| match e { #name::#v_ident(v) => v.get_mut(*index), _ => None },
2990 )
2991 }
2992 });
2993 }
2994 (WrapperKind::HashMap, Some(inner_ty)) => {
2995 tokens.extend(quote! {
2996 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
2997 rust_keypaths::KeyPaths::readable_enum(
2998 #name::#v_ident,
2999 |e: &#name| match e { #name::#v_ident(v) => v.first().map(|(_, v)| v), _ => None }
3000 )
3001 }
3002 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3003 rust_keypaths::KeyPaths::writable_enum(
3004 #name::#v_ident,
3005 |e: &#name| match e { #name::#v_ident(v) => v.first().map(|(_, v)| v), _ => None },
3006 |e: &mut #name| match e { #name::#v_ident(v) => v.first_mut().map(|(_, v)| v), _ => None },
3007 )
3008 }
3009 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>> {
3010 rust_keypaths::KeyPaths::readable_enum(
3011 #name::#v_ident,
3012 |e: &#name| match e { #name::#v_ident(v) => v.get(key), _ => None }
3013 )
3014 }
3015 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>> {
3016 rust_keypaths::KeyPaths::writable_enum(
3017 #name::#v_ident,
3018 |e: &#name| match e { #name::#v_ident(v) => v.get(key), _ => None },
3019 |e: &mut #name| match e { #name::#v_ident(v) => v.get_mut(key), _ => None },
3020 )
3021 }
3022 });
3023 }
3024 (WrapperKind::Box, Some(inner_ty)) => {
3025 tokens.extend(quote! {
3026 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3027 rust_keypaths::KeyPaths::readable_enum(
3028 #name::#v_ident,
3029 |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None }
3030 )
3031 }
3032 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3033 rust_keypaths::KeyPaths::writable_enum(
3034 #name::#v_ident,
3035 |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None },
3036 |e: &mut #name| match e { #name::#v_ident(v) => Some(&mut *v), _ => None },
3037 )
3038 }
3039 });
3040 }
3041 (WrapperKind::Rc, Some(inner_ty))
3042 | (WrapperKind::Arc, Some(inner_ty)) => {
3043 tokens.extend(quote! {
3044 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3045 rust_keypaths::KeyPaths::readable_enum(
3046 #name::#v_ident,
3047 |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None }
3048 )
3049 }
3050 });
3051 }
3052 (WrapperKind::BTreeMap, Some(inner_ty)) => {
3053 tokens.extend(quote! {
3054 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3055 rust_keypaths::KeyPaths::readable_enum(
3056 #name::#v_ident,
3057 |e: &#name| match e { #name::#v_ident(v) => v.first().map(|(_, v)| v), _ => None }
3058 )
3059 }
3060 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3061 rust_keypaths::KeyPaths::writable_enum(
3062 #name::#v_ident,
3063 |e: &#name| match e { #name::#v_ident(v) => v.first().map(|(_, v)| v), _ => None },
3064 |e: &mut #name| match e { #name::#v_ident(v) => v.first_mut().map(|(_, v)| v), _ => None },
3065 )
3066 }
3067 });
3068 }
3069 (WrapperKind::HashSet, Some(inner_ty)) => {
3070 tokens.extend(quote! {
3071 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3072 rust_keypaths::KeyPaths::readable_enum(
3073 #name::#v_ident,
3074 |e: &#name| match e { #name::#v_ident(v) => v.iter().next(), _ => None }
3075 )
3076 }
3077 });
3078 }
3079 (WrapperKind::BTreeSet, Some(inner_ty)) => {
3080 tokens.extend(quote! {
3081 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3082 rust_keypaths::KeyPaths::readable_enum(
3083 #name::#v_ident,
3084 |e: &#name| match e { #name::#v_ident(v) => v.iter().next(), _ => None }
3085 )
3086 }
3087 });
3088 }
3089 (WrapperKind::VecDeque, Some(inner_ty)) => {
3090 tokens.extend(quote! {
3091 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3092 rust_keypaths::KeyPaths::readable_enum(
3093 #name::#v_ident,
3094 |e: &#name| match e { #name::#v_ident(v) => v.front(), _ => None }
3095 )
3096 }
3097 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3098 rust_keypaths::KeyPaths::writable_enum(
3099 #name::#v_ident,
3100 |e: &#name| match e { #name::#v_ident(v) => v.front(), _ => None },
3101 |e: &mut #name| match e { #name::#v_ident(v) => v.front_mut(), _ => None },
3102 )
3103 }
3104 });
3105 }
3106 (WrapperKind::LinkedList, Some(inner_ty)) => {
3107 tokens.extend(quote! {
3108 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3109 rust_keypaths::KeyPaths::readable_enum(
3110 #name::#v_ident,
3111 |e: &#name| match e { #name::#v_ident(v) => v.front(), _ => None }
3112 )
3113 }
3114 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3115 rust_keypaths::KeyPaths::writable_enum(
3116 #name::#v_ident,
3117 |e: &#name| match e { #name::#v_ident(v) => v.front(), _ => None },
3118 |e: &mut #name| match e { #name::#v_ident(v) => v.front_mut(), _ => None },
3119 )
3120 }
3121 });
3122 }
3123 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
3124 tokens.extend(quote! {
3125 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3126 rust_keypaths::KeyPaths::readable_enum(
3127 #name::#v_ident,
3128 |e: &#name| match e { #name::#v_ident(v) => v.peek(), _ => None }
3129 )
3130 }
3131 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3132 rust_keypaths::KeyPaths::writable_enum(
3133 #name::#v_ident,
3134 |e: &#name| match e { #name::#v_ident(v) => v.peek(), _ => None },
3135 |e: &mut #name| match e { #name::#v_ident(v) => v.peek_mut().map(|v| &mut **v), _ => None },
3136 )
3137 }
3138 });
3139 }
3140 (WrapperKind::Result, Some(inner_ty)) => {
3141 tokens.extend(quote! {
3142 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3143 rust_keypaths::KeyPaths::readable_enum(
3144 #name::#v_ident,
3145 |e: &#name| match e { #name::#v_ident(v) => v.as_ref().ok(), _ => None }
3146 )
3147 }
3148 // Note: Result<T, E> doesn't support writable access for inner type
3149 // Only providing readable access
3150 });
3151 }
3152 (WrapperKind::Mutex, Some(inner_ty)) => {
3153 tokens.extend(quote! {
3154 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
3155 rust_keypaths::KeyPaths::readable_enum(
3156 #name::#v_ident,
3157 |e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None }
3158 )
3159 }
3160 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
3161 // Only providing container-level access
3162 });
3163 }
3164 (WrapperKind::RwLock, Some(inner_ty)) => {
3165 tokens.extend(quote! {
3166 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
3167 rust_keypaths::KeyPaths::readable_enum(
3168 #name::#v_ident,
3169 |e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None }
3170 )
3171 }
3172 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
3173 // Only providing container-level access
3174 });
3175 }
3176 (WrapperKind::Weak, Some(inner_ty)) => {
3177 tokens.extend(quote! {
3178 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
3179 rust_keypaths::KeyPaths::readable_enum(
3180 #name::#v_ident,
3181 |e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None }
3182 )
3183 }
3184 // Note: Weak<T> doesn't support writable access (it's immutable)
3185 // Note: Weak<T> doesn't support direct access to inner type due to lifetime constraints
3186 // Only providing container-level access
3187 });
3188 }
3189 // Nested container combinations for enums - COMMENTED OUT FOR NOW
3190 /*
3191 (WrapperKind::OptionBox, Some(inner_ty)) => {
3192 tokens.extend(quote! {
3193 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3194 rust_keypaths::KeyPaths::readable_enum(
3195 #name::#v_ident,
3196 |e: &#name| match e { #name::#v_ident(v) => v.as_ref().map(|b| &**b), _ => None }
3197 )
3198 }
3199 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3200 rust_keypaths::KeyPaths::writable_enum(
3201 #name::#v_ident,
3202 |e: &#name| match e { #name::#v_ident(v) => v.as_ref().map(|b| &**b), _ => None },
3203 |e: &mut #name| match e { #name::#v_ident(v) => v.as_mut().map(|b| &mut **b), _ => None },
3204 )
3205 }
3206 });
3207 }
3208 (WrapperKind::OptionRc, Some(inner_ty)) => {
3209 tokens.extend(quote! {
3210 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3211 rust_keypaths::KeyPaths::readable_enum(
3212 #name::#v_ident,
3213 |e: &#name| match e { #name::#v_ident(v) => v.as_ref().map(|r| &**r), _ => None }
3214 )
3215 }
3216 });
3217 }
3218 (WrapperKind::OptionArc, Some(inner_ty)) => {
3219 tokens.extend(quote! {
3220 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3221 rust_keypaths::KeyPaths::readable_enum(
3222 #name::#v_ident,
3223 |e: &#name| match e { #name::#v_ident(v) => v.as_ref().map(|a| &**a), _ => None }
3224 )
3225 }
3226 });
3227 }
3228 (WrapperKind::BoxOption, Some(inner_ty)) => {
3229 tokens.extend(quote! {
3230 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
3231 rust_keypaths::KeyPaths::readable_enum(
3232 #name::#v_ident,
3233 |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None }
3234 )
3235 }
3236 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #field_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #field_ty> {
3237 rust_keypaths::KeyPaths::writable_enum(
3238 #name::#v_ident,
3239 |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None },
3240 |e: &mut #name| match e { #name::#v_ident(v) => Some(&mut *v), _ => None },
3241 )
3242 }
3243 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
3244 rust_keypaths::KeyPaths::readable_enum(
3245 #name::#v_ident,
3246 |e: &#name| match e { #name::#v_ident(v) => (*v).as_ref(), _ => None }
3247 )
3248 }
3249 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3250 rust_keypaths::KeyPaths::writable_enum(
3251 #name::#v_ident,
3252 |e: &#name| match e { #name::#v_ident(v) => (*v).as_ref(), _ => None },
3253 |e: &mut #name| match e { #name::#v_ident(v) => (*v).as_mut(), _ => None },
3254 )
3255 }
3256 });
3257 }
3258 (WrapperKind::RcOption, Some(inner_ty)) => {
3259 tokens.extend(quote! {
3260 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
3261 rust_keypaths::KeyPaths::readable_enum(
3262 #name::#v_ident,
3263 |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None }
3264 )
3265 }
3266 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
3267 rust_keypaths::KeyPaths::readable_enum(
3268 #name::#v_ident,
3269 |e: &#name| match e { #name::#v_ident(v) => (*v).as_ref(), _ => None }
3270 )
3271 }
3272 });
3273 }
3274 (WrapperKind::ArcOption, Some(inner_ty)) => {
3275 tokens.extend(quote! {
3276 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
3277 rust_keypaths::KeyPaths::readable_enum(
3278 #name::#v_ident,
3279 |e: &#name| match e { #name::#v_ident(v) => Some(&*v), _ => None }
3280 )
3281 }
3282 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
3283 rust_keypaths::KeyPaths::readable_enum(
3284 #name::#v_ident,
3285 |e: &#name| match e { #name::#v_ident(v) => (*v).as_ref(), _ => None }
3286 )
3287 }
3288 });
3289 }
3290 (WrapperKind::VecOption, Some(inner_ty)) => {
3291 tokens.extend(quote! {
3292 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3293 rust_keypaths::KeyPaths::readable_enum(
3294 #name::#v_ident,
3295 |e: &#name| match e { #name::#v_ident(v) => v.first().and_then(|opt| opt.as_ref()), _ => None }
3296 )
3297 }
3298 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3299 rust_keypaths::KeyPaths::writable_enum(
3300 #name::#v_ident,
3301 |e: &#name| match e { #name::#v_ident(v) => v.first().and_then(|opt| opt.as_ref()), _ => None },
3302 |e: &mut #name| match e { #name::#v_ident(v) => v.first_mut().and_then(|opt| opt.as_mut()), _ => None },
3303 )
3304 }
3305 });
3306 }
3307 (WrapperKind::OptionVec, Some(inner_ty)) => {
3308 tokens.extend(quote! {
3309 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3310 rust_keypaths::KeyPaths::readable_enum(
3311 #name::#v_ident,
3312 |e: &#name| match e { #name::#v_ident(v) => v.as_ref().and_then(|vec| vec.first()), _ => None }
3313 )
3314 }
3315 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3316 rust_keypaths::KeyPaths::writable_enum(
3317 #name::#v_ident,
3318 |e: &#name| match e { #name::#v_ident(v) => v.as_ref().and_then(|vec| vec.first()), _ => None },
3319 |e: &mut #name| match e { #name::#v_ident(v) => v.as_mut().and_then(|vec| vec.first_mut()), _ => None },
3320 )
3321 }
3322 });
3323 }
3324 (WrapperKind::HashMapOption, Some(inner_ty)) => {
3325 tokens.extend(quote! {
3326 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3327 rust_keypaths::KeyPaths::readable_enum(
3328 #name::#v_ident,
3329 |e: &#name| match e { #name::#v_ident(v) => v.first().and_then(|(_, opt)| opt.as_ref()), _ => None }
3330 )
3331 }
3332 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3333 rust_keypaths::KeyPaths::writable_enum(
3334 #name::#v_ident,
3335 |e: &#name| match e { #name::#v_ident(v) => v.first().and_then(|(_, opt)| opt.as_ref()), _ => None },
3336 |e: &mut #name| match e { #name::#v_ident(v) => v.first_mut().and_then(|(_, opt)| opt.as_mut()), _ => None },
3337 )
3338 }
3339 });
3340 }
3341 (WrapperKind::OptionHashMap, Some(inner_ty)) => {
3342 tokens.extend(quote! {
3343 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3344 rust_keypaths::KeyPaths::readable_enum(
3345 #name::#v_ident,
3346 |e: &#name| match e { #name::#v_ident(v) => v.as_ref().and_then(|map| map.first().map(|(_, v)| v)), _ => None }
3347 )
3348 }
3349 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3350 rust_keypaths::KeyPaths::writable_enum(
3351 #name::#v_ident,
3352 |e: &#name| match e { #name::#v_ident(v) => v.as_ref().and_then(|map| map.first().map(|(_, v)| v)), _ => None },
3353 |e: &mut #name| match e { #name::#v_ident(v) => v.as_mut().and_then(|map| map.first_mut().map(|(_, v)| v)), _ => None },
3354 )
3355 }
3356 });
3357 }
3358 */
3359 (WrapperKind::None, None) => {
3360 let inner_ty = field_ty;
3361 tokens.extend(quote! {
3362 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
3363 rust_keypaths::KeyPaths::readable_enum(
3364 #name::#v_ident,
3365 |e: &#name| match e { #name::#v_ident(v) => Some(&v), _ => None }
3366 )
3367 }
3368 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3369 rust_keypaths::KeyPaths::writable_enum(
3370 #name::#v_ident,
3371 |e: &#name| match e { #name::#v_ident(v) => Some(&v), _ => None },
3372 |e: &mut #name| match e { #name::#v_ident(v) => Some(&mut v), _ => None },
3373 )
3374 }
3375 });
3376 }
3377 _ => {
3378 tokens.extend(quote! {
3379 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
3380 rust_keypaths::KeyPaths::readable_enum(
3381 #name::#v_ident,
3382 |e: &#name| match e { #name::#v_ident(v) => Some(&v), _ => None }
3383 )
3384 }
3385 });
3386 }
3387 }
3388 }
3389 Fields::Unnamed(unnamed) if unnamed.unnamed.len() > 1 => {
3390 // Multi-field tuple variants - generate methods for each field
3391 for (index, field) in unnamed.unnamed.iter().enumerate() {
3392 let field_ty = &field.ty;
3393 let field_fn = format_ident!("f{}", index);
3394 let r_fn = format_ident!("{}_{}_r", snake, field_fn);
3395 let w_fn = format_ident!("{}_{}_w", snake, field_fn);
3396
3397 // Generate pattern matching for this specific field
3398 let mut pattern_parts = Vec::new();
3399
3400 for i in 0..unnamed.unnamed.len() {
3401 if i == index {
3402 pattern_parts.push(quote! { v });
3403 } else {
3404 pattern_parts.push(quote! { _ });
3405 }
3406 }
3407
3408 let pattern = quote! { #name::#v_ident(#(#pattern_parts),*) };
3409 let match_expr = quote! { match e { #pattern => Some(v), _ => None } };
3410 let match_mut_expr = quote! { match e { #pattern => Some(v), _ => None } };
3411
3412 tokens.extend(quote! {
3413 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
3414 rust_keypaths::OptionalKeyPath::new(|e: &#name| #match_expr)
3415 }
3416 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #field_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #field_ty> {
3417 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| #match_mut_expr)
3418 }
3419 });
3420 }
3421 }
3422 Fields::Named(named) => {
3423 // Labeled enum variants - generate methods for each field
3424 for field in named.named.iter() {
3425 let field_ident = field.ident.as_ref().unwrap();
3426 let field_ty = &field.ty;
3427 let r_fn = format_ident!("{}_{}_r", snake, field_ident);
3428 let w_fn = format_ident!("{}_{}_w", snake, field_ident);
3429
3430 tokens.extend(quote! {
3431 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
3432 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident { #field_ident: v, .. } => Some(v), _ => None })
3433 }
3434 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #field_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #field_ty> {
3435 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| match e { #name::#v_ident { #field_ident: v, .. } => Some(v), _ => None })
3436 }
3437 });
3438 }
3439 }
3440 _ => {
3441 tokens.extend(quote! {
3442 compile_error!("Keypaths derive supports only unit, single-field, multi-field tuple, and labeled variants");
3443 });
3444 }
3445 }
3446 }
3447 tokens
3448 }
3449 _ => quote! {
3450 compile_error!("Keypaths derive supports only structs and enums");
3451 },
3452 };
3453
3454 let expanded = quote! {
3455 impl #name {
3456 #methods
3457 }
3458 };
3459
3460 TokenStream::from(expanded)
3461}
3462
3463fn extract_wrapper_inner_type(ty: &Type) -> (WrapperKind, Option<Type>) {
3464 use syn::{GenericArgument, PathArguments};
3465
3466 if let Type::Path(tp) = ty {
3467 if let Some(seg) = tp.path.segments.last() {
3468 let ident_str = seg.ident.to_string();
3469
3470 if let PathArguments::AngleBracketed(ab) = &seg.arguments {
3471 let args: Vec<_> = ab.args.iter().collect();
3472
3473 // Handle map types (HashMap, BTreeMap) - they have K, V parameters
3474 if ident_str == "HashMap" || ident_str == "BTreeMap" {
3475 if let (Some(_key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
3476 if let GenericArgument::Type(inner) = value_arg {
3477 eprintln!("Detected {} type, extracting value type", ident_str);
3478 // Check for nested Option in map values
3479 let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
3480 match (ident_str.as_str(), inner_kind) {
3481 ("HashMap", WrapperKind::Option) => {
3482 return (WrapperKind::HashMapOption, inner_inner);
3483 }
3484 _ => {
3485 return match ident_str.as_str() {
3486 "HashMap" => (WrapperKind::HashMap, Some(inner.clone())),
3487 "BTreeMap" => (WrapperKind::BTreeMap, Some(inner.clone())),
3488 _ => (WrapperKind::None, None),
3489 };
3490 }
3491 }
3492 }
3493 }
3494 }
3495 // Handle single-parameter container types
3496 else if let Some(arg) = args.get(0) {
3497 if let GenericArgument::Type(inner) = arg {
3498 // Check for nested containers first
3499 let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
3500
3501 // Handle nested combinations
3502 match (ident_str.as_str(), inner_kind) {
3503 ("Option", WrapperKind::Box) => {
3504 return (WrapperKind::OptionBox, inner_inner);
3505 }
3506 ("Option", WrapperKind::Rc) => {
3507 return (WrapperKind::OptionRc, inner_inner);
3508 }
3509 ("Option", WrapperKind::Arc) => {
3510 return (WrapperKind::OptionArc, inner_inner);
3511 }
3512 ("Option", WrapperKind::Vec) => {
3513 return (WrapperKind::OptionVec, inner_inner);
3514 }
3515 ("Option", WrapperKind::HashMap) => {
3516 return (WrapperKind::OptionHashMap, inner_inner);
3517 }
3518 ("Box", WrapperKind::Option) => {
3519 return (WrapperKind::BoxOption, inner_inner);
3520 }
3521 ("Rc", WrapperKind::Option) => {
3522 return (WrapperKind::RcOption, inner_inner);
3523 }
3524 ("Arc", WrapperKind::Option) => {
3525 return (WrapperKind::ArcOption, inner_inner);
3526 }
3527 ("Vec", WrapperKind::Option) => {
3528 return (WrapperKind::VecOption, inner_inner);
3529 }
3530 ("HashMap", WrapperKind::Option) => {
3531 return (WrapperKind::HashMapOption, inner_inner);
3532 }
3533 ("Arc", WrapperKind::Mutex) => {
3534 return (WrapperKind::ArcMutex, inner_inner);
3535 }
3536 ("Arc", WrapperKind::RwLock) => {
3537 return (WrapperKind::ArcRwLock, inner_inner);
3538 }
3539 _ => {
3540 // Handle single-level containers
3541 return match ident_str.as_str() {
3542 "Option" => (WrapperKind::Option, Some(inner.clone())),
3543 "Box" => (WrapperKind::Box, Some(inner.clone())),
3544 "Rc" => (WrapperKind::Rc, Some(inner.clone())),
3545 "Arc" => (WrapperKind::Arc, Some(inner.clone())),
3546 "Vec" => (WrapperKind::Vec, Some(inner.clone())),
3547 "HashSet" => (WrapperKind::HashSet, Some(inner.clone())),
3548 "BTreeSet" => (WrapperKind::BTreeSet, Some(inner.clone())),
3549 "VecDeque" => (WrapperKind::VecDeque, Some(inner.clone())),
3550 "LinkedList" => (WrapperKind::LinkedList, Some(inner.clone())),
3551 "BinaryHeap" => (WrapperKind::BinaryHeap, Some(inner.clone())),
3552 "Result" => (WrapperKind::Result, Some(inner.clone())),
3553 "Mutex" => (WrapperKind::Mutex, Some(inner.clone())),
3554 "RwLock" => (WrapperKind::RwLock, Some(inner.clone())),
3555 "Weak" => (WrapperKind::Weak, Some(inner.clone())),
3556 "Tagged" => (WrapperKind::Tagged, Some(inner.clone())),
3557 _ => (WrapperKind::None, None),
3558 };
3559 }
3560 }
3561 }
3562 }
3563 }
3564 }
3565 }
3566 (WrapperKind::None, None)
3567}
3568
3569
3570fn to_snake_case(name: &str) -> String {
3571 let mut out = String::new();
3572 for (i, c) in name.chars().enumerate() {
3573 if c.is_uppercase() {
3574 if i != 0 {
3575 out.push('_');
3576 }
3577 out.push(c.to_ascii_lowercase());
3578 } else {
3579 out.push(c);
3580 }
3581 }
3582 out
3583}
3584
3585/// Derives only writable keypath methods for struct fields.
3586///
3587/// This macro is a convenience wrapper that generates only writable keypaths,
3588/// equivalent to using `#[derive(Keypaths)]` with `#[Writable]` on the struct.
3589///
3590/// # Generated Methods
3591///
3592/// For each field `field_name`, generates:
3593///
3594/// - `field_name_w()` - Returns a `WritableKeyPath<Struct, FieldType>` for non-optional fields
3595/// - `field_name_fw()` - Returns a `WritableOptionalKeyPath<Struct, InnerType>` for optional/container fields
3596/// - `field_name_fw_at(index)` - Returns a `WritableOptionalKeyPath` for indexed mutable access
3597///
3598/// # Examples
3599///
3600/// ```rust,ignore
3601/// use keypaths_proc::WritableKeypaths;
3602///
3603/// #[derive(WritableKeypaths)]
3604/// struct Counter {
3605/// value: u32,
3606/// history: Vec<u32>,
3607/// }
3608///
3609/// // Usage:
3610/// let mut counter = Counter { value: 0, history: vec![] };
3611/// let value_path = Counter::value_w();
3612/// *value_path.get_mut(&mut counter) += 1;
3613/// ```
3614#[proc_macro_derive(WritableKeypaths)]
3615pub fn derive_writable_keypaths(input: TokenStream) -> TokenStream {
3616 let input = parse_macro_input!(input as DeriveInput);
3617 let name = input.ident;
3618
3619 let methods = match input.data {
3620 Data::Struct(data_struct) => match data_struct.fields {
3621 Fields::Named(fields_named) => {
3622 let mut tokens = proc_macro2::TokenStream::new();
3623 for field in fields_named.named.iter() {
3624 let field_ident = field.ident.as_ref().unwrap();
3625 let ty = &field.ty;
3626
3627 let w_fn = format_ident!("{}_w", field_ident);
3628 let fw_fn = format_ident!("{}_fw", field_ident);
3629 let fw_at_fn = format_ident!("{}_fw_at", field_ident);
3630
3631 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
3632
3633 match (kind, inner_ty.clone()) {
3634 (WrapperKind::Option, Some(inner_ty)) => {
3635 tokens.extend(quote! {
3636 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3637 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3638 }
3639 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3640 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut())
3641 }
3642 });
3643 }
3644 (WrapperKind::Vec, Some(inner_ty)) => {
3645 tokens.extend(quote! {
3646 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3647 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3648 }
3649 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3650 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.first_mut())
3651 }
3652 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>> {
3653 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index))
3654 }
3655 });
3656 }
3657 (WrapperKind::HashMap, Some(inner_ty)) => {
3658 tokens.extend(quote! {
3659 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3660 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3661 }
3662 pub fn #fw_fn(key: String) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3663 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key))
3664 }
3665 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>> {
3666 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key))
3667 }
3668 });
3669 }
3670 (WrapperKind::Box, Some(inner_ty)) => {
3671 tokens.extend(quote! {
3672 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3673 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut *s.#field_ident)
3674 }
3675 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3676 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut *s.#field_ident))
3677 }
3678 });
3679 }
3680 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
3681 tokens.extend(quote! {
3682 // Note: Rc/Arc are not writable due to shared ownership
3683 // Only providing readable methods for these types
3684 });
3685 }
3686 (WrapperKind::BTreeMap, Some(inner_ty)) => {
3687 tokens.extend(quote! {
3688 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3689 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3690 }
3691 pub fn #fw_fn(key: String) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3692 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key))
3693 }
3694 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>> {
3695 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key))
3696 }
3697 });
3698 }
3699 (WrapperKind::HashSet, Some(inner_ty)) => {
3700 tokens.extend(quote! {
3701 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3702 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3703 }
3704 // Note: HashSet doesn't have direct mutable access to elements
3705 // Only providing container-level writable access
3706 });
3707 }
3708 (WrapperKind::BTreeSet, Some(inner_ty)) => {
3709 tokens.extend(quote! {
3710 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3711 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3712 }
3713 // Note: BTreeSet doesn't have direct mutable access to elements
3714 // Only providing container-level writable access
3715 });
3716 }
3717 (WrapperKind::VecDeque, Some(inner_ty)) => {
3718 tokens.extend(quote! {
3719 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3720 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3721 }
3722 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3723 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.front_mut())
3724 }
3725 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>> {
3726 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index))
3727 }
3728 });
3729 }
3730 (WrapperKind::LinkedList, Some(inner_ty)) => {
3731 tokens.extend(quote! {
3732 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3733 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3734 }
3735 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3736 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.front_mut())
3737 }
3738 });
3739 }
3740 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
3741 tokens.extend(quote! {
3742 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3743 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3744 }
3745 // Note: BinaryHeap peek_mut() returns PeekMut wrapper that doesn't allow direct mutable access
3746 // Only providing container-level writable access
3747 });
3748 }
3749 (WrapperKind::Result, Some(inner_ty)) => {
3750 tokens.extend(quote! {
3751 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3752 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3753 }
3754 // Note: Result<T, E> doesn't support failable_writable for inner type
3755 // Only providing container-level writable access
3756 });
3757 }
3758 (WrapperKind::Mutex, Some(inner_ty)) => {
3759 tokens.extend(quote! {
3760 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3761 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3762 }
3763 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
3764 // Only providing container-level writable access
3765 });
3766 }
3767 (WrapperKind::RwLock, Some(inner_ty)) => {
3768 tokens.extend(quote! {
3769 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3770 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3771 }
3772 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
3773 // Only providing container-level writable access
3774 });
3775 }
3776 (WrapperKind::Weak, Some(inner_ty)) => {
3777 tokens.extend(quote! {
3778 // Note: Weak<T> doesn't support writable access (it's immutable)
3779 // No methods generated for Weak<T>
3780 });
3781 }
3782 (WrapperKind::None, None) => {
3783 tokens.extend(quote! {
3784 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3785 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3786 }
3787 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #ty>> {
3788 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#field_ident))
3789 }
3790 });
3791 }
3792 _ => {
3793 tokens.extend(quote! {
3794 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3795 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3796 }
3797 });
3798 }
3799 }
3800 }
3801 tokens
3802 }
3803 Fields::Unnamed(unnamed) => {
3804 let mut tokens = proc_macro2::TokenStream::new();
3805 for (idx, field) in unnamed.unnamed.iter().enumerate() {
3806 let idx_lit = syn::Index::from(idx);
3807 let ty = &field.ty;
3808
3809 let w_fn = format_ident!("f{}_w", idx);
3810 let fw_fn = format_ident!("f{}_fw", idx);
3811 let fw_at_fn = format_ident!("f{}_fw_at", idx);
3812
3813 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
3814
3815 match (kind, inner_ty.clone()) {
3816 (WrapperKind::Option, Some(inner_ty)) => {
3817 tokens.extend(quote! {
3818 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3819 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3820 }
3821 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3822 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.as_mut())
3823 }
3824 });
3825 }
3826 (WrapperKind::Vec, Some(inner_ty)) => {
3827 tokens.extend(quote! {
3828 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3829 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3830 }
3831 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3832 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.first_mut())
3833 }
3834 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>> {
3835 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.get_mut(*index))
3836 }
3837 });
3838 }
3839 (WrapperKind::HashMap, Some(inner_ty)) => {
3840 tokens.extend(quote! {
3841 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3842 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3843 }
3844 pub fn #fw_fn(key: String) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3845 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key))
3846 }
3847 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>> {
3848 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key))
3849 }
3850 });
3851 }
3852 (WrapperKind::Box, Some(inner_ty)) => {
3853 tokens.extend(quote! {
3854 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3855 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut *s.#idx_lit)
3856 }
3857 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3858 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut *s.#idx_lit))
3859 }
3860 });
3861 }
3862 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
3863 tokens.extend(quote! {
3864 // Note: Rc/Arc are not writable due to shared ownership
3865 // Only providing readable methods for these types
3866 });
3867 }
3868 (WrapperKind::BTreeMap, Some(inner_ty)) => {
3869 tokens.extend(quote! {
3870 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3871 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3872 }
3873 pub fn #fw_fn(key: String) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3874 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key))
3875 }
3876 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>> {
3877 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key))
3878 }
3879 });
3880 }
3881 (WrapperKind::HashSet, Some(inner_ty)) => {
3882 tokens.extend(quote! {
3883 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3884 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3885 }
3886 // Note: HashSet doesn't have direct mutable access to elements
3887 // Only providing container-level writable access
3888 });
3889 }
3890 (WrapperKind::BTreeSet, Some(inner_ty)) => {
3891 tokens.extend(quote! {
3892 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3893 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3894 }
3895 // Note: BTreeSet doesn't have direct mutable access to elements
3896 // Only providing container-level writable access
3897 });
3898 }
3899 (WrapperKind::VecDeque, Some(inner_ty)) => {
3900 tokens.extend(quote! {
3901 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3902 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3903 }
3904 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3905 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.front_mut())
3906 }
3907 });
3908 }
3909 (WrapperKind::LinkedList, Some(inner_ty)) => {
3910 tokens.extend(quote! {
3911 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3912 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3913 }
3914 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3915 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.front_mut())
3916 }
3917 });
3918 }
3919 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
3920 tokens.extend(quote! {
3921 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3922 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3923 }
3924 // Note: BinaryHeap peek_mut() returns PeekMut wrapper that doesn't allow direct mutable access
3925 // Only providing container-level writable access
3926 });
3927 }
3928 (WrapperKind::Result, Some(inner_ty)) => {
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.#idx_lit)
3932 }
3933 // Note: Result<T, E> doesn't support failable_writable for inner type
3934 // Only providing container-level writable access
3935 });
3936 }
3937 (WrapperKind::Mutex, Some(inner_ty)) => {
3938 tokens.extend(quote! {
3939 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3940 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3941 }
3942 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
3943 // Only providing container-level writable access
3944 });
3945 }
3946 (WrapperKind::RwLock, Some(inner_ty)) => {
3947 tokens.extend(quote! {
3948 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3949 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3950 }
3951 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
3952 // Only providing container-level writable access
3953 });
3954 }
3955 (WrapperKind::Weak, Some(inner_ty)) => {
3956 tokens.extend(quote! {
3957 // Note: Weak<T> doesn't support writable access (it's immutable)
3958 // No methods generated for Weak<T>
3959 });
3960 }
3961 (WrapperKind::None, None) => {
3962 tokens.extend(quote! {
3963 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3964 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3965 }
3966 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #ty>> {
3967 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#idx_lit))
3968 }
3969 });
3970 }
3971 _ => {
3972 tokens.extend(quote! {
3973 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3974 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3975 }
3976 });
3977 }
3978 }
3979 }
3980 tokens
3981 }
3982 _ => quote! {
3983 compile_error!("WritableKeypaths derive supports only structs with named or unnamed fields");
3984 },
3985 },
3986 _ => quote! {
3987 compile_error!("WritableKeypaths derive supports only structs");
3988 },
3989 };
3990
3991 let expanded = quote! {
3992 impl #name {
3993 #methods
3994 }
3995 };
3996
3997 TokenStream::from(expanded)
3998}
3999
4000/// Derives a single keypath method for each struct field.
4001///
4002/// This macro generates a simplified set of keypath methods, creating only
4003/// the most commonly used readable keypaths. It's a lighter-weight alternative
4004/// to `Keypaths` when you only need basic field access.
4005///
4006/// # Generated Methods
4007///
4008/// For each field `field_name`, generates:
4009///
4010/// - `field_name_r()` - Returns a `KeyPath<Struct, FieldType>` for direct field access
4011///
4012/// # Examples
4013///
4014/// ```rust,ignore
4015/// use keypaths_proc::Keypath;
4016///
4017/// #[derive(Keypath)]
4018/// struct Point {
4019/// x: f64,
4020/// y: f64,
4021/// }
4022///
4023/// // Usage:
4024/// let point = Point { x: 1.0, y: 2.0 };
4025/// let x_path = Point::x_r();
4026/// let x_value = x_path.get(&point); // &f64
4027/// ```
4028#[proc_macro_derive(Keypath)]
4029pub fn derive_keypath(input: TokenStream) -> TokenStream {
4030 let input = parse_macro_input!(input as DeriveInput);
4031 let name = input.ident;
4032
4033 let methods = match input.data {
4034 Data::Struct(data_struct) => match data_struct.fields {
4035 Fields::Named(fields_named) => {
4036 let mut tokens = proc_macro2::TokenStream::new();
4037 for field in fields_named.named.iter() {
4038 let field_ident = field.ident.as_ref().unwrap();
4039 let ty = &field.ty;
4040
4041 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
4042
4043 match (kind, inner_ty.clone()) {
4044 (WrapperKind::Option, Some(inner_ty)) => {
4045 // For Option<T>, return failable readable keypath to inner type
4046 tokens.extend(quote! {
4047 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4048 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref())
4049 }
4050 });
4051 }
4052 (WrapperKind::Vec, Some(inner_ty)) => {
4053 // For Vec<T>, return failable readable keypath to first element
4054 tokens.extend(quote! {
4055 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4056 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first())
4057 }
4058 });
4059 }
4060 (WrapperKind::HashMap, Some(inner_ty)) => {
4061 // For HashMap<K,V>, return readable keypath to the container
4062 tokens.extend(quote! {
4063 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4064 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4065 }
4066 });
4067 }
4068 (WrapperKind::BTreeMap, Some(inner_ty)) => {
4069 // For BTreeMap<K,V>, return readable keypath to the container
4070 tokens.extend(quote! {
4071 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4072 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4073 }
4074 });
4075 }
4076 (WrapperKind::Box, Some(inner_ty)) => {
4077 // For Box<T>, return readable keypath to inner type
4078 tokens.extend(quote! {
4079 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4080 rust_keypaths::KeyPath::new(|s: &#name| &*s.#field_ident)
4081 }
4082 });
4083 }
4084 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
4085 // For Rc<T>/Arc<T>, return readable keypath to inner type
4086 tokens.extend(quote! {
4087 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4088 rust_keypaths::KeyPath::new(|s: &#name| &*s.#field_ident)
4089 }
4090 });
4091 }
4092 (WrapperKind::HashSet, Some(inner_ty)) => {
4093 // For HashSet<T>, return failable readable keypath to any element
4094 tokens.extend(quote! {
4095 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4096 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.iter().next())
4097 }
4098 });
4099 }
4100 (WrapperKind::BTreeSet, Some(inner_ty)) => {
4101 // For BTreeSet<T>, return failable readable keypath to any element
4102 tokens.extend(quote! {
4103 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4104 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.iter().next())
4105 }
4106 });
4107 }
4108 (WrapperKind::VecDeque, Some(inner_ty)) => {
4109 // For VecDeque<T>, return failable readable keypath to front element
4110 tokens.extend(quote! {
4111 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4112 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.front())
4113 }
4114 });
4115 }
4116 (WrapperKind::LinkedList, Some(inner_ty)) => {
4117 // For LinkedList<T>, return failable readable keypath to front element
4118 tokens.extend(quote! {
4119 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4120 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.front())
4121 }
4122 });
4123 }
4124 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
4125 // For BinaryHeap<T>, return failable readable keypath to peek element
4126 tokens.extend(quote! {
4127 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4128 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.peek())
4129 }
4130 });
4131 }
4132 (WrapperKind::Result, Some(inner_ty)) => {
4133 // For Result<T, E>, return failable readable keypath to Ok value
4134 tokens.extend(quote! {
4135 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4136 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref().ok())
4137 }
4138 });
4139 }
4140 (WrapperKind::Mutex, Some(inner_ty)) => {
4141 // For Mutex<T>, return readable keypath to the container (not inner type due to lifetime issues)
4142 tokens.extend(quote! {
4143 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4144 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4145 }
4146 });
4147 }
4148 (WrapperKind::RwLock, Some(inner_ty)) => {
4149 // For RwLock<T>, return readable keypath to the container (not inner type due to lifetime issues)
4150 tokens.extend(quote! {
4151 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4152 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4153 }
4154 });
4155 }
4156 (WrapperKind::Weak, Some(inner_ty)) => {
4157 // For Weak<T>, return readable keypath to the container (not inner type due to lifetime issues)
4158 tokens.extend(quote! {
4159 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4160 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4161 }
4162 });
4163 }
4164 (WrapperKind::None, None) => {
4165 // For basic types, return readable keypath
4166 tokens.extend(quote! {
4167 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4168 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4169 }
4170 });
4171 }
4172 _ => {
4173 // For unknown types, return readable keypath
4174 tokens.extend(quote! {
4175 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4176 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4177 }
4178 });
4179 }
4180 }
4181 }
4182 tokens
4183 }
4184 Fields::Unnamed(unnamed) => {
4185 let mut tokens = proc_macro2::TokenStream::new();
4186 for (idx, field) in unnamed.unnamed.iter().enumerate() {
4187 let idx_lit = syn::Index::from(idx);
4188 let ty = &field.ty;
4189 let field_name = format_ident!("f{}", idx);
4190
4191 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
4192
4193 match (kind, inner_ty.clone()) {
4194 (WrapperKind::Option, Some(inner_ty)) => {
4195 tokens.extend(quote! {
4196 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4197 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref())
4198 }
4199 });
4200 }
4201 (WrapperKind::Vec, Some(inner_ty)) => {
4202 tokens.extend(quote! {
4203 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4204 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
4205 }
4206 });
4207 }
4208 (WrapperKind::HashMap, Some(inner_ty)) => {
4209 tokens.extend(quote! {
4210 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4211 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4212 }
4213 });
4214 }
4215 (WrapperKind::BTreeMap, Some(inner_ty)) => {
4216 tokens.extend(quote! {
4217 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4218 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4219 }
4220 });
4221 }
4222 (WrapperKind::Box, Some(inner_ty)) => {
4223 tokens.extend(quote! {
4224 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4225 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
4226 }
4227 });
4228 }
4229 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
4230 tokens.extend(quote! {
4231 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4232 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
4233 }
4234 });
4235 }
4236 (WrapperKind::HashSet, Some(inner_ty)) => {
4237 tokens.extend(quote! {
4238 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4239 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.iter().next())
4240 }
4241 });
4242 }
4243 (WrapperKind::BTreeSet, Some(inner_ty)) => {
4244 tokens.extend(quote! {
4245 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4246 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.iter().next())
4247 }
4248 });
4249 }
4250 (WrapperKind::VecDeque, Some(inner_ty)) => {
4251 tokens.extend(quote! {
4252 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4253 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.front())
4254 }
4255 });
4256 }
4257 (WrapperKind::LinkedList, Some(inner_ty)) => {
4258 tokens.extend(quote! {
4259 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4260 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.front())
4261 }
4262 });
4263 }
4264 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
4265 tokens.extend(quote! {
4266 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4267 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.peek())
4268 }
4269 });
4270 }
4271 (WrapperKind::Result, Some(inner_ty)) => {
4272 tokens.extend(quote! {
4273 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4274 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref().ok())
4275 }
4276 });
4277 }
4278 (WrapperKind::Mutex, Some(inner_ty)) => {
4279 tokens.extend(quote! {
4280 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4281 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4282 }
4283 });
4284 }
4285 (WrapperKind::RwLock, Some(inner_ty)) => {
4286 tokens.extend(quote! {
4287 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4288 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4289 }
4290 });
4291 }
4292 (WrapperKind::Weak, Some(inner_ty)) => {
4293 tokens.extend(quote! {
4294 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4295 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4296 }
4297 });
4298 }
4299 (WrapperKind::None, None) => {
4300 tokens.extend(quote! {
4301 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4302 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4303 }
4304 });
4305 }
4306 _ => {
4307 tokens.extend(quote! {
4308 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4309 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4310 }
4311 });
4312 }
4313 }
4314 }
4315 tokens
4316 }
4317 _ => quote! {
4318 compile_error!("Keypath derive supports only structs with named or unnamed fields");
4319 },
4320 },
4321 Data::Enum(data_enum) => {
4322 let mut tokens = proc_macro2::TokenStream::new();
4323 for variant in data_enum.variants.iter() {
4324 let v_ident = &variant.ident;
4325 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
4326
4327 match &variant.fields {
4328 Fields::Unit => {
4329 // Unit variant - return readable keypath to the variant itself
4330 tokens.extend(quote! {
4331 pub fn #snake() -> rust_keypaths::KeyPath<#name, #name, impl for<'r> Fn(&'r #name) -> &'r #name> {
4332 rust_keypaths::KeyPath::new(|s: &#name| s)
4333 }
4334 });
4335 }
4336 Fields::Unnamed(unnamed) => {
4337 if unnamed.unnamed.len() == 1 {
4338 // Single-field tuple variant - smart keypath selection
4339 let field_ty = &unnamed.unnamed[0].ty;
4340 let (kind, inner_ty) = extract_wrapper_inner_type(field_ty);
4341
4342 match (kind, inner_ty.clone()) {
4343 (WrapperKind::Option, Some(inner_ty)) => {
4344 tokens.extend(quote! {
4345 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4346 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4347 #name::#v_ident(inner) => inner.as_ref(),
4348 _ => None,
4349 })
4350 }
4351 });
4352 }
4353 (WrapperKind::Vec, Some(inner_ty)) => {
4354 tokens.extend(quote! {
4355 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4356 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4357 #name::#v_ident(inner) => inner.first(),
4358 _ => None,
4359 })
4360 }
4361 });
4362 }
4363 (WrapperKind::HashMap, Some(inner_ty)) => {
4364 tokens.extend(quote! {
4365 pub fn #snake() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
4366 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4367 #name::#v_ident(inner) => Some(inner),
4368 _ => None,
4369 })
4370 }
4371 });
4372 }
4373 (WrapperKind::BTreeMap, Some(inner_ty)) => {
4374 tokens.extend(quote! {
4375 pub fn #snake() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
4376 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4377 #name::#v_ident(inner) => Some(inner),
4378 _ => None,
4379 })
4380 }
4381 });
4382 }
4383 (WrapperKind::Box, Some(inner_ty)) => {
4384 tokens.extend(quote! {
4385 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4386 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4387 #name::#v_ident(inner) => Some(&**inner),
4388 _ => None,
4389 })
4390 }
4391 });
4392 }
4393 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
4394 tokens.extend(quote! {
4395 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4396 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4397 #name::#v_ident(inner) => Some(&**inner),
4398 _ => None,
4399 })
4400 }
4401 });
4402 }
4403 (WrapperKind::HashSet, Some(inner_ty)) => {
4404 tokens.extend(quote! {
4405 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4406 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4407 #name::#v_ident(inner) => inner.iter().next(),
4408 _ => None,
4409 })
4410 }
4411 });
4412 }
4413 (WrapperKind::BTreeSet, Some(inner_ty)) => {
4414 tokens.extend(quote! {
4415 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4416 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4417 #name::#v_ident(inner) => inner.iter().next(),
4418 _ => None,
4419 })
4420 }
4421 });
4422 }
4423 (WrapperKind::VecDeque, Some(inner_ty)) => {
4424 tokens.extend(quote! {
4425 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4426 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4427 #name::#v_ident(inner) => inner.front(),
4428 _ => None,
4429 })
4430 }
4431 });
4432 }
4433 (WrapperKind::LinkedList, Some(inner_ty)) => {
4434 tokens.extend(quote! {
4435 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4436 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4437 #name::#v_ident(inner) => inner.front(),
4438 _ => None,
4439 })
4440 }
4441 });
4442 }
4443 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
4444 tokens.extend(quote! {
4445 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4446 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4447 #name::#v_ident(inner) => inner.peek(),
4448 _ => None,
4449 })
4450 }
4451 });
4452 }
4453 (WrapperKind::Result, Some(inner_ty)) => {
4454 tokens.extend(quote! {
4455 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4456 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4457 #name::#v_ident(inner) => inner.as_ref().ok(),
4458 _ => None,
4459 })
4460 }
4461 });
4462 }
4463 (WrapperKind::Mutex, Some(inner_ty)) => {
4464 tokens.extend(quote! {
4465 pub fn #snake() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
4466 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4467 #name::#v_ident(inner) => Some(inner),
4468 _ => None,
4469 })
4470 }
4471 });
4472 }
4473 (WrapperKind::RwLock, Some(inner_ty)) => {
4474 tokens.extend(quote! {
4475 pub fn #snake() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
4476 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4477 #name::#v_ident(inner) => Some(inner),
4478 _ => None,
4479 })
4480 }
4481 });
4482 }
4483 (WrapperKind::Weak, Some(inner_ty)) => {
4484 tokens.extend(quote! {
4485 pub fn #snake() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
4486 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4487 #name::#v_ident(inner) => Some(inner),
4488 _ => None,
4489 })
4490 }
4491 });
4492 }
4493 (WrapperKind::None, None) => {
4494 // Basic type - return failable readable keypath
4495 tokens.extend(quote! {
4496 pub fn #snake() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
4497 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4498 #name::#v_ident(inner) => Some(inner),
4499 _ => None,
4500 })
4501 }
4502 });
4503 }
4504 _ => {
4505 // Unknown type - return failable readable keypath
4506 tokens.extend(quote! {
4507 pub fn #snake() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
4508 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4509 #name::#v_ident(inner) => Some(inner),
4510 _ => None,
4511 })
4512 }
4513 });
4514 }
4515 }
4516 } else {
4517 // Multi-field tuple variant - return failable readable keypath to the variant
4518 tokens.extend(quote! {
4519 pub fn #snake() -> rust_keypaths::KeyPath<#name, #name, impl for<'r> Fn(&'r #name) -> &'r #name> {
4520 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4521 #name::#v_ident(..) => Some(s),
4522 _ => None,
4523 })
4524 }
4525 });
4526 }
4527 }
4528 Fields::Named(_named) => {
4529 // Named field variant - return failable readable keypath to the variant
4530 tokens.extend(quote! {
4531 pub fn #snake() -> rust_keypaths::KeyPath<#name, #name, impl for<'r> Fn(&'r #name) -> &'r #name> {
4532 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4533 #name::#v_ident { .. } => Some(s),
4534 _ => None,
4535 })
4536 }
4537 });
4538 }
4539 }
4540 }
4541 tokens
4542 }
4543 _ => quote! {
4544 compile_error!("Keypath derive supports only structs and enums");
4545 },
4546 };
4547
4548 let expanded = quote! {
4549 impl #name {
4550 #methods
4551 }
4552 };
4553
4554 TokenStream::from(expanded)
4555}
4556
4557/// Derives only readable keypath methods for struct fields.
4558///
4559/// This macro is a convenience wrapper that generates only readable keypaths,
4560/// equivalent to using `#[derive(Keypaths)]` with `#[Readable]` on the struct.
4561///
4562/// # Generated Methods
4563///
4564/// For each field `field_name`, generates:
4565///
4566/// - `field_name_r()` - Returns a `KeyPath<Struct, FieldType>` for non-optional fields
4567/// - `field_name_fr()` - Returns an `OptionalKeyPath<Struct, InnerType>` for optional/container fields
4568/// - `field_name_fr_at(index)` - Returns an `OptionalKeyPath` for indexed access
4569///
4570/// # Examples
4571///
4572/// ```rust,ignore
4573/// use keypaths_proc::ReadableKeypaths;
4574///
4575/// #[derive(ReadableKeypaths)]
4576/// struct User {
4577/// name: String,
4578/// email: Option<String>,
4579/// tags: Vec<String>,
4580/// }
4581///
4582/// // Usage:
4583/// let user = User {
4584/// name: "Alice".to_string(),
4585/// email: Some("alice@example.com".to_string()),
4586/// tags: vec!["admin".to_string()],
4587/// };
4588///
4589/// let name_path = User::name_r();
4590/// let email_path = User::email_fr();
4591/// let name = name_path.get(&user); // &String
4592/// let email = email_path.get(&user); // Option<&String>
4593/// ```
4594#[proc_macro_derive(ReadableKeypaths)]
4595pub fn derive_readable_keypaths(input: TokenStream) -> TokenStream {
4596 let input = parse_macro_input!(input as DeriveInput);
4597 let name = input.ident;
4598
4599 let methods = match input.data {
4600 Data::Struct(data_struct) => match data_struct.fields {
4601 Fields::Named(fields_named) => {
4602 let mut tokens = proc_macro2::TokenStream::new();
4603 for field in fields_named.named.iter() {
4604 let field_ident = field.ident.as_ref().unwrap();
4605 let ty = &field.ty;
4606
4607 let r_fn = format_ident!("{}_r", field_ident);
4608 let fr_fn = format_ident!("{}_fr", field_ident);
4609 let fr_at_fn = format_ident!("{}_fr_at", field_ident);
4610
4611 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
4612
4613 match (kind, inner_ty.clone()) {
4614 (WrapperKind::Option, Some(inner_ty)) => {
4615 tokens.extend(quote! {
4616 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4617 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4618 }
4619 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4620 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref())
4621 }
4622 });
4623 }
4624 (WrapperKind::Vec, Some(inner_ty)) => {
4625 tokens.extend(quote! {
4626 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4627 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4628 }
4629 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4630 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first())
4631 }
4632 pub fn #fr_at_fn(index: usize) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4633 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index))
4634 }
4635 });
4636 }
4637 (WrapperKind::HashMap, Some(inner_ty)) => {
4638 tokens.extend(quote! {
4639 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4640 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4641 }
4642 pub fn #fr_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4643 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key))
4644 }
4645 pub fn #fr_at_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4646 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key))
4647 }
4648 });
4649 }
4650 (WrapperKind::Box, Some(inner_ty)) => {
4651 tokens.extend(quote! {
4652 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
4653 rust_keypaths::KeyPath::new(|s: &#name| &*s.#field_ident)
4654 }
4655 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4656 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#field_ident))
4657 }
4658 });
4659 }
4660 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
4661 tokens.extend(quote! {
4662 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
4663 rust_keypaths::KeyPath::new(|s: &#name| &*s.#field_ident)
4664 }
4665 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4666 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#field_ident))
4667 }
4668 });
4669 }
4670 (WrapperKind::BTreeMap, Some(inner_ty)) => {
4671 tokens.extend(quote! {
4672 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4673 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4674 }
4675 pub fn #fr_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4676 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key))
4677 }
4678 pub fn #fr_at_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4679 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key))
4680 }
4681 });
4682 }
4683 (WrapperKind::HashSet, Some(inner_ty)) => {
4684 tokens.extend(quote! {
4685 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4686 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4687 }
4688 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4689 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.iter().next())
4690 }
4691 });
4692 }
4693 (WrapperKind::BTreeSet, Some(inner_ty)) => {
4694 tokens.extend(quote! {
4695 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4696 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4697 }
4698 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4699 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.iter().next())
4700 }
4701 });
4702 }
4703 (WrapperKind::VecDeque, Some(inner_ty)) => {
4704 tokens.extend(quote! {
4705 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4706 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4707 }
4708 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4709 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.front())
4710 }
4711 pub fn #fr_at_fn(index: usize) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4712 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index))
4713 }
4714 });
4715 }
4716 (WrapperKind::LinkedList, Some(inner_ty)) => {
4717 tokens.extend(quote! {
4718 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4719 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4720 }
4721 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4722 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.front())
4723 }
4724 });
4725 }
4726 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
4727 tokens.extend(quote! {
4728 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4729 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4730 }
4731 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4732 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.peek())
4733 }
4734 });
4735 }
4736 (WrapperKind::Result, Some(inner_ty)) => {
4737 tokens.extend(quote! {
4738 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4739 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4740 }
4741 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4742 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref().ok())
4743 }
4744 });
4745 }
4746 (WrapperKind::Mutex, Some(inner_ty)) => {
4747 tokens.extend(quote! {
4748 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4749 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4750 }
4751 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
4752 // Only providing container-level access
4753 });
4754 }
4755 (WrapperKind::RwLock, Some(inner_ty)) => {
4756 tokens.extend(quote! {
4757 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4758 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4759 }
4760 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
4761 // Only providing container-level access
4762 });
4763 }
4764 (WrapperKind::Weak, Some(inner_ty)) => {
4765 tokens.extend(quote! {
4766 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4767 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4768 }
4769 // Note: Weak<T> doesn't support direct access to inner type due to lifetime constraints
4770 // Only providing container-level access
4771 });
4772 }
4773 (WrapperKind::None, None) => {
4774 tokens.extend(quote! {
4775 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4776 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4777 }
4778 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4779 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
4780 }
4781 });
4782 }
4783 _ => {
4784 tokens.extend(quote! {
4785 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4786 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4787 }
4788 });
4789 }
4790 }
4791 }
4792 tokens
4793 }
4794 Fields::Unnamed(unnamed) => {
4795 let mut tokens = proc_macro2::TokenStream::new();
4796 for (idx, field) in unnamed.unnamed.iter().enumerate() {
4797 let idx_lit = syn::Index::from(idx);
4798 let ty = &field.ty;
4799
4800 let r_fn = format_ident!("f{}_r", idx);
4801 let fr_fn = format_ident!("f{}_fr", idx);
4802 let fr_at_fn = format_ident!("f{}_fr_at", idx);
4803
4804 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
4805
4806 match (kind, inner_ty.clone()) {
4807 (WrapperKind::Option, Some(inner_ty)) => {
4808 tokens.extend(quote! {
4809 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4810 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4811 }
4812 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4813 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref())
4814 }
4815 });
4816 }
4817 (WrapperKind::Vec, Some(inner_ty)) => {
4818 tokens.extend(quote! {
4819 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4820 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4821 }
4822 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4823 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
4824 }
4825 pub fn #fr_at_fn(index: &'static usize) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4826 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.get(*index))
4827 }
4828 });
4829 }
4830 (WrapperKind::HashMap, Some(inner_ty)) => {
4831 tokens.extend(quote! {
4832 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4833 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4834 }
4835 pub fn #fr_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4836 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key))
4837 }
4838 pub fn #fr_at_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4839 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key))
4840 }
4841 });
4842 }
4843 (WrapperKind::Box, Some(inner_ty)) => {
4844 tokens.extend(quote! {
4845 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
4846 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
4847 }
4848 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4849 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#idx_lit))
4850 }
4851 });
4852 }
4853 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
4854 tokens.extend(quote! {
4855 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
4856 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
4857 }
4858 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4859 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#idx_lit))
4860 }
4861 });
4862 }
4863 (WrapperKind::BTreeMap, Some(inner_ty)) => {
4864 tokens.extend(quote! {
4865 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4866 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4867 }
4868 pub fn #fr_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4869 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key))
4870 }
4871 pub fn #fr_at_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4872 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key))
4873 }
4874 });
4875 }
4876 (WrapperKind::HashSet, Some(inner_ty)) => {
4877 tokens.extend(quote! {
4878 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4879 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4880 }
4881 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4882 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.iter().next())
4883 }
4884 });
4885 }
4886 (WrapperKind::BTreeSet, Some(inner_ty)) => {
4887 tokens.extend(quote! {
4888 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4889 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4890 }
4891 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4892 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.iter().next())
4893 }
4894 });
4895 }
4896 (WrapperKind::VecDeque, 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.#idx_lit)
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.#idx_lit.front())
4903 }
4904 });
4905 }
4906 (WrapperKind::LinkedList, 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.#idx_lit)
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.#idx_lit.front())
4913 }
4914 });
4915 }
4916 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
4917 tokens.extend(quote! {
4918 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4919 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4920 }
4921 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4922 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.peek())
4923 }
4924 });
4925 }
4926 (WrapperKind::Result, Some(inner_ty)) => {
4927 tokens.extend(quote! {
4928 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4929 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4930 }
4931 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4932 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref().ok())
4933 }
4934 });
4935 }
4936 (WrapperKind::Mutex, Some(inner_ty)) => {
4937 tokens.extend(quote! {
4938 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4939 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4940 }
4941 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
4942 // Only providing container-level access
4943 });
4944 }
4945 (WrapperKind::RwLock, Some(inner_ty)) => {
4946 tokens.extend(quote! {
4947 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4948 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4949 }
4950 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
4951 // Only providing container-level access
4952 });
4953 }
4954 (WrapperKind::Weak, Some(inner_ty)) => {
4955 tokens.extend(quote! {
4956 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4957 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4958 }
4959 // Note: Weak<T> doesn't support direct access to inner type due to lifetime constraints
4960 // Only providing container-level access
4961 });
4962 }
4963 (WrapperKind::None, None) => {
4964 tokens.extend(quote! {
4965 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4966 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4967 }
4968 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4969 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
4970 }
4971 });
4972 }
4973 _ => {
4974 tokens.extend(quote! {
4975 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4976 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4977 }
4978 });
4979 }
4980 }
4981 }
4982 tokens
4983 }
4984 _ => quote! {
4985 compile_error!("ReadableKeypaths derive supports only structs with named or unnamed fields");
4986 },
4987 },
4988 _ => quote! {
4989 compile_error!("ReadableKeypaths derive supports only structs");
4990 },
4991 };
4992
4993 let expanded = quote! {
4994 impl #name {
4995 #methods
4996 }
4997 };
4998
4999 TokenStream::from(expanded)
5000}
5001
5002/// Derives case path methods for enum variants.
5003///
5004/// Case paths (also known as prisms) provide a way to access and manipulate
5005/// enum variants in a composable way. They allow you to extract values from
5006/// enum variants and embed values back into variants.
5007///
5008/// # Generated Methods
5009///
5010/// For each variant `VariantName` with a single field of type `T`:
5011///
5012/// - `variant_name_case_r()` - Returns an `OptionalKeyPath<Enum, T>` for reading
5013/// - `variant_name_case_w()` - Returns a `WritableOptionalKeyPath<Enum, T>` for writing
5014/// - `variant_name_case_fr()` - Alias for `variant_name_case_r()`
5015/// - `variant_name_case_fw()` - Alias for `variant_name_case_w()`
5016/// - `variant_name_case_embed(value)` - Returns `Enum` by embedding a value into the variant
5017/// - `variant_name_case_enum()` - Returns an `EnumKeyPath<Enum, T>` with both extraction and embedding
5018///
5019/// For unit variants (no fields):
5020///
5021/// - `variant_name_case_fr()` - Returns an `OptionalKeyPath<Enum, ()>` that checks if variant matches
5022///
5023/// For multi-field tuple variants:
5024///
5025/// - `variant_name_case_fr()` - Returns an `OptionalKeyPath<Enum, (T1, T2, ...)>` for the tuple
5026/// - `variant_name_case_fw()` - Returns a `WritableOptionalKeyPath<Enum, (T1, T2, ...)>` for the tuple
5027///
5028/// # Attributes
5029///
5030/// ## Enum-level attributes:
5031///
5032/// - `#[All]` - Generate all methods (readable and writable)
5033/// - `#[Readable]` - Generate only readable methods (default)
5034/// - `#[Writable]` - Generate only writable methods
5035///
5036/// ## Variant-level attributes:
5037///
5038/// - `#[Readable]` - Generate readable methods for this variant only
5039/// - `#[Writable]` - Generate writable methods for this variant only
5040/// - `#[All]` - Generate all methods for this variant
5041///
5042/// # Examples
5043///
5044/// ```rust,ignore
5045/// use keypaths_proc::Casepaths;
5046///
5047/// #[derive(Casepaths)]
5048/// #[All]
5049/// enum Status {
5050/// Active(String),
5051/// Inactive,
5052/// Pending(u32),
5053/// }
5054///
5055/// // Usage:
5056/// let mut status = Status::Active("online".to_string());
5057///
5058/// // Extract value from variant
5059/// let active_path = Status::active_case_r();
5060/// if let Some(value) = active_path.get(&status) {
5061/// println!("Status is: {}", value);
5062/// }
5063///
5064/// // Embed value into variant
5065/// let new_status = Status::active_case_embed("offline".to_string());
5066///
5067/// // Use EnumKeyPath for both extraction and embedding
5068/// let active_enum = Status::active_case_enum();
5069/// let extracted = active_enum.extract(&status); // Option<&String>
5070/// let embedded = active_enum.embed("new".to_string()); // Status::Active("new")
5071/// ```
5072#[proc_macro_derive(Casepaths, attributes(Readable, Writable, All))]
5073pub fn derive_casepaths(input: TokenStream) -> TokenStream {
5074 let input = parse_macro_input!(input as DeriveInput);
5075 let name = input.ident;
5076
5077 // Get default scope from attributes
5078 let default_scope = match method_scope_from_attrs(&input.attrs) {
5079 Ok(Some(scope)) => scope,
5080 Ok(None) => MethodScope::Readable, // Default to readable
5081 Err(e) => return e.to_compile_error().into(),
5082 };
5083
5084 let tokens = match input.data {
5085 Data::Enum(data_enum) => {
5086 let mut tokens = proc_macro2::TokenStream::new();
5087 for variant in data_enum.variants.iter() {
5088 let v_ident = &variant.ident;
5089 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
5090
5091 // Get variant-specific scope
5092 let variant_scope = match method_scope_from_attrs(&variant.attrs) {
5093 Ok(Some(scope)) => scope,
5094 Ok(None) => default_scope.clone(),
5095 Err(_) => default_scope.clone(),
5096 };
5097
5098 let r_fn = format_ident!("{}_case_r", snake);
5099 let w_fn = format_ident!("{}_case_w", snake);
5100 let fr_fn = format_ident!("{}_case_fr", snake);
5101 let fw_fn = format_ident!("{}_case_fw", snake);
5102
5103 match &variant.fields {
5104 Fields::Unit => {
5105 // Unit variants - return OptionalKeyPath that checks if variant matches
5106 if variant_scope.includes_read() {
5107 tokens.extend(quote! {
5108 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, (), impl for<'r> Fn(&'r #name) -> Option<&'r ()>> {
5109 static UNIT: () = ();
5110 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident => Some(&UNIT), _ => None })
5111 }
5112 });
5113 }
5114 }
5115 Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
5116 let inner_ty = &unnamed.unnamed.first().unwrap().ty;
5117
5118 // Single-field variant - extract the inner value
5119 // Generate EnumKeyPath for single-field variants to support embedding
5120 if variant_scope.includes_read() {
5121 let embed_fn = format_ident!("{}_case_embed", snake);
5122 let enum_kp_fn = format_ident!("{}_case_enum", snake);
5123 tokens.extend(quote! {
5124 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
5125 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None })
5126 }
5127 // Alias for fr_fn - returns OptionalKeyPath (enum casepaths are always optional)
5128 pub fn #r_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
5129 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None })
5130 }
5131 // EnumKeyPath version with embedding support
5132 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> {
5133 rust_keypaths::EnumKeyPath::readable_enum(
5134 |value: #inner_ty| #name::#v_ident(value),
5135 |e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None }
5136 )
5137 }
5138 // Embed method - creates the enum variant from a value
5139 pub fn #embed_fn(value: #inner_ty) -> #name {
5140 #name::#v_ident(value)
5141 }
5142 });
5143 }
5144 if variant_scope.includes_write() {
5145 tokens.extend(quote! {
5146 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
5147 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| match e { #name::#v_ident(v) => Some(v), _ => None })
5148 }
5149 // Alias for fw_fn - returns WritableOptionalKeyPath (enum casepaths are always optional)
5150 pub fn #w_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
5151 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| match e { #name::#v_ident(v) => Some(v), _ => None })
5152 }
5153 });
5154 }
5155 }
5156 // Multi-field tuple variant: Enum::Variant(T1, T2, ...)
5157 Fields::Unnamed(unnamed) => {
5158 let field_types: Vec<_> = unnamed.unnamed.iter().map(|f| &f.ty).collect();
5159 let tuple_ty = quote! { (#(#field_types),*) };
5160
5161 // Generate pattern matching for tuple fields
5162 let field_patterns: Vec<_> = (0..unnamed.unnamed.len())
5163 .map(|i| format_ident!("f{}", i))
5164 .collect();
5165
5166 if variant_scope.includes_read() {
5167 tokens.extend(quote! {
5168 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #tuple_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #tuple_ty>> {
5169 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident(#(#field_patterns),*) => Some(&(#(#field_patterns),*)), _ => None })
5170 }
5171 });
5172 }
5173 if variant_scope.includes_write() {
5174 tokens.extend(quote! {
5175 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #tuple_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #tuple_ty>> {
5176 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| match e { #name::#v_ident(#(#field_patterns),*) => Some((#(#field_patterns),*)), _ => None })
5177 }
5178 });
5179 }
5180 }
5181
5182 // Labeled variant: Enum::Variant { field1: T1, field2: T2, ... }
5183 Fields::Named(named) => {
5184 let field_names: Vec<_> = named.named.iter().map(|f| f.ident.as_ref().unwrap()).collect();
5185 let field_types: Vec<_> = named.named.iter().map(|f| &f.ty).collect();
5186 let tuple_ty = quote! { (#(#field_types),*) };
5187
5188 if variant_scope.includes_read() {
5189 tokens.extend(quote! {
5190 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #tuple_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #tuple_ty>> {
5191 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident { #(#field_names: ref #field_names),* } => Some(&(#(#field_names),*)), _ => None })
5192 }
5193 });
5194 }
5195 if variant_scope.includes_write() {
5196 tokens.extend(quote! {
5197 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #tuple_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #tuple_ty>> {
5198 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| match e { #name::#v_ident { #(#field_names: ref mut #field_names),* } => Some((#(#field_names),*)), _ => None })
5199 }
5200 });
5201 }
5202 }
5203 }
5204 }
5205 tokens
5206 }
5207 _ => quote! { compile_error!("Casepaths can only be derived for enums"); },
5208 };
5209
5210 let expanded = quote! {
5211 impl #name {
5212 #tokens
5213 }
5214 };
5215
5216 TokenStream::from(expanded)
5217}
5218
5219/// Derives type-erased keypath methods with known root type.
5220///
5221/// `PartialKeyPath` is similar to Swift's `PartialKeyPath<Root>`. It hides
5222/// the `Value` type but keeps the `Root` type visible. This is useful for
5223/// storing collections of keypaths with the same root type but different value types.
5224///
5225/// # Generated Methods
5226///
5227/// For each field `field_name`, generates:
5228///
5229/// - `field_name_r()` - Returns a `PartialKeyPath<Struct>` for readable access
5230/// - `field_name_w()` - Returns a `PartialWritableKeyPath<Struct>` for writable access
5231/// - `field_name_fr()` - Returns a `PartialOptionalKeyPath<Struct>` for optional fields
5232/// - `field_name_fw()` - Returns a `PartialWritableOptionalKeyPath<Struct>` for optional writable fields
5233///
5234/// # Type Erasure
5235///
5236/// The `get()` method returns `&dyn Any`, requiring downcasting to access the actual value.
5237/// Use `get_as::<Root, Value>()` for type-safe access when you know the value type.
5238///
5239/// # Examples
5240///
5241/// ```rust,ignore
5242/// use keypaths_proc::PartialKeypaths;
5243/// use rust_keypaths::PartialKeyPath;
5244///
5245/// #[derive(PartialKeypaths)]
5246/// struct User {
5247/// name: String,
5248/// age: u32,
5249/// email: Option<String>,
5250/// }
5251///
5252/// // Usage:
5253/// let mut paths: Vec<PartialKeyPath<User>> = vec![
5254/// User::name_r(),
5255/// User::age_r(),
5256/// ];
5257///
5258/// let user = User {
5259/// name: "Alice".to_string(),
5260/// age: 30,
5261/// email: Some("alice@example.com".to_string()),
5262/// };
5263///
5264/// // Access values (requires type information)
5265/// if let Some(name) = paths[0].get_as::<User, String>(&user) {
5266/// println!("Name: {}", name);
5267/// }
5268/// ```
5269#[proc_macro_derive(PartialKeypaths)]
5270pub fn derive_partial_keypaths(input: TokenStream) -> TokenStream {
5271 let input = parse_macro_input!(input as DeriveInput);
5272 let name = input.ident;
5273
5274 let methods = match input.data {
5275 Data::Struct(data_struct) => match data_struct.fields {
5276 Fields::Named(fields_named) => {
5277 let mut tokens = proc_macro2::TokenStream::new();
5278 for field in fields_named.named.iter() {
5279 let field_ident = field.ident.as_ref().unwrap();
5280 let ty = &field.ty;
5281
5282 let r_fn = format_ident!("{}_partial_r", field_ident);
5283 let w_fn = format_ident!("{}_partial_w", field_ident);
5284 let fr_fn = format_ident!("{}_partial_fr", field_ident);
5285 let fw_fn = format_ident!("{}_partial_fw", field_ident);
5286 let fr_at_fn = format_ident!("{}_partial_fr_at", field_ident);
5287 let fw_at_fn = format_ident!("{}_partial_fw_at", field_ident);
5288 // Owned keypath method names
5289 let o_fn = format_ident!("{}_partial_o", field_ident);
5290 let fo_fn = format_ident!("{}_partial_fo", field_ident);
5291
5292 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
5293
5294 match (kind, inner_ty.clone()) {
5295 (WrapperKind::Option, Some(inner_ty)) => {
5296 tokens.extend(quote! {
5297 pub fn #r_fn() -> rust_keypaths::PartialOptionalKeyPath<#name> {
5298 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref()).to_partial()
5299 }
5300 pub fn #w_fn() -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5301 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut()).to_partial()
5302 }
5303 pub fn #fr_fn() -> rust_keypaths::PartialOptionalKeyPath<#name> {
5304 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref()).to_partial()
5305 }
5306 pub fn #fw_fn() -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5307 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut()).to_partial()
5308 }
5309 // Owned keypath methods - these don't make sense for Option types
5310 // as we can't return owned values from references
5311 });
5312 }
5313 (WrapperKind::Vec, Some(inner_ty)) => {
5314 tokens.extend(quote! {
5315 pub fn #fr_at_fn(index: usize) -> rust_keypaths::PartialOptionalKeyPath<#name> {
5316 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index)).to_partial()
5317 }
5318 pub fn #fw_at_fn(index: usize) -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5319 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index)).to_partial()
5320 }
5321 pub fn #r_fn() -> rust_keypaths::PartialKeyPath<#name> {
5322 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident).to_partial()
5323 }
5324 pub fn #w_fn() -> rust_keypaths::PartialWritableKeyPath<#name> {
5325 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident).to_partial()
5326 }
5327 pub fn #fr_fn() -> rust_keypaths::PartialOptionalKeyPath<#name> {
5328 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first()).to_partial()
5329 }
5330 pub fn #fw_fn() -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5331 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.first_mut()).to_partial()
5332 }
5333 // Owned keypath methods - not supported for Vec as we need references
5334 });
5335 }
5336 (WrapperKind::HashMap, Some(inner_ty)) => {
5337 tokens.extend(quote! {
5338 pub fn #r_fn() -> rust_keypaths::PartialKeyPath<#name> {
5339 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident).to_partial()
5340 }
5341 pub fn #w_fn() -> rust_keypaths::PartialWritableKeyPath<#name> {
5342 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident).to_partial()
5343 }
5344 pub fn #fr_fn(key: String) -> rust_keypaths::PartialOptionalKeyPath<#name> {
5345 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key)).to_partial()
5346 }
5347 pub fn #fw_fn(key: String) -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5348 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key)).to_partial()
5349 }
5350 pub fn #fr_at_fn(key: String) -> rust_keypaths::PartialOptionalKeyPath<#name> {
5351 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key)).to_partial()
5352 }
5353 pub fn #fw_at_fn(key: String) -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5354 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key)).to_partial()
5355 }
5356 // Owned keypath methods - not supported for HashMap as we need references
5357 });
5358 }
5359 _ => {
5360 // Default case for simple types
5361 tokens.extend(quote! {
5362 pub fn #r_fn() -> rust_keypaths::PartialKeyPath<#name> {
5363 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident).to_partial()
5364 }
5365 pub fn #w_fn() -> rust_keypaths::PartialWritableKeyPath<#name> {
5366 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident).to_partial()
5367 }
5368 // Owned keypath methods - not supported as we need references
5369 });
5370 }
5371 }
5372 }
5373 tokens
5374 }
5375 _ => quote! { compile_error!("PartialKeypaths can only be derived for structs with named fields"); },
5376 },
5377 _ => quote! { compile_error!("PartialKeypaths can only be derived for structs"); },
5378 };
5379
5380 let expanded = quote! {
5381 impl #name {
5382 #methods
5383 }
5384 };
5385
5386 TokenStream::from(expanded)
5387}
5388
5389/// Derives fully type-erased keypath methods.
5390///
5391/// `AnyKeyPath` is similar to Swift's `AnyKeyPath`. It hides both the `Root`
5392/// and `Value` types, making it useful for storing keypaths from different
5393/// struct types in the same collection.
5394///
5395/// # Generated Methods
5396///
5397/// For each field `field_name`, generates:
5398///
5399/// - `field_name_r()` - Returns an `AnyKeyPath` for readable access
5400/// - `field_name_w()` - Returns an `AnyWritableKeyPath` for writable access
5401/// - `field_name_fr()` - Returns an `AnyKeyPath` for optional fields
5402/// - `field_name_fw()` - Returns an `AnyWritableKeyPath` for optional writable fields
5403///
5404/// # Type Erasure
5405///
5406/// The `get()` method returns `&dyn Any`, requiring downcasting to access the actual value.
5407/// Use `get_as::<Root, Value>()` for type-safe access when you know both root and value types.
5408///
5409/// # Examples
5410///
5411/// ```rust,ignore
5412/// use keypaths_proc::AnyKeypaths;
5413/// use rust_keypaths::AnyKeyPath;
5414///
5415/// #[derive(AnyKeypaths)]
5416/// struct User {
5417/// name: String,
5418/// age: u32,
5419/// }
5420///
5421/// #[derive(AnyKeypaths)]
5422/// struct Product {
5423/// price: f64,
5424/// }
5425///
5426/// // Usage:
5427/// let mut paths: Vec<AnyKeyPath> = vec![
5428/// User::name_r(),
5429/// Product::price_r(),
5430/// ];
5431///
5432/// let user = User {
5433/// name: "Alice".to_string(),
5434/// age: 30,
5435/// };
5436///
5437/// // Access values (requires both root and value type information)
5438/// if let Some(name) = paths[0].get_as::<User, String>(&user) {
5439/// println!("Name: {}", name);
5440/// }
5441/// ```
5442#[proc_macro_derive(AnyKeypaths)]
5443pub fn derive_any_keypaths(input: TokenStream) -> TokenStream {
5444 let input = parse_macro_input!(input as DeriveInput);
5445 let name = input.ident;
5446
5447 let methods = match input.data {
5448 Data::Struct(data_struct) => match data_struct.fields {
5449 Fields::Named(fields_named) => {
5450 let mut tokens = proc_macro2::TokenStream::new();
5451 for field in fields_named.named.iter() {
5452 let field_ident = field.ident.as_ref().unwrap();
5453 let ty = &field.ty;
5454
5455 let r_fn = format_ident!("{}_any_r", field_ident);
5456 let w_fn = format_ident!("{}_any_w", field_ident);
5457 let fr_fn = format_ident!("{}_any_fr", field_ident);
5458 let fw_fn = format_ident!("{}_any_fw", field_ident);
5459 let fr_at_fn = format_ident!("{}_any_fr_at", field_ident);
5460 let fw_at_fn = format_ident!("{}_any_fw_at", field_ident);
5461 // Owned keypath method names
5462 let o_fn = format_ident!("{}_any_o", field_ident);
5463 let fo_fn = format_ident!("{}_any_fo", field_ident);
5464
5465 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
5466
5467 match (kind, inner_ty.clone()) {
5468 (WrapperKind::Option, Some(inner_ty)) => {
5469 tokens.extend(quote! {
5470 pub fn #r_fn() -> rust_keypaths::AnyKeyPath {
5471 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref()).to_any()
5472 }
5473 pub fn #w_fn() -> rust_keypaths::AnyWritableKeyPath {
5474 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut()).to_any()
5475 }
5476 pub fn #fr_fn() -> rust_keypaths::AnyKeyPath {
5477 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref()).to_any()
5478 }
5479 pub fn #fw_fn() -> rust_keypaths::AnyWritableKeyPath {
5480 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut()).to_any()
5481 }
5482 // Owned keypath methods - not supported for Option types
5483 });
5484 }
5485 (WrapperKind::Vec, Some(inner_ty)) => {
5486 tokens.extend(quote! {
5487 pub fn #fr_at_fn(index: usize) -> rust_keypaths::AnyKeyPath {
5488 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index)).to_any()
5489 }
5490 pub fn #fw_at_fn(index: usize) -> rust_keypaths::AnyWritableKeyPath {
5491 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index)).to_any()
5492 }
5493 pub fn #r_fn() -> rust_keypaths::AnyKeyPath {
5494 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident)).to_any()
5495 }
5496 pub fn #w_fn() -> rust_keypaths::AnyWritableKeyPath {
5497 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#field_ident)).to_any()
5498 }
5499 pub fn #fr_fn() -> rust_keypaths::AnyKeyPath {
5500 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first()).to_any()
5501 }
5502 pub fn #fw_fn() -> rust_keypaths::AnyWritableKeyPath {
5503 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.first_mut()).to_any()
5504 }
5505 // Owned keypath methods - not supported for Vec
5506 });
5507 }
5508 (WrapperKind::HashMap, Some(inner_ty)) => {
5509 tokens.extend(quote! {
5510 pub fn #r_fn() -> rust_keypaths::AnyKeyPath {
5511 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident)).to_any()
5512 }
5513 pub fn #w_fn() -> rust_keypaths::AnyWritableKeyPath {
5514 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#field_ident)).to_any()
5515 }
5516 pub fn #fr_fn(key: String) -> rust_keypaths::AnyKeyPath {
5517 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key)).to_any()
5518 }
5519 pub fn #fw_fn(key: String) -> rust_keypaths::AnyWritableKeyPath {
5520 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key)).to_any()
5521 }
5522 pub fn #fr_at_fn(key: String) -> rust_keypaths::AnyKeyPath {
5523 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key)).to_any()
5524 }
5525 pub fn #fw_at_fn(key: String) -> rust_keypaths::AnyWritableKeyPath {
5526 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key)).to_any()
5527 }
5528 // Owned keypath methods - not supported for HashMap
5529 });
5530 }
5531 _ => {
5532 // Default case for simple types
5533 tokens.extend(quote! {
5534 pub fn #r_fn() -> rust_keypaths::AnyKeyPath {
5535 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident)).to_any()
5536 }
5537 pub fn #w_fn() -> rust_keypaths::AnyWritableKeyPath {
5538 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#field_ident)).to_any()
5539 }
5540 // Owned keypath methods - not supported as we need references
5541 });
5542 }
5543 }
5544 }
5545 tokens
5546 }
5547 _ => quote! { compile_error!("AnyKeypaths can only be derived for structs with named fields"); },
5548 },
5549 _ => quote! { compile_error!("AnyKeypaths can only be derived for structs"); },
5550 };
5551
5552 let expanded = quote! {
5553 impl #name {
5554 #methods
5555 }
5556 };
5557
5558 TokenStream::from(expanded)
5559}
5560
5561// /// A helper macro that provides suggestions when there are type mismatches with container types.
5562// /// This macro helps users understand when to use adapter methods like for_arc(), for_box(), etc.
5563// #[proc_macro]
5564// pub fn keypath_suggestion(input: TokenStream) -> TokenStream {
5565// let input_str = input.to_string();
5566//
5567// // Parse the input to understand what the user is trying to do
5568// let suggestion = if input_str.contains("Arc<") && input_str.contains("KeyPaths<") {
5569// "💡 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();"
5570// } else if input_str.contains("Box<") && input_str.contains("KeyPaths<") {
5571// "💡 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();"
5572// } else if input_str.contains("Rc<") && input_str.contains("KeyPaths<") {
5573// "💡 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();"
5574// } else if input_str.contains("Option<") && input_str.contains("KeyPaths<") {
5575// "💡 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();"
5576// } else if input_str.contains("Result<") && input_str.contains("KeyPaths<") {
5577// "💡 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();"
5578// } else if input_str.contains("Mutex<") && input_str.contains("KeyPaths<") {
5579// "💡 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 */ });"
5580// } else if input_str.contains("RwLock<") && input_str.contains("KeyPaths<") {
5581// "💡 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 */ });"
5582// } else {
5583// "💡 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)"
5584// };
5585//
5586// let expanded = quote! {
5587// compile_error!(#suggestion);
5588// };
5589//
5590// TokenStream::from(expanded)
5591// }
5592
5593// /// A helper macro that provides compile-time suggestions for common KeyPaths usage patterns.
5594// /// This macro can be used to get helpful error messages when there are type mismatches.
5595// #[proc_macro]
5596// pub fn keypath_help(input: TokenStream) -> TokenStream {
5597// let input_str = input.to_string();
5598//
5599// let help_message = if input_str.is_empty() {
5600// "🔧 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()
5601// } else {
5602// format!("🔧 KeyPaths Help for '{}': Use adapter methods to work with different container types. See documentation for more details.", input_str)
5603// };
5604//
5605// let expanded = quote! {
5606// compile_error!(#help_message);
5607// };
5608//
5609// TokenStream::from(expanded)
5610// }