keypaths_proc/lib.rs
1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{Data, DeriveInput, Fields, Type, Attribute, parse_macro_input, spanned::Spanned};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6enum WrapperKind {
7 None,
8 Option,
9 Box,
10 Rc,
11 Arc,
12 Vec,
13 HashMap,
14 BTreeMap,
15 HashSet,
16 BTreeSet,
17 VecDeque,
18 LinkedList,
19 BinaryHeap,
20 // Error handling containers
21 Result,
22 // Synchronization primitives
23 Mutex,
24 RwLock,
25 // Reference counting with weak references
26 Weak,
27 // String types (currently unused)
28 // String,
29 // OsString,
30 // PathBuf,
31 // Nested container support
32 OptionBox,
33 OptionRc,
34 OptionArc,
35 BoxOption,
36 RcOption,
37 ArcOption,
38 VecOption,
39 OptionVec,
40 HashMapOption,
41 OptionHashMap,
42 // Arc with synchronization primitives
43 ArcMutex,
44 ArcRwLock,
45 // Tagged types
46 Tagged,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50enum MethodScope {
51 All,
52 Readable,
53 Writable,
54 Owned,
55}
56
57impl MethodScope {
58 fn includes_read(self) -> bool {
59 matches!(self, MethodScope::All | MethodScope::Readable)
60 }
61
62 fn includes_write(self) -> bool {
63 matches!(self, MethodScope::All | MethodScope::Writable)
64 }
65
66 fn includes_owned(self) -> bool {
67 matches!(self, MethodScope::All | MethodScope::Owned)
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72enum MethodKind {
73 Readable,
74 Writable,
75 Owned,
76}
77
78fn push_method(
79 target: &mut proc_macro2::TokenStream,
80 scope: MethodScope,
81 kind: MethodKind,
82 method_tokens: proc_macro2::TokenStream,
83) {
84 let include = match kind {
85 MethodKind::Readable => scope.includes_read(),
86 MethodKind::Writable => scope.includes_write(),
87 MethodKind::Owned => scope.includes_owned(),
88 };
89
90 if include {
91 target.extend(method_tokens);
92 }
93}
94
95fn method_scope_from_attrs(attrs: &[Attribute]) -> syn::Result<Option<MethodScope>> {
96 let mut scope: Option<MethodScope> = None;
97 for attr in attrs {
98 if attr.path().is_ident("Readable") {
99 if scope.is_some() {
100 return Err(syn::Error::new(attr.span(), "Only one of #[All], #[Readable], #[Writable], or #[Owned] may be used per field or variant"));
101 }
102 scope = Some(MethodScope::Readable);
103 } else if attr.path().is_ident("Writable") {
104 if scope.is_some() {
105 return Err(syn::Error::new(attr.span(), "Only one of #[All], #[Readable], #[Writable], or #[Owned] may be used per field or variant"));
106 }
107 scope = Some(MethodScope::Writable);
108 } else if attr.path().is_ident("Owned") {
109 if scope.is_some() {
110 return Err(syn::Error::new(attr.span(), "Only one of #[All], #[Readable], #[Writable], or #[Owned] may be used per field or variant"));
111 }
112 scope = Some(MethodScope::Owned);
113 } else if attr.path().is_ident("All") {
114 if scope.is_some() {
115 return Err(syn::Error::new(attr.span(), "Only one of #[All], #[Readable], #[Writable], or #[Owned] may be used per field or variant"));
116 }
117 scope = Some(MethodScope::All);
118 }
119 }
120 Ok(scope)
121}
122
123/// Derives keypath methods for struct fields.
124///
125/// This macro generates methods to create keypaths for accessing struct fields.
126/// By default, it generates readable keypaths, but you can control which methods
127/// are generated using attributes.
128///
129/// # Generated Methods
130///
131/// For each field `field_name`, the following methods are generated (depending on attributes):
132///
133/// - `field_name_r()` - Returns a `KeyPath<Struct, FieldType>` for non-optional fields
134/// - `field_name_w()` - Returns a `WritableKeyPath<Struct, FieldType>` for non-optional fields
135/// - `field_name_fr()` - Returns an `OptionalKeyPath<Struct, InnerType>` for optional/container fields
136/// - `field_name_fw()` - Returns a `WritableOptionalKeyPath<Struct, InnerType>` for optional/container fields
137/// - `field_name_fr_at(index)` - Returns an `OptionalKeyPath` for indexed access (Vec, HashMap, etc.)
138/// - `field_name_fw_at(index)` - Returns a `WritableOptionalKeyPath` for indexed mutable access
139/// - `field_name_o()` - Returns a `KeyPath` for owned access (when `#[Owned]` is used)
140/// - `field_name_fo()` - Returns an `OptionalKeyPath` for owned optional access
141///
142/// # Attributes
143///
144/// ## Struct-level attributes:
145///
146/// - `#[All]` - Generate all methods (readable, writable, and owned)
147/// - `#[Readable]` - Generate only readable methods (default)
148/// - `#[Writable]` - Generate only writable methods
149/// - `#[Owned]` - Generate only owned methods
150///
151/// ## Field-level attributes:
152///
153/// - `#[Readable]` - Generate readable methods for this field only
154/// - `#[Writable]` - Generate writable methods for this field only
155/// - `#[Owned]` - Generate owned methods for this field only
156/// - `#[All]` - Generate all methods for this field
157///
158/// # Supported Field Types
159///
160/// The macro automatically handles various container types:
161///
162/// - `Option<T>` - Generates failable keypaths
163/// - `Vec<T>` - Generates keypaths with iteration support
164/// - `Box<T>`, `Rc<T>`, `Arc<T>` - Generates keypaths that dereference
165/// - `HashMap<K, V>`, `BTreeMap<K, V>` - Generates key-based access methods
166/// - `Result<T, E>` - Generates failable keypaths for `Ok` variant
167/// - Tuple structs - Generates `f0_r()`, `f1_r()`, etc. for each field
168///
169/// # Examples
170///
171/// ```rust,ignore
172/// use keypaths_proc::Keypaths;
173///
174/// #[derive(Keypaths)]
175/// #[All] // Generate all methods
176/// struct User {
177/// name: String,
178/// age: Option<u32>,
179/// tags: Vec<String>,
180/// }
181///
182/// // Usage:
183/// let name_path = User::name_r(); // KeyPath<User, String>
184/// let age_path = User::age_fr(); // OptionalKeyPath<User, u32>
185/// let tags_path = User::tags_r(); // KeyPath<User, Vec<String>>
186///
187/// let user = User {
188/// name: "Alice".to_string(),
189/// age: Some(30),
190/// tags: vec!["admin".to_string()],
191/// };
192///
193/// // Read values
194/// let name = name_path.get(&user);
195/// let age = age_path.get(&user); // Returns Option<&u32>
196/// ```
197///
198/// # Field-level Control
199///
200/// ```rust,ignore
201/// #[derive(Keypaths)]
202/// struct Config {
203/// #[Readable] // Only readable methods for this field
204/// api_key: String,
205///
206/// #[Writable] // Only writable methods for this field
207/// counter: u32,
208///
209/// #[All] // All methods for this field
210/// settings: Option<Settings>,
211/// }
212/// ```
213#[proc_macro_derive(Keypaths, attributes(Readable, Writable, Owned, All))]
214pub fn derive_keypaths(input: TokenStream) -> TokenStream {
215 let input = parse_macro_input!(input as DeriveInput);
216 let name = input.ident;
217
218 let default_scope = match method_scope_from_attrs(&input.attrs) {
219 Ok(Some(scope)) => scope,
220 Ok(None) => MethodScope::Readable,
221 Err(err) => return err.to_compile_error().into(),
222 };
223
224 let methods = match input.data {
225 Data::Struct(data_struct) => match data_struct.fields {
226 Fields::Named(fields_named) => {/**/
227 let mut tokens = proc_macro2::TokenStream::new();
228 for field in fields_named.named.iter() {
229 let field_ident = field.ident.as_ref().unwrap();
230 let ty = &field.ty;
231
232 let r_fn = format_ident!("{}_r", field_ident);
233 let w_fn = format_ident!("{}_w", field_ident);
234 let fr_fn = format_ident!("{}_fr", field_ident);
235 let fw_fn = format_ident!("{}_fw", field_ident);
236 let fr_at_fn = format_ident!("{}_fr_at", field_ident);
237 let fw_at_fn = format_ident!("{}_fw_at", field_ident);
238 // Owned keypath method names
239 let o_fn = format_ident!("{}_o", field_ident);
240 let fo_fn = format_ident!("{}_fo", field_ident);
241
242 let method_scope = match method_scope_from_attrs(&field.attrs) {
243 Ok(Some(scope)) => scope,
244 Ok(None) => default_scope,
245 Err(err) => return err.to_compile_error().into(),
246 };
247
248 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
249
250 match (kind, inner_ty.clone()) {
251 (WrapperKind::Option, Some(inner_ty)) => {
252 push_method(
253 &mut tokens,
254 method_scope,
255 MethodKind::Readable,
256 quote! {
257 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
258 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
259 }
260 },
261 );
262 let inner_ty_read = inner_ty.clone();
263 push_method(
264 &mut tokens,
265 method_scope,
266 MethodKind::Readable,
267 quote! {
268 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_read, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_read>> {
269 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref())
270 }
271 },
272 );
273 push_method(
274 &mut tokens,
275 method_scope,
276 MethodKind::Writable,
277 quote! {
278 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
279 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
280 }
281 },
282 );
283 let inner_ty_write = inner_ty.clone();
284 push_method(
285 &mut tokens,
286 method_scope,
287 MethodKind::Writable,
288 quote! {
289 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_write, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_write>> {
290 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut())
291 }
292 },
293 );
294 push_method(
295 &mut tokens,
296 method_scope,
297 MethodKind::Owned,
298 quote! {
299 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
300 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
301 }
302 },
303 );
304 // For Option fields, fo_fn() returns OptionalKeyPath that unwraps the Option
305 let inner_ty_owned = inner_ty.clone();
306 push_method(
307 &mut tokens,
308 method_scope,
309 MethodKind::Owned,
310 quote! {
311 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_owned, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_owned>> {
312 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref())
313 }
314 },
315 );
316 }
317 (WrapperKind::Vec, Some(inner_ty)) => {
318 let inner_ty_fr_at = inner_ty.clone();
319 push_method(
320 &mut tokens,
321 method_scope,
322 MethodKind::Readable,
323 quote! {
324 pub fn #fr_at_fn(index: usize) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr_at, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr_at>> {
325 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index))
326 }
327 },
328 );
329 push_method(
330 &mut tokens,
331 method_scope,
332 MethodKind::Readable,
333 quote! {
334 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
335 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
336 }
337 },
338 );
339 let inner_ty_fr = inner_ty.clone();
340 push_method(
341 &mut tokens,
342 method_scope,
343 MethodKind::Readable,
344 quote! {
345 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
346 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first())
347 }
348 },
349 );
350 let inner_ty_fw_at = inner_ty.clone();
351 push_method(
352 &mut tokens,
353 method_scope,
354 MethodKind::Writable,
355 quote! {
356 pub fn #fw_at_fn(index: usize) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw_at, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw_at>> {
357 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index))
358 }
359 },
360 );
361 push_method(
362 &mut tokens,
363 method_scope,
364 MethodKind::Writable,
365 quote! {
366 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
367 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
368 }
369 },
370 );
371 let inner_ty_fw = inner_ty.clone();
372 push_method(
373 &mut tokens,
374 method_scope,
375 MethodKind::Writable,
376 quote! {
377 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
378 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.first_mut())
379 }
380 },
381 );
382 push_method(
383 &mut tokens,
384 method_scope,
385 MethodKind::Owned,
386 quote! {
387 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
388 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
389 }
390 },
391 );
392 let inner_ty_fo = inner_ty.clone();
393 push_method(
394 &mut tokens,
395 method_scope,
396 MethodKind::Owned,
397 quote! {
398 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
399 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first())
400 }
401 },
402 );
403 }
404 (WrapperKind::HashMap, Some(inner_ty)) => {
405 push_method(
406 &mut tokens,
407 method_scope,
408 MethodKind::Readable,
409 quote! {
410 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
411 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
412 }
413 },
414 );
415 let inner_ty_fr = inner_ty.clone();
416 push_method(
417 &mut tokens,
418 method_scope,
419 MethodKind::Readable,
420 quote! {
421 pub fn #fr_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
422 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key))
423 }
424 },
425 );
426 let inner_ty_fr_at = inner_ty.clone();
427 push_method(
428 &mut tokens,
429 method_scope,
430 MethodKind::Readable,
431 quote! {
432 pub fn #fr_at_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr_at, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr_at>> {
433 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key))
434 }
435 },
436 );
437 push_method(
438 &mut tokens,
439 method_scope,
440 MethodKind::Writable,
441 quote! {
442 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
443 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
444 }
445 },
446 );
447 let inner_ty_fw = inner_ty.clone();
448 push_method(
449 &mut tokens,
450 method_scope,
451 MethodKind::Writable,
452 quote! {
453 pub fn #fw_fn(key: String) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
454 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key))
455 }
456 },
457 );
458 let inner_ty_fw_at = inner_ty.clone();
459 push_method(
460 &mut tokens,
461 method_scope,
462 MethodKind::Writable,
463 quote! {
464 pub fn #fw_at_fn(key: String) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw_at, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw_at>> {
465 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key))
466 }
467 },
468 );
469 push_method(
470 &mut tokens,
471 method_scope,
472 MethodKind::Owned,
473 quote! {
474 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
475 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
476 }
477 },
478 );
479 let inner_ty_fo = inner_ty.clone();
480 push_method(
481 &mut tokens,
482 method_scope,
483 MethodKind::Owned,
484 quote! {
485 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
486 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.values().next())
487 }
488 },
489 );
490 }
491 (WrapperKind::Box, Some(inner_ty)) => {
492 push_method(
493 &mut tokens,
494 method_scope,
495 MethodKind::Readable,
496 quote! {
497 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
498 rust_keypaths::KeyPath::new(|s: &#name| &*s.#field_ident)
499 }
500 },
501 );
502 let inner_ty_fr = inner_ty.clone();
503 push_method(
504 &mut tokens,
505 method_scope,
506 MethodKind::Readable,
507 quote! {
508 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
509 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#field_ident))
510 }
511 },
512 );
513 push_method(
514 &mut tokens,
515 method_scope,
516 MethodKind::Writable,
517 quote! {
518 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
519 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut *s.#field_ident)
520 }
521 },
522 );
523 let inner_ty_fw = inner_ty.clone();
524 push_method(
525 &mut tokens,
526 method_scope,
527 MethodKind::Writable,
528 quote! {
529 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
530 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut *s.#field_ident))
531 }
532 },
533 );
534 push_method(
535 &mut tokens,
536 method_scope,
537 MethodKind::Owned,
538 quote! {
539 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
540 rust_keypaths::KeyPath::new(|s: &#name| *s.#field_ident)
541 }
542 },
543 );
544 let inner_ty_fo = inner_ty.clone();
545 push_method(
546 &mut tokens,
547 method_scope,
548 MethodKind::Owned,
549 quote! {
550 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
551 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(*s.#field_ident))
552 }
553 },
554 );
555 }
556 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
557 push_method(
558 &mut tokens,
559 method_scope,
560 MethodKind::Readable,
561 quote! {
562 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
563 rust_keypaths::KeyPath::new(|s: &#name| s.#field_ident.as_ref())
564 }
565 },
566 );
567 let inner_ty_fr = inner_ty.clone();
568 push_method(
569 &mut tokens,
570 method_scope,
571 MethodKind::Readable,
572 quote! {
573 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
574 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(s.#field_ident.as_ref()))
575 }
576 },
577 );
578 push_method(
579 &mut tokens,
580 method_scope,
581 MethodKind::Owned,
582 quote! {
583 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
584 rust_keypaths::KeyPath::new(|s: &#name| s.#field_ident.as_ref())
585 }
586 },
587 );
588 let inner_ty_fo = inner_ty.clone();
589 push_method(
590 &mut tokens,
591 method_scope,
592 MethodKind::Owned,
593 quote! {
594 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
595 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(s.#field_ident.as_ref()))
596 }
597 },
598 );
599 }
600 (WrapperKind::BTreeMap, Some(inner_ty)) => {
601 push_method(
602 &mut tokens,
603 method_scope,
604 MethodKind::Readable,
605 quote! {
606 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
607 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
608 }
609 },
610 );
611 push_method(
612 &mut tokens,
613 method_scope,
614 MethodKind::Writable,
615 quote! {
616 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
617 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
618 }
619 },
620 );
621 push_method(
622 &mut tokens,
623 method_scope,
624 MethodKind::Owned,
625 quote! {
626 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
627 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
628 }
629 },
630 );
631 let inner_ty_fo = inner_ty.clone();
632 push_method(
633 &mut tokens,
634 method_scope,
635 MethodKind::Owned,
636 quote! {
637 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
638 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.into_values().next())
639 }
640 },
641 );
642 // Note: Key-based access methods for BTreeMap require the exact key type
643 // For now, we'll skip generating these methods to avoid generic constraint issues
644 }
645 (WrapperKind::HashSet, Some(inner_ty)) => {
646 push_method(
647 &mut tokens,
648 method_scope,
649 MethodKind::Readable,
650 quote! {
651 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
652 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
653 }
654 },
655 );
656 let inner_ty_fr = inner_ty.clone();
657 push_method(
658 &mut tokens,
659 method_scope,
660 MethodKind::Readable,
661 quote! {
662 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
663 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.iter().next())
664 }
665 },
666 );
667 push_method(
668 &mut tokens,
669 method_scope,
670 MethodKind::Writable,
671 quote! {
672 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
673 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
674 }
675 },
676 );
677 push_method(
678 &mut tokens,
679 method_scope,
680 MethodKind::Owned,
681 quote! {
682 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
683 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
684 }
685 },
686 );
687 let inner_ty_fo = inner_ty.clone();
688 push_method(
689 &mut tokens,
690 method_scope,
691 MethodKind::Owned,
692 quote! {
693 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
694 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.into_iter().next())
695 }
696 },
697 );
698 }
699 (WrapperKind::BTreeSet, Some(inner_ty)) => {
700 push_method(
701 &mut tokens,
702 method_scope,
703 MethodKind::Readable,
704 quote! {
705 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
706 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
707 }
708 },
709 );
710 let inner_ty_fr = inner_ty.clone();
711 push_method(
712 &mut tokens,
713 method_scope,
714 MethodKind::Readable,
715 quote! {
716 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
717 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.iter().next())
718 }
719 },
720 );
721 push_method(
722 &mut tokens,
723 method_scope,
724 MethodKind::Writable,
725 quote! {
726 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
727 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
728 }
729 },
730 );
731 push_method(
732 &mut tokens,
733 method_scope,
734 MethodKind::Owned,
735 quote! {
736 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
737 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
738 }
739 },
740 );
741 let inner_ty_fo = inner_ty.clone();
742 push_method(
743 &mut tokens,
744 method_scope,
745 MethodKind::Owned,
746 quote! {
747 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
748 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.into_iter().next())
749 }
750 },
751 );
752 }
753 (WrapperKind::VecDeque, Some(inner_ty)) => {
754 push_method(
755 &mut tokens,
756 method_scope,
757 MethodKind::Readable,
758 quote! {
759 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
760 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
761 }
762 },
763 );
764 let inner_ty_fr = inner_ty.clone();
765 push_method(
766 &mut tokens,
767 method_scope,
768 MethodKind::Readable,
769 quote! {
770 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
771 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.front())
772 }
773 },
774 );
775 let inner_ty_fr_at = inner_ty.clone();
776 push_method(
777 &mut tokens,
778 method_scope,
779 MethodKind::Readable,
780 quote! {
781 pub fn #fr_at_fn(index: usize) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr_at, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr_at>> {
782 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index))
783 }
784 },
785 );
786 push_method(
787 &mut tokens,
788 method_scope,
789 MethodKind::Writable,
790 quote! {
791 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
792 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
793 }
794 },
795 );
796 let inner_ty_fw = inner_ty.clone();
797 push_method(
798 &mut tokens,
799 method_scope,
800 MethodKind::Writable,
801 quote! {
802 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
803 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.front_mut())
804 }
805 },
806 );
807 let inner_ty_fw_at = inner_ty.clone();
808 push_method(
809 &mut tokens,
810 method_scope,
811 MethodKind::Writable,
812 quote! {
813 pub fn #fw_at_fn(index: usize) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw_at, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw_at>> {
814 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index))
815 }
816 },
817 );
818 push_method(
819 &mut tokens,
820 method_scope,
821 MethodKind::Owned,
822 quote! {
823 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
824 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
825 }
826 },
827 );
828 let inner_ty_fo = inner_ty.clone();
829 push_method(
830 &mut tokens,
831 method_scope,
832 MethodKind::Owned,
833 quote! {
834 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
835 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.into_iter().next())
836 }
837 },
838 );
839 }
840 (WrapperKind::LinkedList, Some(inner_ty)) => {
841 push_method(
842 &mut tokens,
843 method_scope,
844 MethodKind::Readable,
845 quote! {
846 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
847 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
848 }
849 },
850 );
851 let inner_ty_fr = inner_ty.clone();
852 push_method(
853 &mut tokens,
854 method_scope,
855 MethodKind::Readable,
856 quote! {
857 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
858 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.front())
859 }
860 },
861 );
862 push_method(
863 &mut tokens,
864 method_scope,
865 MethodKind::Writable,
866 quote! {
867 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
868 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
869 }
870 },
871 );
872 let inner_ty_fw = inner_ty.clone();
873 push_method(
874 &mut tokens,
875 method_scope,
876 MethodKind::Writable,
877 quote! {
878 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty_fw, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty_fw>> {
879 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.front_mut())
880 }
881 },
882 );
883 push_method(
884 &mut tokens,
885 method_scope,
886 MethodKind::Owned,
887 quote! {
888 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
889 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
890 }
891 },
892 );
893 let inner_ty_fo = inner_ty.clone();
894 push_method(
895 &mut tokens,
896 method_scope,
897 MethodKind::Owned,
898 quote! {
899 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
900 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.into_iter().next())
901 }
902 },
903 );
904 }
905 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
906 push_method(
907 &mut tokens,
908 method_scope,
909 MethodKind::Readable,
910 quote! {
911 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
912 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
913 }
914 },
915 );
916 push_method(
917 &mut tokens,
918 method_scope,
919 MethodKind::Writable,
920 quote! {
921 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
922 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
923 }
924 },
925 );
926 push_method(
927 &mut tokens,
928 method_scope,
929 MethodKind::Owned,
930 quote! {
931 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
932 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
933 }
934 },
935 );
936 let inner_ty_fo = inner_ty.clone();
937 push_method(
938 &mut tokens,
939 method_scope,
940 MethodKind::Owned,
941 quote! {
942 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
943 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.into_iter().next())
944 }
945 },
946 );
947 // Note: BinaryHeap peek() returns &T, but we need &inner_ty
948 // For now, we'll skip failable methods for BinaryHeap to avoid type issues
949 }
950 (WrapperKind::Result, Some(inner_ty)) => {
951 push_method(
952 &mut tokens,
953 method_scope,
954 MethodKind::Readable,
955 quote! {
956 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
957 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
958 }
959 },
960 );
961 let inner_ty_fr = inner_ty.clone();
962 push_method(
963 &mut tokens,
964 method_scope,
965 MethodKind::Readable,
966 quote! {
967 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fr, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fr>> {
968 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref().ok())
969 }
970 },
971 );
972 push_method(
973 &mut tokens,
974 method_scope,
975 MethodKind::Writable,
976 quote! {
977 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
978 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
979 }
980 },
981 );
982 // Note: Result<T, E> doesn't support failable_writable for inner type
983 // Only providing container-level writable access
984 push_method(
985 &mut tokens,
986 method_scope,
987 MethodKind::Owned,
988 quote! {
989 pub fn #o_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
990 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
991 }
992 },
993 );
994 let inner_ty_fo = inner_ty.clone();
995 push_method(
996 &mut tokens,
997 method_scope,
998 MethodKind::Owned,
999 quote! {
1000 pub fn #fo_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty_fo, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty_fo>> {
1001 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.ok())
1002 }
1003 },
1004 );
1005 }
1006 (WrapperKind::Mutex, Some(_inner_ty)) => {
1007 push_method(
1008 &mut tokens,
1009 method_scope,
1010 MethodKind::Readable,
1011 quote! {
1012 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
1013 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
1014 }
1015 },
1016 );
1017 push_method(
1018 &mut tokens,
1019 method_scope,
1020 MethodKind::Writable,
1021 quote! {
1022 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
1023 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
1024 }
1025 },
1026 );
1027 // 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.as_ref().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.as_ref().map(|r| &**r))
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.as_ref().map(|a| &**a))
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::EnumKeyPath<#name, (), impl for<'r> Fn(&'r #name) -> Option<&'r ()>, impl Fn(()) -> #name> {
2934 static UNIT: () = ();
2935 rust_keypaths::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath::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::EnumKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>, impl Fn(#inner_ty) -> #name> {
3363 rust_keypaths::EnumKeyPath::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::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3369 rust_keypaths::WritableOptionalKeyPath::new(
3370 |e: &mut #name| match e { #name::#v_ident(v) => Some(v), _ => None }
3371 )
3372 }
3373 });
3374 }
3375 _ => {
3376 tokens.extend(quote! {
3377 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> &'r #field_ty> {
3378 rust_keypaths::EnumKeyPath::readable_enum(
3379 #name::#v_ident,
3380 |e: &#name| match e { #name::#v_ident(v) => Some(&v), _ => None }
3381 )
3382 }
3383 });
3384 }
3385 }
3386 }
3387 Fields::Unnamed(unnamed) if unnamed.unnamed.len() > 1 => {
3388 // Multi-field tuple variants - generate methods for each field
3389 for (index, field) in unnamed.unnamed.iter().enumerate() {
3390 let field_ty = &field.ty;
3391 let field_fn = format_ident!("f{}", index);
3392 let r_fn = format_ident!("{}_{}_r", snake, field_fn);
3393 let w_fn = format_ident!("{}_{}_w", snake, field_fn);
3394
3395 // Generate pattern matching for this specific field
3396 let mut pattern_parts = Vec::new();
3397
3398 for i in 0..unnamed.unnamed.len() {
3399 if i == index {
3400 pattern_parts.push(quote! { v });
3401 } else {
3402 pattern_parts.push(quote! { _ });
3403 }
3404 }
3405
3406 let pattern = quote! { #name::#v_ident(#(#pattern_parts),*) };
3407 let match_expr = quote! { match e { #pattern => Some(v), _ => None } };
3408 let match_mut_expr = quote! { match e { #pattern => Some(v), _ => None } };
3409
3410 tokens.extend(quote! {
3411 pub fn #r_fn() -> rust_keypaths::OptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #field_ty>> {
3412 rust_keypaths::OptionalKeyPath::new(|e: &#name| #match_expr)
3413 }
3414 pub fn #w_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #field_ty>> {
3415 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| #match_mut_expr)
3416 }
3417 });
3418 }
3419 }
3420 Fields::Named(named) => {
3421 // Labeled enum variants - generate methods for each field
3422 for field in named.named.iter() {
3423 let field_ident = field.ident.as_ref().unwrap();
3424 let field_ty = &field.ty;
3425 let r_fn = format_ident!("{}_{}_r", snake, field_ident);
3426 let w_fn = format_ident!("{}_{}_w", snake, field_ident);
3427
3428 tokens.extend(quote! {
3429 pub fn #r_fn() -> rust_keypaths::OptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #field_ty>> {
3430 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident { #field_ident: v, .. } => Some(v), _ => None })
3431 }
3432 pub fn #w_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #field_ty>> {
3433 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| match e { #name::#v_ident { #field_ident: v, .. } => Some(v), _ => None })
3434 }
3435 });
3436 }
3437 }
3438 _ => {
3439 tokens.extend(quote! {
3440 compile_error!("Keypaths derive supports only unit, single-field, multi-field tuple, and labeled variants");
3441 });
3442 }
3443 }
3444 }
3445 tokens
3446 }
3447 _ => quote! {
3448 compile_error!("Keypaths derive supports only structs and enums");
3449 },
3450 };
3451
3452 let expanded = quote! {
3453 impl #name {
3454 #methods
3455 }
3456 };
3457
3458 TokenStream::from(expanded)
3459}
3460
3461fn extract_wrapper_inner_type(ty: &Type) -> (WrapperKind, Option<Type>) {
3462 use syn::{GenericArgument, PathArguments};
3463
3464 if let Type::Path(tp) = ty {
3465 if let Some(seg) = tp.path.segments.last() {
3466 let ident_str = seg.ident.to_string();
3467
3468 if let PathArguments::AngleBracketed(ab) = &seg.arguments {
3469 let args: Vec<_> = ab.args.iter().collect();
3470
3471 // Handle map types (HashMap, BTreeMap) - they have K, V parameters
3472 if ident_str == "HashMap" || ident_str == "BTreeMap" {
3473 if let (Some(_key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
3474 if let GenericArgument::Type(inner) = value_arg {
3475 eprintln!("Detected {} type, extracting value type", ident_str);
3476 // Check for nested Option in map values
3477 let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
3478 match (ident_str.as_str(), inner_kind) {
3479 ("HashMap", WrapperKind::Option) => {
3480 return (WrapperKind::HashMapOption, inner_inner);
3481 }
3482 _ => {
3483 return match ident_str.as_str() {
3484 "HashMap" => (WrapperKind::HashMap, Some(inner.clone())),
3485 "BTreeMap" => (WrapperKind::BTreeMap, Some(inner.clone())),
3486 _ => (WrapperKind::None, None),
3487 };
3488 }
3489 }
3490 }
3491 }
3492 }
3493 // Handle single-parameter container types
3494 else if let Some(arg) = args.get(0) {
3495 if let GenericArgument::Type(inner) = arg {
3496 // Check for nested containers first
3497 let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
3498
3499 // Handle nested combinations
3500 match (ident_str.as_str(), inner_kind) {
3501 ("Option", WrapperKind::Box) => {
3502 return (WrapperKind::OptionBox, inner_inner);
3503 }
3504 ("Option", WrapperKind::Rc) => {
3505 return (WrapperKind::OptionRc, inner_inner);
3506 }
3507 ("Option", WrapperKind::Arc) => {
3508 return (WrapperKind::OptionArc, inner_inner);
3509 }
3510 ("Option", WrapperKind::Vec) => {
3511 return (WrapperKind::OptionVec, inner_inner);
3512 }
3513 ("Option", WrapperKind::HashMap) => {
3514 return (WrapperKind::OptionHashMap, inner_inner);
3515 }
3516 ("Box", WrapperKind::Option) => {
3517 return (WrapperKind::BoxOption, inner_inner);
3518 }
3519 ("Rc", WrapperKind::Option) => {
3520 return (WrapperKind::RcOption, inner_inner);
3521 }
3522 ("Arc", WrapperKind::Option) => {
3523 return (WrapperKind::ArcOption, inner_inner);
3524 }
3525 ("Vec", WrapperKind::Option) => {
3526 return (WrapperKind::VecOption, inner_inner);
3527 }
3528 ("HashMap", WrapperKind::Option) => {
3529 return (WrapperKind::HashMapOption, inner_inner);
3530 }
3531 ("Arc", WrapperKind::Mutex) => {
3532 return (WrapperKind::ArcMutex, inner_inner);
3533 }
3534 ("Arc", WrapperKind::RwLock) => {
3535 return (WrapperKind::ArcRwLock, inner_inner);
3536 }
3537 _ => {
3538 // Handle single-level containers
3539 return match ident_str.as_str() {
3540 "Option" => (WrapperKind::Option, Some(inner.clone())),
3541 "Box" => (WrapperKind::Box, Some(inner.clone())),
3542 "Rc" => (WrapperKind::Rc, Some(inner.clone())),
3543 "Arc" => (WrapperKind::Arc, Some(inner.clone())),
3544 "Vec" => (WrapperKind::Vec, Some(inner.clone())),
3545 "HashSet" => (WrapperKind::HashSet, Some(inner.clone())),
3546 "BTreeSet" => (WrapperKind::BTreeSet, Some(inner.clone())),
3547 "VecDeque" => (WrapperKind::VecDeque, Some(inner.clone())),
3548 "LinkedList" => (WrapperKind::LinkedList, Some(inner.clone())),
3549 "BinaryHeap" => (WrapperKind::BinaryHeap, Some(inner.clone())),
3550 "Result" => (WrapperKind::Result, Some(inner.clone())),
3551 "Mutex" => (WrapperKind::Mutex, Some(inner.clone())),
3552 "RwLock" => (WrapperKind::RwLock, Some(inner.clone())),
3553 "Weak" => (WrapperKind::Weak, Some(inner.clone())),
3554 "Tagged" => (WrapperKind::Tagged, Some(inner.clone())),
3555 _ => (WrapperKind::None, None),
3556 };
3557 }
3558 }
3559 }
3560 }
3561 }
3562 }
3563 }
3564 (WrapperKind::None, None)
3565}
3566
3567
3568fn to_snake_case(name: &str) -> String {
3569 let mut out = String::new();
3570 for (i, c) in name.chars().enumerate() {
3571 if c.is_uppercase() {
3572 if i != 0 {
3573 out.push('_');
3574 }
3575 out.push(c.to_ascii_lowercase());
3576 } else {
3577 out.push(c);
3578 }
3579 }
3580 out
3581}
3582
3583/// Derives only writable keypath methods for struct fields.
3584///
3585/// This macro is a convenience wrapper that generates only writable keypaths,
3586/// equivalent to using `#[derive(Keypaths)]` with `#[Writable]` on the struct.
3587///
3588/// # Generated Methods
3589///
3590/// For each field `field_name`, generates:
3591///
3592/// - `field_name_w()` - Returns a `WritableKeyPath<Struct, FieldType>` for non-optional fields
3593/// - `field_name_fw()` - Returns a `WritableOptionalKeyPath<Struct, InnerType>` for optional/container fields
3594/// - `field_name_fw_at(index)` - Returns a `WritableOptionalKeyPath` for indexed mutable access
3595///
3596/// # Examples
3597///
3598/// ```rust,ignore
3599/// use keypaths_proc::WritableKeypaths;
3600///
3601/// #[derive(WritableKeypaths)]
3602/// struct Counter {
3603/// value: u32,
3604/// history: Vec<u32>,
3605/// }
3606///
3607/// // Usage:
3608/// let mut counter = Counter { value: 0, history: vec![] };
3609/// let value_path = Counter::value_w();
3610/// *value_path.get_mut(&mut counter) += 1;
3611/// ```
3612#[proc_macro_derive(WritableKeypaths)]
3613pub fn derive_writable_keypaths(input: TokenStream) -> TokenStream {
3614 let input = parse_macro_input!(input as DeriveInput);
3615 let name = input.ident;
3616
3617 let methods = match input.data {
3618 Data::Struct(data_struct) => match data_struct.fields {
3619 Fields::Named(fields_named) => {
3620 let mut tokens = proc_macro2::TokenStream::new();
3621 for field in fields_named.named.iter() {
3622 let field_ident = field.ident.as_ref().unwrap();
3623 let ty = &field.ty;
3624
3625 let w_fn = format_ident!("{}_w", field_ident);
3626 let fw_fn = format_ident!("{}_fw", field_ident);
3627 let fw_at_fn = format_ident!("{}_fw_at", field_ident);
3628
3629 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
3630
3631 match (kind, inner_ty.clone()) {
3632 (WrapperKind::Option, Some(inner_ty)) => {
3633 tokens.extend(quote! {
3634 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3635 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3636 }
3637 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3638 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut())
3639 }
3640 });
3641 }
3642 (WrapperKind::Vec, Some(inner_ty)) => {
3643 tokens.extend(quote! {
3644 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3645 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3646 }
3647 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3648 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.first_mut())
3649 }
3650 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>> {
3651 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index))
3652 }
3653 });
3654 }
3655 (WrapperKind::HashMap, Some(inner_ty)) => {
3656 tokens.extend(quote! {
3657 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3658 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3659 }
3660 pub fn #fw_fn(key: String) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3661 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key))
3662 }
3663 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>> {
3664 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key))
3665 }
3666 });
3667 }
3668 (WrapperKind::Box, Some(inner_ty)) => {
3669 tokens.extend(quote! {
3670 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3671 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut *s.#field_ident)
3672 }
3673 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3674 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut *s.#field_ident))
3675 }
3676 });
3677 }
3678 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
3679 tokens.extend(quote! {
3680 // Note: Rc/Arc are not writable due to shared ownership
3681 // Only providing readable methods for these types
3682 });
3683 }
3684 (WrapperKind::BTreeMap, Some(inner_ty)) => {
3685 tokens.extend(quote! {
3686 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3687 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3688 }
3689 pub fn #fw_fn(key: String) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3690 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key))
3691 }
3692 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>> {
3693 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key))
3694 }
3695 });
3696 }
3697 (WrapperKind::HashSet, Some(inner_ty)) => {
3698 tokens.extend(quote! {
3699 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3700 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3701 }
3702 // Note: HashSet doesn't have direct mutable access to elements
3703 // Only providing container-level writable access
3704 });
3705 }
3706 (WrapperKind::BTreeSet, Some(inner_ty)) => {
3707 tokens.extend(quote! {
3708 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3709 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3710 }
3711 // Note: BTreeSet doesn't have direct mutable access to elements
3712 // Only providing container-level writable access
3713 });
3714 }
3715 (WrapperKind::VecDeque, Some(inner_ty)) => {
3716 tokens.extend(quote! {
3717 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3718 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3719 }
3720 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3721 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.front_mut())
3722 }
3723 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>> {
3724 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index))
3725 }
3726 });
3727 }
3728 (WrapperKind::LinkedList, Some(inner_ty)) => {
3729 tokens.extend(quote! {
3730 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3731 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3732 }
3733 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3734 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.front_mut())
3735 }
3736 });
3737 }
3738 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
3739 tokens.extend(quote! {
3740 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3741 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3742 }
3743 // Note: BinaryHeap peek_mut() returns PeekMut wrapper that doesn't allow direct mutable access
3744 // Only providing container-level writable access
3745 });
3746 }
3747 (WrapperKind::Result, Some(inner_ty)) => {
3748 tokens.extend(quote! {
3749 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3750 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3751 }
3752 // Note: Result<T, E> doesn't support failable_writable for inner type
3753 // Only providing container-level writable access
3754 });
3755 }
3756 (WrapperKind::Mutex, Some(inner_ty)) => {
3757 tokens.extend(quote! {
3758 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3759 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3760 }
3761 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
3762 // Only providing container-level writable access
3763 });
3764 }
3765 (WrapperKind::RwLock, Some(inner_ty)) => {
3766 tokens.extend(quote! {
3767 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3768 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3769 }
3770 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
3771 // Only providing container-level writable access
3772 });
3773 }
3774 (WrapperKind::Weak, Some(inner_ty)) => {
3775 tokens.extend(quote! {
3776 // Note: Weak<T> doesn't support writable access (it's immutable)
3777 // No methods generated for Weak<T>
3778 });
3779 }
3780 (WrapperKind::None, None) => {
3781 tokens.extend(quote! {
3782 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3783 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3784 }
3785 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #ty>> {
3786 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#field_ident))
3787 }
3788 });
3789 }
3790 _ => {
3791 tokens.extend(quote! {
3792 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3793 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident)
3794 }
3795 });
3796 }
3797 }
3798 }
3799 tokens
3800 }
3801 Fields::Unnamed(unnamed) => {
3802 let mut tokens = proc_macro2::TokenStream::new();
3803 for (idx, field) in unnamed.unnamed.iter().enumerate() {
3804 let idx_lit = syn::Index::from(idx);
3805 let ty = &field.ty;
3806
3807 let w_fn = format_ident!("f{}_w", idx);
3808 let fw_fn = format_ident!("f{}_fw", idx);
3809 let fw_at_fn = format_ident!("f{}_fw_at", idx);
3810
3811 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
3812
3813 match (kind, inner_ty.clone()) {
3814 (WrapperKind::Option, Some(inner_ty)) => {
3815 tokens.extend(quote! {
3816 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3817 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3818 }
3819 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3820 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.as_mut())
3821 }
3822 });
3823 }
3824 (WrapperKind::Vec, Some(inner_ty)) => {
3825 tokens.extend(quote! {
3826 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3827 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3828 }
3829 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3830 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.first_mut())
3831 }
3832 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>> {
3833 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.get_mut(*index))
3834 }
3835 });
3836 }
3837 (WrapperKind::HashMap, Some(inner_ty)) => {
3838 tokens.extend(quote! {
3839 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3840 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3841 }
3842 pub fn #fw_fn(key: String) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3843 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key))
3844 }
3845 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>> {
3846 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key))
3847 }
3848 });
3849 }
3850 (WrapperKind::Box, Some(inner_ty)) => {
3851 tokens.extend(quote! {
3852 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #inner_ty> {
3853 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut *s.#idx_lit)
3854 }
3855 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3856 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut *s.#idx_lit))
3857 }
3858 });
3859 }
3860 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
3861 tokens.extend(quote! {
3862 // Note: Rc/Arc are not writable due to shared ownership
3863 // Only providing readable methods for these types
3864 });
3865 }
3866 (WrapperKind::BTreeMap, Some(inner_ty)) => {
3867 tokens.extend(quote! {
3868 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3869 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3870 }
3871 pub fn #fw_fn(key: String) -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3872 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key))
3873 }
3874 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>> {
3875 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#idx_lit.get_mut(&key))
3876 }
3877 });
3878 }
3879 (WrapperKind::HashSet, Some(inner_ty)) => {
3880 tokens.extend(quote! {
3881 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3882 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3883 }
3884 // Note: HashSet doesn't have direct mutable access to elements
3885 // Only providing container-level writable access
3886 });
3887 }
3888 (WrapperKind::BTreeSet, Some(inner_ty)) => {
3889 tokens.extend(quote! {
3890 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3891 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3892 }
3893 // Note: BTreeSet doesn't have direct mutable access to elements
3894 // Only providing container-level writable access
3895 });
3896 }
3897 (WrapperKind::VecDeque, Some(inner_ty)) => {
3898 tokens.extend(quote! {
3899 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3900 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3901 }
3902 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3903 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.front_mut())
3904 }
3905 });
3906 }
3907 (WrapperKind::LinkedList, Some(inner_ty)) => {
3908 tokens.extend(quote! {
3909 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3910 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3911 }
3912 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
3913 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#idx_lit.front_mut())
3914 }
3915 });
3916 }
3917 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
3918 tokens.extend(quote! {
3919 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3920 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3921 }
3922 // Note: BinaryHeap peek_mut() returns PeekMut wrapper that doesn't allow direct mutable access
3923 // Only providing container-level writable access
3924 });
3925 }
3926 (WrapperKind::Result, Some(inner_ty)) => {
3927 tokens.extend(quote! {
3928 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3929 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3930 }
3931 // Note: Result<T, E> doesn't support failable_writable for inner type
3932 // Only providing container-level writable access
3933 });
3934 }
3935 (WrapperKind::Mutex, Some(inner_ty)) => {
3936 tokens.extend(quote! {
3937 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3938 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3939 }
3940 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
3941 // Only providing container-level writable access
3942 });
3943 }
3944 (WrapperKind::RwLock, Some(inner_ty)) => {
3945 tokens.extend(quote! {
3946 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3947 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3948 }
3949 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
3950 // Only providing container-level writable access
3951 });
3952 }
3953 (WrapperKind::Weak, Some(inner_ty)) => {
3954 tokens.extend(quote! {
3955 // Note: Weak<T> doesn't support writable access (it's immutable)
3956 // No methods generated for Weak<T>
3957 });
3958 }
3959 (WrapperKind::None, None) => {
3960 tokens.extend(quote! {
3961 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3962 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3963 }
3964 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #ty>> {
3965 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#idx_lit))
3966 }
3967 });
3968 }
3969 _ => {
3970 tokens.extend(quote! {
3971 pub fn #w_fn() -> rust_keypaths::WritableKeyPath<#name, #ty, impl for<'r> Fn(&'r mut #name) -> &'r mut #ty> {
3972 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#idx_lit)
3973 }
3974 });
3975 }
3976 }
3977 }
3978 tokens
3979 }
3980 _ => quote! {
3981 compile_error!("WritableKeypaths derive supports only structs with named or unnamed fields");
3982 },
3983 },
3984 _ => quote! {
3985 compile_error!("WritableKeypaths derive supports only structs");
3986 },
3987 };
3988
3989 let expanded = quote! {
3990 impl #name {
3991 #methods
3992 }
3993 };
3994
3995 TokenStream::from(expanded)
3996}
3997
3998/// Derives a single keypath method for each struct field.
3999///
4000/// This macro generates a simplified set of keypath methods, creating only
4001/// the most commonly used readable keypaths. It's a lighter-weight alternative
4002/// to `Keypaths` when you only need basic field access.
4003///
4004/// # Generated Methods
4005///
4006/// For each field `field_name`, generates:
4007///
4008/// - `field_name_r()` - Returns a `KeyPath<Struct, FieldType>` for direct field access
4009///
4010/// # Examples
4011///
4012/// ```rust,ignore
4013/// use keypaths_proc::Keypath;
4014///
4015/// #[derive(Keypath)]
4016/// struct Point {
4017/// x: f64,
4018/// y: f64,
4019/// }
4020///
4021/// // Usage:
4022/// let point = Point { x: 1.0, y: 2.0 };
4023/// let x_path = Point::x_r();
4024/// let x_value = x_path.get(&point); // &f64
4025/// ```
4026#[proc_macro_derive(Keypath)]
4027pub fn derive_keypath(input: TokenStream) -> TokenStream {
4028 let input = parse_macro_input!(input as DeriveInput);
4029 let name = input.ident;
4030
4031 let methods = match input.data {
4032 Data::Struct(data_struct) => match data_struct.fields {
4033 Fields::Named(fields_named) => {
4034 let mut tokens = proc_macro2::TokenStream::new();
4035 for field in fields_named.named.iter() {
4036 let field_ident = field.ident.as_ref().unwrap();
4037 let ty = &field.ty;
4038
4039 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
4040
4041 match (kind, inner_ty.clone()) {
4042 (WrapperKind::Option, Some(inner_ty)) => {
4043 // For Option<T>, return failable readable keypath to inner type
4044 tokens.extend(quote! {
4045 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4046 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref())
4047 }
4048 });
4049 }
4050 (WrapperKind::Vec, Some(inner_ty)) => {
4051 // For Vec<T>, return failable readable keypath to first element
4052 tokens.extend(quote! {
4053 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4054 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first())
4055 }
4056 });
4057 }
4058 (WrapperKind::HashMap, Some(inner_ty)) => {
4059 // For HashMap<K,V>, return readable keypath to the container
4060 tokens.extend(quote! {
4061 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4062 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
4063 }
4064 });
4065 }
4066 (WrapperKind::BTreeMap, Some(inner_ty)) => {
4067 // For BTreeMap<K,V>, return readable keypath to the container
4068 tokens.extend(quote! {
4069 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4070 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
4071 }
4072 });
4073 }
4074 (WrapperKind::Box, Some(inner_ty)) => {
4075 // For Box<T>, return readable keypath to inner type
4076 tokens.extend(quote! {
4077 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4078 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#field_ident))
4079 }
4080 });
4081 }
4082 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
4083 // For Rc<T>/Arc<T>, return readable keypath to inner type
4084 tokens.extend(quote! {
4085 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4086 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#field_ident))
4087 }
4088 });
4089 }
4090 (WrapperKind::HashSet, Some(inner_ty)) => {
4091 // For HashSet<T>, return failable readable keypath to any element
4092 tokens.extend(quote! {
4093 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4094 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.iter().next())
4095 }
4096 });
4097 }
4098 (WrapperKind::BTreeSet, Some(inner_ty)) => {
4099 // For BTreeSet<T>, return failable readable keypath to any element
4100 tokens.extend(quote! {
4101 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4102 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.iter().next())
4103 }
4104 });
4105 }
4106 (WrapperKind::VecDeque, Some(inner_ty)) => {
4107 // For VecDeque<T>, return failable readable keypath to front element
4108 tokens.extend(quote! {
4109 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4110 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.front())
4111 }
4112 });
4113 }
4114 (WrapperKind::LinkedList, Some(inner_ty)) => {
4115 // For LinkedList<T>, return failable readable keypath to front element
4116 tokens.extend(quote! {
4117 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4118 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.front())
4119 }
4120 });
4121 }
4122 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
4123 // For BinaryHeap<T>, return failable readable keypath to peek element
4124 tokens.extend(quote! {
4125 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4126 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.peek())
4127 }
4128 });
4129 }
4130 (WrapperKind::Result, Some(inner_ty)) => {
4131 // For Result<T, E>, return failable readable keypath to Ok value
4132 tokens.extend(quote! {
4133 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4134 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref().ok())
4135 }
4136 });
4137 }
4138 (WrapperKind::Mutex, Some(inner_ty)) => {
4139 // For Mutex<T>, return readable keypath to the container (not inner type due to lifetime issues)
4140 tokens.extend(quote! {
4141 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4142 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
4143 }
4144 });
4145 }
4146 (WrapperKind::RwLock, Some(inner_ty)) => {
4147 // For RwLock<T>, return readable keypath to the container (not inner type due to lifetime issues)
4148 tokens.extend(quote! {
4149 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4150 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
4151 }
4152 });
4153 }
4154 (WrapperKind::Weak, Some(inner_ty)) => {
4155 // For Weak<T>, return readable keypath to the container (not inner type due to lifetime issues)
4156 tokens.extend(quote! {
4157 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4158 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
4159 }
4160 });
4161 }
4162 (WrapperKind::None, None) => {
4163 // For basic types, return readable keypath
4164 tokens.extend(quote! {
4165 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4166 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
4167 }
4168 });
4169 }
4170 _ => {
4171 // For unknown types, return readable keypath
4172 tokens.extend(quote! {
4173 pub fn #field_ident() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4174 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
4175 }
4176 });
4177 }
4178 }
4179 }
4180 tokens
4181 }
4182 Fields::Unnamed(unnamed) => {
4183 let mut tokens = proc_macro2::TokenStream::new();
4184 for (idx, field) in unnamed.unnamed.iter().enumerate() {
4185 let idx_lit = syn::Index::from(idx);
4186 let ty = &field.ty;
4187 let field_name = format_ident!("f{}", idx);
4188
4189 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
4190
4191 match (kind, inner_ty.clone()) {
4192 (WrapperKind::Option, Some(inner_ty)) => {
4193 tokens.extend(quote! {
4194 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4195 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref())
4196 }
4197 });
4198 }
4199 (WrapperKind::Vec, Some(inner_ty)) => {
4200 tokens.extend(quote! {
4201 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4202 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
4203 }
4204 });
4205 }
4206 (WrapperKind::HashMap, Some(inner_ty)) => {
4207 tokens.extend(quote! {
4208 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4209 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
4210 }
4211 });
4212 }
4213 (WrapperKind::BTreeMap, Some(inner_ty)) => {
4214 tokens.extend(quote! {
4215 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4216 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
4217 }
4218 });
4219 }
4220 (WrapperKind::Box, Some(inner_ty)) => {
4221 tokens.extend(quote! {
4222 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4223 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#idx_lit))
4224 }
4225 });
4226 }
4227 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
4228 tokens.extend(quote! {
4229 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4230 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#idx_lit))
4231 }
4232 });
4233 }
4234 (WrapperKind::HashSet, Some(inner_ty)) => {
4235 tokens.extend(quote! {
4236 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4237 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.iter().next())
4238 }
4239 });
4240 }
4241 (WrapperKind::BTreeSet, Some(inner_ty)) => {
4242 tokens.extend(quote! {
4243 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4244 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.iter().next())
4245 }
4246 });
4247 }
4248 (WrapperKind::VecDeque, Some(inner_ty)) => {
4249 tokens.extend(quote! {
4250 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4251 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.front())
4252 }
4253 });
4254 }
4255 (WrapperKind::LinkedList, Some(inner_ty)) => {
4256 tokens.extend(quote! {
4257 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4258 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.front())
4259 }
4260 });
4261 }
4262 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
4263 tokens.extend(quote! {
4264 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4265 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.peek())
4266 }
4267 });
4268 }
4269 (WrapperKind::Result, Some(inner_ty)) => {
4270 tokens.extend(quote! {
4271 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4272 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref().ok())
4273 }
4274 });
4275 }
4276 (WrapperKind::Mutex, Some(inner_ty)) => {
4277 tokens.extend(quote! {
4278 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4279 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
4280 }
4281 });
4282 }
4283 (WrapperKind::RwLock, Some(inner_ty)) => {
4284 tokens.extend(quote! {
4285 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4286 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
4287 }
4288 });
4289 }
4290 (WrapperKind::Weak, Some(inner_ty)) => {
4291 tokens.extend(quote! {
4292 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4293 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
4294 }
4295 });
4296 }
4297 (WrapperKind::None, None) => {
4298 tokens.extend(quote! {
4299 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4300 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
4301 }
4302 });
4303 }
4304 _ => {
4305 tokens.extend(quote! {
4306 pub fn #field_name() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4307 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
4308 }
4309 });
4310 }
4311 }
4312 }
4313 tokens
4314 }
4315 _ => quote! {
4316 compile_error!("Keypath derive supports only structs with named or unnamed fields");
4317 },
4318 },
4319 Data::Enum(data_enum) => {
4320 let mut tokens = proc_macro2::TokenStream::new();
4321 for variant in data_enum.variants.iter() {
4322 let v_ident = &variant.ident;
4323 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
4324
4325 match &variant.fields {
4326 Fields::Unit => {
4327 // Unit variant - return failable readable keypath to the variant itself
4328 tokens.extend(quote! {
4329 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, (), impl for<'r> Fn(&'r #name) -> Option<&'r ()>> {
4330 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4331 #name::#v_ident => {
4332 static UNIT: () = ();
4333 Some(&UNIT)
4334 },
4335 _ => None,
4336 })
4337 }
4338 });
4339 }
4340 Fields::Unnamed(unnamed) => {
4341 if unnamed.unnamed.len() == 1 {
4342 // Single-field tuple variant - smart keypath selection
4343 let field_ty = &unnamed.unnamed[0].ty;
4344 let (kind, inner_ty) = extract_wrapper_inner_type(field_ty);
4345
4346 match (kind, inner_ty.clone()) {
4347 (WrapperKind::Option, Some(inner_ty)) => {
4348 tokens.extend(quote! {
4349 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4350 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4351 #name::#v_ident(inner) => inner.as_ref(),
4352 _ => None,
4353 })
4354 }
4355 });
4356 }
4357 (WrapperKind::Vec, Some(inner_ty)) => {
4358 tokens.extend(quote! {
4359 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4360 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4361 #name::#v_ident(inner) => inner.first(),
4362 _ => None,
4363 })
4364 }
4365 });
4366 }
4367 (WrapperKind::HashMap, Some(inner_ty)) => {
4368 tokens.extend(quote! {
4369 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #field_ty>> {
4370 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4371 #name::#v_ident(inner) => Some(inner),
4372 _ => None,
4373 })
4374 }
4375 });
4376 }
4377 (WrapperKind::BTreeMap, Some(inner_ty)) => {
4378 tokens.extend(quote! {
4379 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #field_ty>> {
4380 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4381 #name::#v_ident(inner) => Some(inner),
4382 _ => None,
4383 })
4384 }
4385 });
4386 }
4387 (WrapperKind::Box, Some(inner_ty)) => {
4388 tokens.extend(quote! {
4389 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4390 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4391 #name::#v_ident(inner) => Some(&**inner),
4392 _ => None,
4393 })
4394 }
4395 });
4396 }
4397 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
4398 tokens.extend(quote! {
4399 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4400 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4401 #name::#v_ident(inner) => Some(&**inner),
4402 _ => None,
4403 })
4404 }
4405 });
4406 }
4407 (WrapperKind::HashSet, Some(inner_ty)) => {
4408 tokens.extend(quote! {
4409 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4410 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4411 #name::#v_ident(inner) => inner.iter().next(),
4412 _ => None,
4413 })
4414 }
4415 });
4416 }
4417 (WrapperKind::BTreeSet, Some(inner_ty)) => {
4418 tokens.extend(quote! {
4419 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4420 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4421 #name::#v_ident(inner) => inner.iter().next(),
4422 _ => None,
4423 })
4424 }
4425 });
4426 }
4427 (WrapperKind::VecDeque, Some(inner_ty)) => {
4428 tokens.extend(quote! {
4429 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4430 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4431 #name::#v_ident(inner) => inner.front(),
4432 _ => None,
4433 })
4434 }
4435 });
4436 }
4437 (WrapperKind::LinkedList, Some(inner_ty)) => {
4438 tokens.extend(quote! {
4439 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4440 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4441 #name::#v_ident(inner) => inner.front(),
4442 _ => None,
4443 })
4444 }
4445 });
4446 }
4447 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
4448 tokens.extend(quote! {
4449 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4450 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4451 #name::#v_ident(inner) => inner.peek(),
4452 _ => None,
4453 })
4454 }
4455 });
4456 }
4457 (WrapperKind::Result, Some(inner_ty)) => {
4458 tokens.extend(quote! {
4459 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4460 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4461 #name::#v_ident(inner) => inner.as_ref().ok(),
4462 _ => None,
4463 })
4464 }
4465 });
4466 }
4467 (WrapperKind::Mutex, Some(inner_ty)) => {
4468 tokens.extend(quote! {
4469 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #field_ty>> {
4470 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4471 #name::#v_ident(inner) => Some(inner),
4472 _ => None,
4473 })
4474 }
4475 });
4476 }
4477 (WrapperKind::RwLock, Some(inner_ty)) => {
4478 tokens.extend(quote! {
4479 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #field_ty>> {
4480 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4481 #name::#v_ident(inner) => Some(inner),
4482 _ => None,
4483 })
4484 }
4485 });
4486 }
4487 (WrapperKind::Weak, Some(inner_ty)) => {
4488 tokens.extend(quote! {
4489 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #field_ty>> {
4490 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4491 #name::#v_ident(inner) => Some(inner),
4492 _ => None,
4493 })
4494 }
4495 });
4496 }
4497 (WrapperKind::None, None) => {
4498 // Basic type - return failable readable keypath
4499 tokens.extend(quote! {
4500 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #field_ty>> {
4501 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4502 #name::#v_ident(inner) => Some(inner),
4503 _ => None,
4504 })
4505 }
4506 });
4507 }
4508 _ => {
4509 // Unknown type - return failable readable keypath
4510 tokens.extend(quote! {
4511 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #field_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #field_ty>> {
4512 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4513 #name::#v_ident(inner) => Some(inner),
4514 _ => None,
4515 })
4516 }
4517 });
4518 }
4519 }
4520 } else {
4521 // Multi-field tuple variant - return failable readable keypath to the variant
4522 tokens.extend(quote! {
4523 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #name, impl for<'r> Fn(&'r #name) -> Option<&'r #name>> {
4524 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4525 #name::#v_ident(..) => Some(s),
4526 _ => None,
4527 })
4528 }
4529 });
4530 }
4531 }
4532 Fields::Named(_named) => {
4533 // Named field variant - return failable readable keypath to the variant
4534 tokens.extend(quote! {
4535 pub fn #snake() -> rust_keypaths::OptionalKeyPath<#name, #name, impl for<'r> Fn(&'r #name) -> Option<&'r #name>> {
4536 rust_keypaths::OptionalKeyPath::new(|s: &#name| match s {
4537 #name::#v_ident { .. } => Some(s),
4538 _ => None,
4539 })
4540 }
4541 });
4542 }
4543 }
4544 }
4545 tokens
4546 }
4547 _ => quote! {
4548 compile_error!("Keypath derive supports only structs and enums");
4549 },
4550 };
4551
4552 let expanded = quote! {
4553 impl #name {
4554 #methods
4555 }
4556 };
4557
4558 TokenStream::from(expanded)
4559}
4560
4561/// Derives only readable keypath methods for struct fields.
4562///
4563/// This macro is a convenience wrapper that generates only readable keypaths,
4564/// equivalent to using `#[derive(Keypaths)]` with `#[Readable]` on the struct.
4565///
4566/// # Generated Methods
4567///
4568/// For each field `field_name`, generates:
4569///
4570/// - `field_name_r()` - Returns a `KeyPath<Struct, FieldType>` for non-optional fields
4571/// - `field_name_fr()` - Returns an `OptionalKeyPath<Struct, InnerType>` for optional/container fields
4572/// - `field_name_fr_at(index)` - Returns an `OptionalKeyPath` for indexed access
4573///
4574/// # Examples
4575///
4576/// ```rust,ignore
4577/// use keypaths_proc::ReadableKeypaths;
4578///
4579/// #[derive(ReadableKeypaths)]
4580/// struct User {
4581/// name: String,
4582/// email: Option<String>,
4583/// tags: Vec<String>,
4584/// }
4585///
4586/// // Usage:
4587/// let user = User {
4588/// name: "Alice".to_string(),
4589/// email: Some("alice@example.com".to_string()),
4590/// tags: vec!["admin".to_string()],
4591/// };
4592///
4593/// let name_path = User::name_r();
4594/// let email_path = User::email_fr();
4595/// let name = name_path.get(&user); // &String
4596/// let email = email_path.get(&user); // Option<&String>
4597/// ```
4598#[proc_macro_derive(ReadableKeypaths)]
4599pub fn derive_readable_keypaths(input: TokenStream) -> TokenStream {
4600 let input = parse_macro_input!(input as DeriveInput);
4601 let name = input.ident;
4602
4603 let methods = match input.data {
4604 Data::Struct(data_struct) => match data_struct.fields {
4605 Fields::Named(fields_named) => {
4606 let mut tokens = proc_macro2::TokenStream::new();
4607 for field in fields_named.named.iter() {
4608 let field_ident = field.ident.as_ref().unwrap();
4609 let ty = &field.ty;
4610
4611 let r_fn = format_ident!("{}_r", field_ident);
4612 let fr_fn = format_ident!("{}_fr", field_ident);
4613 let fr_at_fn = format_ident!("{}_fr_at", field_ident);
4614
4615 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
4616
4617 match (kind, inner_ty.clone()) {
4618 (WrapperKind::Option, Some(inner_ty)) => {
4619 tokens.extend(quote! {
4620 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4621 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4622 }
4623 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4624 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref())
4625 }
4626 });
4627 }
4628 (WrapperKind::Vec, Some(inner_ty)) => {
4629 tokens.extend(quote! {
4630 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4631 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4632 }
4633 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4634 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first())
4635 }
4636 pub fn #fr_at_fn(index: usize) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4637 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index))
4638 }
4639 });
4640 }
4641 (WrapperKind::HashMap, Some(inner_ty)) => {
4642 tokens.extend(quote! {
4643 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4644 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4645 }
4646 pub fn #fr_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4647 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key))
4648 }
4649 pub fn #fr_at_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4650 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key))
4651 }
4652 });
4653 }
4654 (WrapperKind::Box, Some(inner_ty)) => {
4655 tokens.extend(quote! {
4656 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
4657 rust_keypaths::KeyPath::new(|s: &#name| &*s.#field_ident)
4658 }
4659 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4660 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#field_ident))
4661 }
4662 });
4663 }
4664 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
4665 tokens.extend(quote! {
4666 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
4667 rust_keypaths::KeyPath::new(|s: &#name| &*s.#field_ident)
4668 }
4669 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4670 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#field_ident))
4671 }
4672 });
4673 }
4674 (WrapperKind::BTreeMap, Some(inner_ty)) => {
4675 tokens.extend(quote! {
4676 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4677 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4678 }
4679 pub fn #fr_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4680 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key))
4681 }
4682 pub fn #fr_at_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4683 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key))
4684 }
4685 });
4686 }
4687 (WrapperKind::HashSet, Some(inner_ty)) => {
4688 tokens.extend(quote! {
4689 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4690 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4691 }
4692 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4693 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.iter().next())
4694 }
4695 });
4696 }
4697 (WrapperKind::BTreeSet, Some(inner_ty)) => {
4698 tokens.extend(quote! {
4699 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4700 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4701 }
4702 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4703 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.iter().next())
4704 }
4705 });
4706 }
4707 (WrapperKind::VecDeque, Some(inner_ty)) => {
4708 tokens.extend(quote! {
4709 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4710 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4711 }
4712 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4713 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.front())
4714 }
4715 pub fn #fr_at_fn(index: usize) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4716 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index))
4717 }
4718 });
4719 }
4720 (WrapperKind::LinkedList, Some(inner_ty)) => {
4721 tokens.extend(quote! {
4722 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4723 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4724 }
4725 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4726 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.front())
4727 }
4728 });
4729 }
4730 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
4731 tokens.extend(quote! {
4732 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4733 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4734 }
4735 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4736 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.peek())
4737 }
4738 });
4739 }
4740 (WrapperKind::Result, Some(inner_ty)) => {
4741 tokens.extend(quote! {
4742 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4743 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4744 }
4745 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4746 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref().ok())
4747 }
4748 });
4749 }
4750 (WrapperKind::Mutex, Some(inner_ty)) => {
4751 tokens.extend(quote! {
4752 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4753 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4754 }
4755 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
4756 // Only providing container-level access
4757 });
4758 }
4759 (WrapperKind::RwLock, Some(inner_ty)) => {
4760 tokens.extend(quote! {
4761 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4762 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4763 }
4764 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
4765 // Only providing container-level access
4766 });
4767 }
4768 (WrapperKind::Weak, Some(inner_ty)) => {
4769 tokens.extend(quote! {
4770 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4771 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4772 }
4773 // Note: Weak<T> doesn't support direct access to inner type due to lifetime constraints
4774 // Only providing container-level access
4775 });
4776 }
4777 (WrapperKind::None, None) => {
4778 tokens.extend(quote! {
4779 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4780 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4781 }
4782 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4783 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident))
4784 }
4785 });
4786 }
4787 _ => {
4788 tokens.extend(quote! {
4789 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4790 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident)
4791 }
4792 });
4793 }
4794 }
4795 }
4796 tokens
4797 }
4798 Fields::Unnamed(unnamed) => {
4799 let mut tokens = proc_macro2::TokenStream::new();
4800 for (idx, field) in unnamed.unnamed.iter().enumerate() {
4801 let idx_lit = syn::Index::from(idx);
4802 let ty = &field.ty;
4803
4804 let r_fn = format_ident!("f{}_r", idx);
4805 let fr_fn = format_ident!("f{}_fr", idx);
4806 let fr_at_fn = format_ident!("f{}_fr_at", idx);
4807
4808 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
4809
4810 match (kind, inner_ty.clone()) {
4811 (WrapperKind::Option, Some(inner_ty)) => {
4812 tokens.extend(quote! {
4813 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4814 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4815 }
4816 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4817 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref())
4818 }
4819 });
4820 }
4821 (WrapperKind::Vec, Some(inner_ty)) => {
4822 tokens.extend(quote! {
4823 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4824 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4825 }
4826 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4827 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.first())
4828 }
4829 pub fn #fr_at_fn(index: &'static usize) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4830 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.get(*index))
4831 }
4832 });
4833 }
4834 (WrapperKind::HashMap, Some(inner_ty)) => {
4835 tokens.extend(quote! {
4836 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4837 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4838 }
4839 pub fn #fr_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4840 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key))
4841 }
4842 pub fn #fr_at_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4843 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key))
4844 }
4845 });
4846 }
4847 (WrapperKind::Box, Some(inner_ty)) => {
4848 tokens.extend(quote! {
4849 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
4850 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
4851 }
4852 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4853 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#idx_lit))
4854 }
4855 });
4856 }
4857 (WrapperKind::Rc, Some(inner_ty)) | (WrapperKind::Arc, Some(inner_ty)) => {
4858 tokens.extend(quote! {
4859 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> &'r #inner_ty> {
4860 rust_keypaths::KeyPath::new(|s: &#name| &*s.#idx_lit)
4861 }
4862 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4863 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&*s.#idx_lit))
4864 }
4865 });
4866 }
4867 (WrapperKind::BTreeMap, Some(inner_ty)) => {
4868 tokens.extend(quote! {
4869 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4870 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4871 }
4872 pub fn #fr_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4873 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key))
4874 }
4875 pub fn #fr_at_fn(key: String) -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4876 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#idx_lit.get(&key))
4877 }
4878 });
4879 }
4880 (WrapperKind::HashSet, Some(inner_ty)) => {
4881 tokens.extend(quote! {
4882 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4883 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4884 }
4885 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4886 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.iter().next())
4887 }
4888 });
4889 }
4890 (WrapperKind::BTreeSet, Some(inner_ty)) => {
4891 tokens.extend(quote! {
4892 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4893 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4894 }
4895 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4896 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.iter().next())
4897 }
4898 });
4899 }
4900 (WrapperKind::VecDeque, Some(inner_ty)) => {
4901 tokens.extend(quote! {
4902 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4903 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4904 }
4905 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4906 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.front())
4907 }
4908 });
4909 }
4910 (WrapperKind::LinkedList, Some(inner_ty)) => {
4911 tokens.extend(quote! {
4912 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4913 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4914 }
4915 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4916 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.front())
4917 }
4918 });
4919 }
4920 (WrapperKind::BinaryHeap, Some(inner_ty)) => {
4921 tokens.extend(quote! {
4922 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4923 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4924 }
4925 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4926 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.peek())
4927 }
4928 });
4929 }
4930 (WrapperKind::Result, Some(inner_ty)) => {
4931 tokens.extend(quote! {
4932 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4933 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4934 }
4935 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
4936 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#idx_lit.as_ref().ok())
4937 }
4938 });
4939 }
4940 (WrapperKind::Mutex, Some(inner_ty)) => {
4941 tokens.extend(quote! {
4942 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4943 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4944 }
4945 // Note: Mutex<T> doesn't support direct access to inner type due to lifetime constraints
4946 // Only providing container-level access
4947 });
4948 }
4949 (WrapperKind::RwLock, Some(inner_ty)) => {
4950 tokens.extend(quote! {
4951 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4952 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4953 }
4954 // Note: RwLock<T> doesn't support direct access to inner type due to lifetime constraints
4955 // Only providing container-level access
4956 });
4957 }
4958 (WrapperKind::Weak, Some(inner_ty)) => {
4959 tokens.extend(quote! {
4960 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4961 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4962 }
4963 // Note: Weak<T> doesn't support direct access to inner type due to lifetime constraints
4964 // Only providing container-level access
4965 });
4966 }
4967 (WrapperKind::None, None) => {
4968 tokens.extend(quote! {
4969 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4970 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4971 }
4972 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> Option<&'r #ty>> {
4973 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#idx_lit))
4974 }
4975 });
4976 }
4977 _ => {
4978 tokens.extend(quote! {
4979 pub fn #r_fn() -> rust_keypaths::KeyPath<#name, #ty, impl for<'r> Fn(&'r #name) -> &'r #ty> {
4980 rust_keypaths::KeyPath::new(|s: &#name| &s.#idx_lit)
4981 }
4982 });
4983 }
4984 }
4985 }
4986 tokens
4987 }
4988 _ => quote! {
4989 compile_error!("ReadableKeypaths derive supports only structs with named or unnamed fields");
4990 },
4991 },
4992 _ => quote! {
4993 compile_error!("ReadableKeypaths derive supports only structs");
4994 },
4995 };
4996
4997 let expanded = quote! {
4998 impl #name {
4999 #methods
5000 }
5001 };
5002
5003 TokenStream::from(expanded)
5004}
5005
5006/// Derives case path methods for enum variants.
5007///
5008/// Case paths (also known as prisms) provide a way to access and manipulate
5009/// enum variants in a composable way. They allow you to extract values from
5010/// enum variants and embed values back into variants.
5011///
5012/// # Generated Methods
5013///
5014/// For each variant `VariantName` with a single field of type `T`:
5015///
5016/// - `variant_name_case_r()` - Returns an `OptionalKeyPath<Enum, T>` for reading
5017/// - `variant_name_case_w()` - Returns a `WritableOptionalKeyPath<Enum, T>` for writing
5018/// - `variant_name_case_fr()` - Alias for `variant_name_case_r()`
5019/// - `variant_name_case_fw()` - Alias for `variant_name_case_w()`
5020/// - `variant_name_case_embed(value)` - Returns `Enum` by embedding a value into the variant
5021/// - `variant_name_case_enum()` - Returns an `EnumKeyPath<Enum, T>` with both extraction and embedding
5022///
5023/// For unit variants (no fields):
5024///
5025/// - `variant_name_case_fr()` - Returns an `OptionalKeyPath<Enum, ()>` that checks if variant matches
5026///
5027/// For multi-field tuple variants:
5028///
5029/// - `variant_name_case_fr()` - Returns an `OptionalKeyPath<Enum, (T1, T2, ...)>` for the tuple
5030/// - `variant_name_case_fw()` - Returns a `WritableOptionalKeyPath<Enum, (T1, T2, ...)>` for the tuple
5031///
5032/// # Attributes
5033///
5034/// ## Enum-level attributes:
5035///
5036/// - `#[All]` - Generate all methods (readable and writable)
5037/// - `#[Readable]` - Generate only readable methods (default)
5038/// - `#[Writable]` - Generate only writable methods
5039///
5040/// ## Variant-level attributes:
5041///
5042/// - `#[Readable]` - Generate readable methods for this variant only
5043/// - `#[Writable]` - Generate writable methods for this variant only
5044/// - `#[All]` - Generate all methods for this variant
5045///
5046/// # Examples
5047///
5048/// ```rust,ignore
5049/// use keypaths_proc::Casepaths;
5050///
5051/// #[derive(Casepaths)]
5052/// #[All]
5053/// enum Status {
5054/// Active(String),
5055/// Inactive,
5056/// Pending(u32),
5057/// }
5058///
5059/// // Usage:
5060/// let mut status = Status::Active("online".to_string());
5061///
5062/// // Extract value from variant
5063/// let active_path = Status::active_case_r();
5064/// if let Some(value) = active_path.get(&status) {
5065/// println!("Status is: {}", value);
5066/// }
5067///
5068/// // Embed value into variant
5069/// let new_status = Status::active_case_embed("offline".to_string());
5070///
5071/// // Use EnumKeyPath for both extraction and embedding
5072/// let active_enum = Status::active_case_enum();
5073/// let extracted = active_enum.extract(&status); // Option<&String>
5074/// let embedded = active_enum.embed("new".to_string()); // Status::Active("new")
5075/// ```
5076#[proc_macro_derive(Casepaths, attributes(Readable, Writable, All))]
5077pub fn derive_casepaths(input: TokenStream) -> TokenStream {
5078 let input = parse_macro_input!(input as DeriveInput);
5079 let name = input.ident;
5080
5081 // Get default scope from attributes
5082 let default_scope = match method_scope_from_attrs(&input.attrs) {
5083 Ok(Some(scope)) => scope,
5084 Ok(None) => MethodScope::Readable, // Default to readable
5085 Err(e) => return e.to_compile_error().into(),
5086 };
5087
5088 let tokens = match input.data {
5089 Data::Enum(data_enum) => {
5090 let mut tokens = proc_macro2::TokenStream::new();
5091 for variant in data_enum.variants.iter() {
5092 let v_ident = &variant.ident;
5093 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
5094
5095 // Get variant-specific scope
5096 let variant_scope = match method_scope_from_attrs(&variant.attrs) {
5097 Ok(Some(scope)) => scope,
5098 Ok(None) => default_scope.clone(),
5099 Err(_) => default_scope.clone(),
5100 };
5101
5102 let r_fn = format_ident!("{}_case_r", snake);
5103 let w_fn = format_ident!("{}_case_w", snake);
5104 let fr_fn = format_ident!("{}_case_fr", snake);
5105 let fw_fn = format_ident!("{}_case_fw", snake);
5106
5107 match &variant.fields {
5108 Fields::Unit => {
5109 // Unit variants - return OptionalKeyPath that checks if variant matches
5110 if variant_scope.includes_read() {
5111 tokens.extend(quote! {
5112 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, (), impl for<'r> Fn(&'r #name) -> Option<&'r ()>> {
5113 static UNIT: () = ();
5114 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident => Some(&UNIT), _ => None })
5115 }
5116 });
5117 }
5118 }
5119 Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
5120 let inner_ty = &unnamed.unnamed.first().unwrap().ty;
5121
5122 // Single-field variant - extract the inner value
5123 // Generate EnumKeyPath for single-field variants to support embedding
5124 if variant_scope.includes_read() {
5125 let embed_fn = format_ident!("{}_case_embed", snake);
5126 let enum_kp_fn = format_ident!("{}_case_enum", snake);
5127 tokens.extend(quote! {
5128 pub fn #fr_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 // Alias for fr_fn - returns OptionalKeyPath (enum casepaths are always optional)
5132 pub fn #r_fn() -> rust_keypaths::OptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #inner_ty>> {
5133 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None })
5134 }
5135 // EnumKeyPath version with embedding support
5136 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> {
5137 rust_keypaths::EnumKeyPath::readable_enum(
5138 |value: #inner_ty| #name::#v_ident(value),
5139 |e: &#name| match e { #name::#v_ident(v) => Some(v), _ => None }
5140 )
5141 }
5142 // Embed method - creates the enum variant from a value
5143 pub fn #embed_fn(value: #inner_ty) -> #name {
5144 #name::#v_ident(value)
5145 }
5146 });
5147 }
5148 if variant_scope.includes_write() {
5149 tokens.extend(quote! {
5150 pub fn #fw_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 // Alias for fw_fn - returns WritableOptionalKeyPath (enum casepaths are always optional)
5154 pub fn #w_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #inner_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #inner_ty>> {
5155 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| match e { #name::#v_ident(v) => Some(v), _ => None })
5156 }
5157 });
5158 }
5159 }
5160 // Multi-field tuple variant: Enum::Variant(T1, T2, ...)
5161 Fields::Unnamed(unnamed) => {
5162 let field_types: Vec<_> = unnamed.unnamed.iter().map(|f| &f.ty).collect();
5163 let tuple_ty = quote! { (#(#field_types),*) };
5164
5165 // Generate pattern matching for tuple fields
5166 let field_patterns: Vec<_> = (0..unnamed.unnamed.len())
5167 .map(|i| format_ident!("f{}", i))
5168 .collect();
5169
5170 if variant_scope.includes_read() {
5171 tokens.extend(quote! {
5172 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #tuple_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #tuple_ty>> {
5173 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident(#(#field_patterns),*) => Some(&(#(#field_patterns),*)), _ => None })
5174 }
5175 });
5176 }
5177 if variant_scope.includes_write() {
5178 tokens.extend(quote! {
5179 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #tuple_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #tuple_ty>> {
5180 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| match e { #name::#v_ident(#(#field_patterns),*) => Some((#(#field_patterns),*)), _ => None })
5181 }
5182 });
5183 }
5184 }
5185
5186 // Labeled variant: Enum::Variant { field1: T1, field2: T2, ... }
5187 Fields::Named(named) => {
5188 let field_names: Vec<_> = named.named.iter().map(|f| f.ident.as_ref().unwrap()).collect();
5189 let field_types: Vec<_> = named.named.iter().map(|f| &f.ty).collect();
5190 let tuple_ty = quote! { (#(#field_types),*) };
5191
5192 if variant_scope.includes_read() {
5193 tokens.extend(quote! {
5194 pub fn #fr_fn() -> rust_keypaths::OptionalKeyPath<#name, #tuple_ty, impl for<'r> Fn(&'r #name) -> Option<&'r #tuple_ty>> {
5195 rust_keypaths::OptionalKeyPath::new(|e: &#name| match e { #name::#v_ident { #(#field_names: ref #field_names),* } => Some(&(#(#field_names),*)), _ => None })
5196 }
5197 });
5198 }
5199 if variant_scope.includes_write() {
5200 tokens.extend(quote! {
5201 pub fn #fw_fn() -> rust_keypaths::WritableOptionalKeyPath<#name, #tuple_ty, impl for<'r> Fn(&'r mut #name) -> Option<&'r mut #tuple_ty>> {
5202 rust_keypaths::WritableOptionalKeyPath::new(|e: &mut #name| match e { #name::#v_ident { #(#field_names: ref mut #field_names),* } => Some((#(#field_names),*)), _ => None })
5203 }
5204 });
5205 }
5206 }
5207 }
5208 }
5209 tokens
5210 }
5211 _ => quote! { compile_error!("Casepaths can only be derived for enums"); },
5212 };
5213
5214 let expanded = quote! {
5215 impl #name {
5216 #tokens
5217 }
5218 };
5219
5220 TokenStream::from(expanded)
5221}
5222
5223/// Derives type-erased keypath methods with known root type.
5224///
5225/// `PartialKeyPath` is similar to Swift's `PartialKeyPath<Root>`. It hides
5226/// the `Value` type but keeps the `Root` type visible. This is useful for
5227/// storing collections of keypaths with the same root type but different value types.
5228///
5229/// # Generated Methods
5230///
5231/// For each field `field_name`, generates:
5232///
5233/// - `field_name_r()` - Returns a `PartialKeyPath<Struct>` for readable access
5234/// - `field_name_w()` - Returns a `PartialWritableKeyPath<Struct>` for writable access
5235/// - `field_name_fr()` - Returns a `PartialOptionalKeyPath<Struct>` for optional fields
5236/// - `field_name_fw()` - Returns a `PartialWritableOptionalKeyPath<Struct>` for optional writable fields
5237///
5238/// # Type Erasure
5239///
5240/// The `get()` method returns `&dyn Any`, requiring downcasting to access the actual value.
5241/// Use `get_as::<Root, Value>()` for type-safe access when you know the value type.
5242///
5243/// # Examples
5244///
5245/// ```rust,ignore
5246/// use keypaths_proc::PartialKeypaths;
5247/// use rust_keypaths::PartialKeyPath;
5248///
5249/// #[derive(PartialKeypaths)]
5250/// struct User {
5251/// name: String,
5252/// age: u32,
5253/// email: Option<String>,
5254/// }
5255///
5256/// // Usage:
5257/// let mut paths: Vec<PartialKeyPath<User>> = vec![
5258/// User::name_r(),
5259/// User::age_r(),
5260/// ];
5261///
5262/// let user = User {
5263/// name: "Alice".to_string(),
5264/// age: 30,
5265/// email: Some("alice@example.com".to_string()),
5266/// };
5267///
5268/// // Access values (requires type information)
5269/// if let Some(name) = paths[0].get_as::<User, String>(&user) {
5270/// println!("Name: {}", name);
5271/// }
5272/// ```
5273#[proc_macro_derive(PartialKeypaths)]
5274pub fn derive_partial_keypaths(input: TokenStream) -> TokenStream {
5275 let input = parse_macro_input!(input as DeriveInput);
5276 let name = input.ident;
5277
5278 let methods = match input.data {
5279 Data::Struct(data_struct) => match data_struct.fields {
5280 Fields::Named(fields_named) => {
5281 let mut tokens = proc_macro2::TokenStream::new();
5282 for field in fields_named.named.iter() {
5283 let field_ident = field.ident.as_ref().unwrap();
5284 let ty = &field.ty;
5285
5286 let r_fn = format_ident!("{}_partial_r", field_ident);
5287 let w_fn = format_ident!("{}_partial_w", field_ident);
5288 let fr_fn = format_ident!("{}_partial_fr", field_ident);
5289 let fw_fn = format_ident!("{}_partial_fw", field_ident);
5290 let fr_at_fn = format_ident!("{}_partial_fr_at", field_ident);
5291 let fw_at_fn = format_ident!("{}_partial_fw_at", field_ident);
5292 // Owned keypath method names
5293 let o_fn = format_ident!("{}_partial_o", field_ident);
5294 let fo_fn = format_ident!("{}_partial_fo", field_ident);
5295
5296 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
5297
5298 match (kind, inner_ty.clone()) {
5299 (WrapperKind::Option, Some(inner_ty)) => {
5300 tokens.extend(quote! {
5301 pub fn #r_fn() -> rust_keypaths::PartialOptionalKeyPath<#name> {
5302 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref()).to_partial()
5303 }
5304 pub fn #w_fn() -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5305 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut()).to_partial()
5306 }
5307 pub fn #fr_fn() -> rust_keypaths::PartialOptionalKeyPath<#name> {
5308 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref()).to_partial()
5309 }
5310 pub fn #fw_fn() -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5311 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut()).to_partial()
5312 }
5313 // Owned keypath methods - these don't make sense for Option types
5314 // as we can't return owned values from references
5315 });
5316 }
5317 (WrapperKind::Vec, Some(inner_ty)) => {
5318 tokens.extend(quote! {
5319 pub fn #fr_at_fn(index: usize) -> rust_keypaths::PartialOptionalKeyPath<#name> {
5320 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index)).to_partial()
5321 }
5322 pub fn #fw_at_fn(index: usize) -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5323 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index)).to_partial()
5324 }
5325 pub fn #r_fn() -> rust_keypaths::PartialKeyPath<#name> {
5326 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident).to_partial()
5327 }
5328 pub fn #w_fn() -> rust_keypaths::PartialWritableKeyPath<#name> {
5329 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident).to_partial()
5330 }
5331 pub fn #fr_fn() -> rust_keypaths::PartialOptionalKeyPath<#name> {
5332 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first()).to_partial()
5333 }
5334 pub fn #fw_fn() -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5335 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.first_mut()).to_partial()
5336 }
5337 // Owned keypath methods - not supported for Vec as we need references
5338 });
5339 }
5340 (WrapperKind::HashMap, Some(inner_ty)) => {
5341 tokens.extend(quote! {
5342 pub fn #r_fn() -> rust_keypaths::PartialKeyPath<#name> {
5343 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident).to_partial()
5344 }
5345 pub fn #w_fn() -> rust_keypaths::PartialWritableKeyPath<#name> {
5346 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident).to_partial()
5347 }
5348 pub fn #fr_fn(key: String) -> rust_keypaths::PartialOptionalKeyPath<#name> {
5349 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key)).to_partial()
5350 }
5351 pub fn #fw_fn(key: String) -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5352 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key)).to_partial()
5353 }
5354 pub fn #fr_at_fn(key: String) -> rust_keypaths::PartialOptionalKeyPath<#name> {
5355 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key)).to_partial()
5356 }
5357 pub fn #fw_at_fn(key: String) -> rust_keypaths::PartialWritableOptionalKeyPath<#name> {
5358 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key)).to_partial()
5359 }
5360 // Owned keypath methods - not supported for HashMap as we need references
5361 });
5362 }
5363 _ => {
5364 // Default case for simple types
5365 tokens.extend(quote! {
5366 pub fn #r_fn() -> rust_keypaths::PartialKeyPath<#name> {
5367 rust_keypaths::KeyPath::new(|s: &#name| &s.#field_ident).to_partial()
5368 }
5369 pub fn #w_fn() -> rust_keypaths::PartialWritableKeyPath<#name> {
5370 rust_keypaths::WritableKeyPath::new(|s: &mut #name| &mut s.#field_ident).to_partial()
5371 }
5372 // Owned keypath methods - not supported as we need references
5373 });
5374 }
5375 }
5376 }
5377 tokens
5378 }
5379 _ => quote! { compile_error!("PartialKeypaths can only be derived for structs with named fields"); },
5380 },
5381 _ => quote! { compile_error!("PartialKeypaths can only be derived for structs"); },
5382 };
5383
5384 let expanded = quote! {
5385 impl #name {
5386 #methods
5387 }
5388 };
5389
5390 TokenStream::from(expanded)
5391}
5392
5393/// Derives fully type-erased keypath methods.
5394///
5395/// `AnyKeyPath` is similar to Swift's `AnyKeyPath`. It hides both the `Root`
5396/// and `Value` types, making it useful for storing keypaths from different
5397/// struct types in the same collection.
5398///
5399/// # Generated Methods
5400///
5401/// For each field `field_name`, generates:
5402///
5403/// - `field_name_r()` - Returns an `AnyKeyPath` for readable access
5404/// - `field_name_w()` - Returns an `AnyWritableKeyPath` for writable access
5405/// - `field_name_fr()` - Returns an `AnyKeyPath` for optional fields
5406/// - `field_name_fw()` - Returns an `AnyWritableKeyPath` for optional writable fields
5407///
5408/// # Type Erasure
5409///
5410/// The `get()` method returns `&dyn Any`, requiring downcasting to access the actual value.
5411/// Use `get_as::<Root, Value>()` for type-safe access when you know both root and value types.
5412///
5413/// # Examples
5414///
5415/// ```rust,ignore
5416/// use keypaths_proc::AnyKeypaths;
5417/// use rust_keypaths::AnyKeyPath;
5418///
5419/// #[derive(AnyKeypaths)]
5420/// struct User {
5421/// name: String,
5422/// age: u32,
5423/// }
5424///
5425/// #[derive(AnyKeypaths)]
5426/// struct Product {
5427/// price: f64,
5428/// }
5429///
5430/// // Usage:
5431/// let mut paths: Vec<AnyKeyPath> = vec![
5432/// User::name_r(),
5433/// Product::price_r(),
5434/// ];
5435///
5436/// let user = User {
5437/// name: "Alice".to_string(),
5438/// age: 30,
5439/// };
5440///
5441/// // Access values (requires both root and value type information)
5442/// if let Some(name) = paths[0].get_as::<User, String>(&user) {
5443/// println!("Name: {}", name);
5444/// }
5445/// ```
5446#[proc_macro_derive(AnyKeypaths)]
5447pub fn derive_any_keypaths(input: TokenStream) -> TokenStream {
5448 let input = parse_macro_input!(input as DeriveInput);
5449 let name = input.ident;
5450
5451 let methods = match input.data {
5452 Data::Struct(data_struct) => match data_struct.fields {
5453 Fields::Named(fields_named) => {
5454 let mut tokens = proc_macro2::TokenStream::new();
5455 for field in fields_named.named.iter() {
5456 let field_ident = field.ident.as_ref().unwrap();
5457 let ty = &field.ty;
5458
5459 let r_fn = format_ident!("{}_any_r", field_ident);
5460 let w_fn = format_ident!("{}_any_w", field_ident);
5461 let fr_fn = format_ident!("{}_any_fr", field_ident);
5462 let fw_fn = format_ident!("{}_any_fw", field_ident);
5463 let fr_at_fn = format_ident!("{}_any_fr_at", field_ident);
5464 let fw_at_fn = format_ident!("{}_any_fw_at", field_ident);
5465 // Owned keypath method names
5466 let o_fn = format_ident!("{}_any_o", field_ident);
5467 let fo_fn = format_ident!("{}_any_fo", field_ident);
5468
5469 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
5470
5471 match (kind, inner_ty.clone()) {
5472 (WrapperKind::Option, Some(inner_ty)) => {
5473 tokens.extend(quote! {
5474 pub fn #r_fn() -> rust_keypaths::AnyKeyPath {
5475 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref()).to_any()
5476 }
5477 pub fn #w_fn() -> rust_keypaths::AnyWritableKeyPath {
5478 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut()).to_any()
5479 }
5480 pub fn #fr_fn() -> rust_keypaths::AnyKeyPath {
5481 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.as_ref()).to_any()
5482 }
5483 pub fn #fw_fn() -> rust_keypaths::AnyWritableKeyPath {
5484 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.as_mut()).to_any()
5485 }
5486 // Owned keypath methods - not supported for Option types
5487 });
5488 }
5489 (WrapperKind::Vec, Some(inner_ty)) => {
5490 tokens.extend(quote! {
5491 pub fn #fr_at_fn(index: usize) -> rust_keypaths::AnyKeyPath {
5492 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(index)).to_any()
5493 }
5494 pub fn #fw_at_fn(index: usize) -> rust_keypaths::AnyWritableKeyPath {
5495 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(index)).to_any()
5496 }
5497 pub fn #r_fn() -> rust_keypaths::AnyKeyPath {
5498 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident)).to_any()
5499 }
5500 pub fn #w_fn() -> rust_keypaths::AnyWritableKeyPath {
5501 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#field_ident)).to_any()
5502 }
5503 pub fn #fr_fn() -> rust_keypaths::AnyKeyPath {
5504 rust_keypaths::OptionalKeyPath::new(|s: &#name| s.#field_ident.first()).to_any()
5505 }
5506 pub fn #fw_fn() -> rust_keypaths::AnyWritableKeyPath {
5507 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| s.#field_ident.first_mut()).to_any()
5508 }
5509 // Owned keypath methods - not supported for Vec
5510 });
5511 }
5512 (WrapperKind::HashMap, Some(inner_ty)) => {
5513 tokens.extend(quote! {
5514 pub fn #r_fn() -> rust_keypaths::AnyKeyPath {
5515 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident)).to_any()
5516 }
5517 pub fn #w_fn() -> rust_keypaths::AnyWritableKeyPath {
5518 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#field_ident)).to_any()
5519 }
5520 pub fn #fr_fn(key: String) -> rust_keypaths::AnyKeyPath {
5521 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key)).to_any()
5522 }
5523 pub fn #fw_fn(key: String) -> rust_keypaths::AnyWritableKeyPath {
5524 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key)).to_any()
5525 }
5526 pub fn #fr_at_fn(key: String) -> rust_keypaths::AnyKeyPath {
5527 rust_keypaths::OptionalKeyPath::new(move |s: &#name| s.#field_ident.get(&key)).to_any()
5528 }
5529 pub fn #fw_at_fn(key: String) -> rust_keypaths::AnyWritableKeyPath {
5530 rust_keypaths::WritableOptionalKeyPath::new(move |s: &mut #name| s.#field_ident.get_mut(&key)).to_any()
5531 }
5532 // Owned keypath methods - not supported for HashMap
5533 });
5534 }
5535 _ => {
5536 // Default case for simple types
5537 tokens.extend(quote! {
5538 pub fn #r_fn() -> rust_keypaths::AnyKeyPath {
5539 rust_keypaths::OptionalKeyPath::new(|s: &#name| Some(&s.#field_ident)).to_any()
5540 }
5541 pub fn #w_fn() -> rust_keypaths::AnyWritableKeyPath {
5542 rust_keypaths::WritableOptionalKeyPath::new(|s: &mut #name| Some(&mut s.#field_ident)).to_any()
5543 }
5544 // Owned keypath methods - not supported as we need references
5545 });
5546 }
5547 }
5548 }
5549 tokens
5550 }
5551 _ => quote! { compile_error!("AnyKeypaths can only be derived for structs with named fields"); },
5552 },
5553 _ => quote! { compile_error!("AnyKeypaths can only be derived for structs"); },
5554 };
5555
5556 let expanded = quote! {
5557 impl #name {
5558 #methods
5559 }
5560 };
5561
5562 TokenStream::from(expanded)
5563}
5564
5565// /// A helper macro that provides suggestions when there are type mismatches with container types.
5566// /// This macro helps users understand when to use adapter methods like for_arc(), for_box(), etc.
5567// #[proc_macro]
5568// pub fn keypath_suggestion(input: TokenStream) -> TokenStream {
5569// let input_str = input.to_string();
5570//
5571// // Parse the input to understand what the user is trying to do
5572// let suggestion = if input_str.contains("Arc<") && input_str.contains("KeyPaths<") {
5573// "💡 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();"
5574// } else if input_str.contains("Box<") && input_str.contains("KeyPaths<") {
5575// "💡 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();"
5576// } else if input_str.contains("Rc<") && input_str.contains("KeyPaths<") {
5577// "💡 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();"
5578// } else if input_str.contains("Option<") && input_str.contains("KeyPaths<") {
5579// "💡 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();"
5580// } else if input_str.contains("Result<") && input_str.contains("KeyPaths<") {
5581// "💡 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();"
5582// } else if input_str.contains("Mutex<") && input_str.contains("KeyPaths<") {
5583// "💡 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 */ });"
5584// } else if input_str.contains("RwLock<") && input_str.contains("KeyPaths<") {
5585// "💡 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 */ });"
5586// } else {
5587// "💡 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)"
5588// };
5589//
5590// let expanded = quote! {
5591// compile_error!(#suggestion);
5592// };
5593//
5594// TokenStream::from(expanded)
5595// }
5596
5597// /// A helper macro that provides compile-time suggestions for common KeyPaths usage patterns.
5598// /// This macro can be used to get helpful error messages when there are type mismatches.
5599// #[proc_macro]
5600// pub fn keypath_help(input: TokenStream) -> TokenStream {
5601// let input_str = input.to_string();
5602//
5603// let help_message = if input_str.is_empty() {
5604// "🔧 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()
5605// } else {
5606// format!("🔧 KeyPaths Help for '{}': Use adapter methods to work with different container types. See documentation for more details.", input_str)
5607// };
5608//
5609// let expanded = quote! {
5610// compile_error!(#help_message);
5611// };
5612//
5613// TokenStream::from(expanded)
5614// }