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