key_paths_derive/lib.rs
1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{Data, DeriveInput, Fields, Type, 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 // Reference counting with weak references
23 Weak,
24 // String types (currently unused)
25 // String,
26 // OsString,
27 // PathBuf,
28 // Nested container support
29 OptionBox,
30 OptionRc,
31 OptionArc,
32 BoxOption,
33 RcOption,
34 ArcOption,
35 VecOption,
36 OptionVec,
37 HashMapOption,
38 OptionHashMap,
39 // Arc with synchronization primitives (default)
40 StdArcMutex,
41 StdArcRwLock,
42 OptionStdArcMutex,
43 OptionStdArcRwLock,
44 // Synchronization primitives default
45 StdMutex,
46 StdRwLock,
47 OptionStdMutex,
48 OptionStdRwLock,
49 // Synchronization primitives (parking_lot)
50 Mutex,
51 RwLock,
52 OptionMutex,
53 OptionRwLock,
54 // Synchronization primitives (tokio::sync - requires tokio feature)
55 TokioMutex,
56 TokioRwLock,
57 // parking_lot
58 ArcMutex,
59 ArcRwLock,
60 OptionArcMutex,
61 OptionArcRwLock,
62 // Arc with synchronization primitives (tokio::sync - requires tokio feature)
63 TokioArcMutex,
64 TokioArcRwLock,
65 OptionTokioArcMutex,
66 OptionTokioArcRwLock,
67 // Tagged types
68 Tagged,
69 OptionTagged,
70 // Clone-on-write (std::borrow::Cow)
71 Cow,
72 OptionCow,
73 // Reference types (&T, &str, &[T], etc.)
74 Reference,
75 OptionReference,
76 // Atomic types (std::sync::atomic::*)
77 Atomic,
78 OptionAtomic,
79 // Pin types
80 Pin,
81 PinBox,
82 /// Field marked with #[pin] - plain type (pin_project pattern)
83 PinnedField,
84 /// Field marked with #[pin] - Future type (pin_project pattern)
85 PinnedFuture,
86 /// Field marked with #[pin] - Box<dyn Future> (pin_project pattern)
87 PinnedBoxFuture,
88}
89
90/// Helper function to check if a type path includes std::sync module
91fn is_std_sync_type(path: &syn::Path) -> bool {
92 // Check for paths like std::sync::Mutex, std::sync::RwLock
93 let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
94 segments.len() >= 2
95 && segments.contains(&"std".to_string())
96 && segments.contains(&"sync".to_string())
97}
98
99/// Helper function to check if a type path includes tokio::sync module
100fn is_tokio_sync_type(path: &syn::Path) -> bool {
101 // Check for paths like tokio::sync::Mutex, tokio::sync::RwLock
102 let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
103 segments.len() >= 2
104 && segments.contains(&"tokio".to_string())
105 && segments.contains(&"sync".to_string())
106}
107
108/// Helper function to check if a type path includes std::sync::atomic module
109fn is_std_sync_atomic_type(path: &syn::Path) -> bool {
110 let segments: Vec<_> = path.segments.iter().map(|s| s.ident.to_string()).collect();
111 segments.contains(&"std".to_string())
112 && segments.contains(&"sync".to_string())
113 && segments.contains(&"atomic".to_string())
114}
115
116/// Atomic type idents (no type params): AtomicBool, AtomicI8, etc.
117const ATOMIC_TYPE_IDENTS: &[&str] = &[
118 "AtomicBool", "AtomicI8", "AtomicI16", "AtomicI32", "AtomicI64", "AtomicI128", "AtomicIsize",
119 "AtomicU8", "AtomicU16", "AtomicU32", "AtomicU64", "AtomicU128", "AtomicUsize",
120];
121
122fn extract_wrapper_inner_type(ty: &Type) -> (WrapperKind, Option<Type>) {
123 use syn::{GenericArgument, PathArguments};
124
125 // Handle reference types: &T, &'a str, &[T], etc.
126 if let Type::Reference(tr) = ty {
127 return (WrapperKind::Reference, Some((*tr.elem).clone()));
128 }
129
130 if let Type::Path(tp) = ty {
131 // Check if this is explicitly a std::sync type
132 let is_std_sync = is_std_sync_type(&tp.path);
133 // Check if this is explicitly a tokio::sync type
134 let is_tokio_sync = is_tokio_sync_type(&tp.path);
135
136 if let Some(seg) = tp.path.segments.last() {
137 let ident_str = seg.ident.to_string();
138
139 if let PathArguments::AngleBracketed(ab) = &seg.arguments {
140 let args: Vec<_> = ab.args.iter().collect();
141
142 // Handle map types (HashMap, BTreeMap) - they have K, V parameters
143 if ident_str == "HashMap" || ident_str == "BTreeMap" {
144 if let (Some(_key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
145 if let GenericArgument::Type(inner) = value_arg {
146 // Check for nested Option in map values
147 let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
148 match (ident_str.as_str(), inner_kind) {
149 ("HashMap", WrapperKind::Option) => {
150 return (WrapperKind::HashMapOption, inner_inner);
151 }
152 _ => {
153 return match ident_str.as_str() {
154 "HashMap" => (WrapperKind::HashMap, Some(inner.clone())),
155 "BTreeMap" => (WrapperKind::BTreeMap, Some(inner.clone())),
156 _ => (WrapperKind::None, None),
157 };
158 }
159 }
160 }
161 }
162 }
163 // Handle Cow<'a, B> - has lifetime then type parameter
164 else if ident_str == "Cow" {
165 if let Some(inner) = args.iter().find_map(|arg| {
166 if let GenericArgument::Type(t) = arg {
167 Some(t.clone())
168 } else {
169 None
170 }
171 }) {
172 return (WrapperKind::Cow, Some(inner));
173 }
174 }
175 // Handle single-parameter container types
176 else if let Some(arg) = args.get(0) {
177 if let GenericArgument::Type(inner) = arg {
178 // Check for nested containers first
179 let (inner_kind, inner_inner) = extract_wrapper_inner_type(inner);
180
181 // Handle nested combinations
182 match (ident_str.as_str(), inner_kind) {
183 ("Option", WrapperKind::Box) => {
184 return (WrapperKind::OptionBox, inner_inner);
185 }
186 ("Option", WrapperKind::Rc) => {
187 return (WrapperKind::OptionRc, inner_inner);
188 }
189 ("Option", WrapperKind::Arc) => {
190 return (WrapperKind::OptionArc, inner_inner);
191 }
192 ("Option", WrapperKind::Vec) => {
193 return (WrapperKind::OptionVec, inner_inner);
194 }
195 ("Option", WrapperKind::HashMap) => {
196 return (WrapperKind::OptionHashMap, inner_inner);
197 }
198 ("Option", WrapperKind::StdArcMutex) => {
199 return (WrapperKind::OptionStdArcMutex, inner_inner);
200 }
201 ("Option", WrapperKind::StdArcRwLock) => {
202 return (WrapperKind::OptionStdArcRwLock, inner_inner);
203 }
204 ("Option", WrapperKind::ArcMutex) => {
205 return (WrapperKind::OptionArcMutex, inner_inner);
206 }
207 ("Option", WrapperKind::ArcRwLock) => {
208 return (WrapperKind::OptionArcRwLock, inner_inner);
209 }
210 ("Option", WrapperKind::StdMutex) => {
211 return (WrapperKind::OptionStdMutex, inner_inner);
212 }
213 ("Option", WrapperKind::StdRwLock) => {
214 return (WrapperKind::OptionStdRwLock, inner_inner);
215 }
216 ("Option", WrapperKind::Mutex) => {
217 return (WrapperKind::OptionMutex, inner_inner);
218 }
219 ("Option", WrapperKind::RwLock) => {
220 return (WrapperKind::OptionRwLock, inner_inner);
221 }
222 ("Option", WrapperKind::TokioArcMutex) => {
223 return (WrapperKind::OptionTokioArcMutex, inner_inner);
224 }
225 ("Option", WrapperKind::TokioArcRwLock) => {
226 return (WrapperKind::OptionTokioArcRwLock, inner_inner);
227 }
228 ("Option", WrapperKind::Cow) => {
229 return (WrapperKind::OptionCow, inner_inner);
230 }
231 ("Option", WrapperKind::Tagged) => {
232 return (WrapperKind::OptionTagged, inner_inner);
233 }
234 ("Option", WrapperKind::Reference) => {
235 return (WrapperKind::OptionReference, Some(inner.clone()));
236 }
237 ("Option", WrapperKind::Atomic) => {
238 return (WrapperKind::OptionAtomic, Some(inner.clone()));
239 }
240 ("Pin", WrapperKind::Box) => {
241 return (WrapperKind::PinBox, inner_inner);
242 }
243 ("Box", WrapperKind::Option) => {
244 return (WrapperKind::BoxOption, inner_inner);
245 }
246 ("Rc", WrapperKind::Option) => {
247 return (WrapperKind::RcOption, inner_inner);
248 }
249 ("Arc", WrapperKind::Option) => {
250 return (WrapperKind::ArcOption, inner_inner);
251 }
252 ("Vec", WrapperKind::Option) => {
253 return (WrapperKind::VecOption, inner_inner);
254 }
255 ("HashMap", WrapperKind::Option) => {
256 return (WrapperKind::HashMapOption, inner_inner);
257 }
258 // std::sync variants (when inner is StdMutex/StdRwLock)
259 ("Arc", WrapperKind::StdMutex) => {
260 return (WrapperKind::StdArcMutex, inner_inner);
261 }
262 ("Arc", WrapperKind::StdRwLock) => {
263 return (WrapperKind::StdArcRwLock, inner_inner);
264 }
265 // parking_lot variants (default - when inner is Mutex/RwLock without std::sync prefix)
266 ("Arc", WrapperKind::Mutex) => {
267 return (WrapperKind::ArcMutex, inner_inner);
268 }
269 ("Arc", WrapperKind::RwLock) => {
270 return (WrapperKind::ArcRwLock, inner_inner);
271 }
272 // tokio::sync variants (when inner is TokioMutex/TokioRwLock)
273 ("Arc", WrapperKind::TokioMutex) => {
274 return (WrapperKind::TokioArcMutex, inner_inner);
275 }
276 ("Arc", WrapperKind::TokioRwLock) => {
277 return (WrapperKind::TokioArcRwLock, inner_inner);
278 }
279 _ => {
280 // Handle single-level containers
281 // For Mutex and RwLock:
282 // - If path contains std::sync, it's std::sync (StdMutex/StdRwLock)
283 // - Otherwise, default to parking_lot (Mutex/RwLock)
284 return match ident_str.as_str() {
285 "Option" => (WrapperKind::Option, Some(inner.clone())),
286 "Box" => (WrapperKind::Box, Some(inner.clone())),
287 "Rc" => (WrapperKind::Rc, Some(inner.clone())),
288 "Arc" => (WrapperKind::Arc, Some(inner.clone())),
289 "Vec" => (WrapperKind::Vec, Some(inner.clone())),
290 "HashSet" => (WrapperKind::HashSet, Some(inner.clone())),
291 "BTreeSet" => (WrapperKind::BTreeSet, Some(inner.clone())),
292 "VecDeque" => (WrapperKind::VecDeque, Some(inner.clone())),
293 "LinkedList" => (WrapperKind::LinkedList, Some(inner.clone())),
294 "BinaryHeap" => (WrapperKind::BinaryHeap, Some(inner.clone())),
295 "Result" => (WrapperKind::Result, Some(inner.clone())),
296 // For std::sync::Mutex and std::sync::RwLock, use Std variants
297 "Mutex" if is_std_sync => {
298 (WrapperKind::StdMutex, Some(inner.clone()))
299 }
300 "RwLock" if is_std_sync => {
301 (WrapperKind::StdRwLock, Some(inner.clone()))
302 }
303 // For tokio::sync::Mutex and tokio::sync::RwLock, use Tokio variants
304 "Mutex" if is_tokio_sync => {
305 (WrapperKind::TokioMutex, Some(inner.clone()))
306 }
307 "RwLock" if is_tokio_sync => {
308 (WrapperKind::TokioRwLock, Some(inner.clone()))
309 }
310 // Default: parking_lot (no std::sync or tokio::sync prefix)
311 "Mutex" => (WrapperKind::Mutex, Some(inner.clone())),
312 "RwLock" => (WrapperKind::RwLock, Some(inner.clone())),
313 "Weak" => (WrapperKind::Weak, Some(inner.clone())),
314 "Tagged" => (WrapperKind::Tagged, Some(inner.clone())),
315 "Cow" => (WrapperKind::Cow, Some(inner.clone())),
316 "AtomicPtr" if is_std_sync_atomic_type(&tp.path) => (WrapperKind::Atomic, None),
317 "Pin" => (WrapperKind::Pin, Some(inner.clone())),
318 _ => (WrapperKind::None, None),
319 };
320 }
321 }
322 }
323 }
324 }
325 // Handle atomic types with no angle bracket args (AtomicBool, AtomicI32, etc.)
326 if matches!(seg.arguments, PathArguments::None)
327 && is_std_sync_atomic_type(&tp.path)
328 && ATOMIC_TYPE_IDENTS.contains(&ident_str.as_str())
329 {
330 return (WrapperKind::Atomic, None);
331 }
332 }
333 }
334 (WrapperKind::None, None)
335}
336
337/// Check if a field has the #[pin] attribute (pin_project pattern).
338fn field_has_pin_attr(field: &syn::Field) -> bool {
339 field.attrs.iter().any(|attr| {
340 attr.path().get_ident().map(|i| i == "pin").unwrap_or(false)
341 })
342}
343
344/// Check if a type is a Future (dyn Future, impl Future, or Box<dyn Future>).
345fn is_future_type(ty: &Type) -> bool {
346 use syn::{GenericArgument, PathArguments, TypeParamBound};
347
348 match ty {
349 Type::TraitObject(trait_obj) => trait_obj.bounds.iter().any(|b| {
350 if let TypeParamBound::Trait(t) = b {
351 t.path.segments.last()
352 .map(|s| s.ident == "Future")
353 .unwrap_or(false)
354 } else {
355 false
356 }
357 }),
358 Type::ImplTrait(impl_trait) => impl_trait.bounds.iter().any(|b| {
359 if let TypeParamBound::Trait(t) = b {
360 t.path.segments.last()
361 .map(|s| s.ident == "Future")
362 .unwrap_or(false)
363 } else {
364 false
365 }
366 }),
367 Type::Path(tp) => {
368 if let Some(seg) = tp.path.segments.last() {
369 match seg.ident.to_string().as_str() {
370 "Box" | "Pin" => {
371 if let PathArguments::AngleBracketed(args) = &seg.arguments {
372 if let Some(GenericArgument::Type(inner)) = args.args.first() {
373 return is_future_type(inner);
374 }
375 }
376 }
377 _ => {}
378 }
379 }
380 false
381 }
382 _ => false,
383 }
384}
385
386/// Extract Output type from Future trait bound (dyn Future<Output = T>, impl Future<Output = T>, etc.).
387fn extract_future_output(ty: &Type) -> Option<Type> {
388 use syn::{GenericArgument, PathArguments, TypeParamBound};
389
390 let bounds = match ty {
391 Type::TraitObject(t) => &t.bounds,
392 Type::ImplTrait(t) => &t.bounds,
393 Type::Path(tp) => {
394 if let Some(seg) = tp.path.segments.last() {
395 if matches!(seg.ident.to_string().as_str(), "Box" | "Pin") {
396 if let PathArguments::AngleBracketed(args) = &seg.arguments {
397 if let Some(GenericArgument::Type(inner)) = args.args.first() {
398 return extract_future_output(inner);
399 }
400 }
401 }
402 }
403 return None;
404 }
405 _ => return None,
406 };
407
408 for bound in bounds {
409 if let TypeParamBound::Trait(trait_bound) = bound {
410 if let Some(seg) = trait_bound.path.segments.last() {
411 if seg.ident == "Future" {
412 if let PathArguments::AngleBracketed(args) = &seg.arguments {
413 for arg in &args.args {
414 if let GenericArgument::AssocType(assoc) = arg {
415 if assoc.ident == "Output" {
416 return Some(assoc.ty.clone());
417 }
418 }
419 }
420 }
421 }
422 }
423 }
424 }
425 None
426}
427
428/// For HashMap<K,V> or BTreeMap<K,V>, returns Some((key_ty, value_ty)).
429fn extract_map_key_value(ty: &Type) -> Option<(Type, Type)> {
430 use syn::{GenericArgument, PathArguments};
431
432 if let Type::Path(tp) = ty {
433 if let Some(seg) = tp.path.segments.last() {
434 let ident_str = seg.ident.to_string();
435 if ident_str == "HashMap" || ident_str == "BTreeMap" {
436 if let PathArguments::AngleBracketed(ab) = &seg.arguments {
437 let args: Vec<_> = ab.args.iter().collect();
438 if let (Some(key_arg), Some(value_arg)) = (args.get(0), args.get(1)) {
439 if let (GenericArgument::Type(key_ty), GenericArgument::Type(value_ty)) =
440 (key_arg, value_arg)
441 {
442 return Some((key_ty.clone(), value_ty.clone()));
443 }
444 }
445 }
446 }
447 }
448 }
449 None
450}
451
452fn to_snake_case(name: &str) -> String {
453 let mut out = String::new();
454 for (i, c) in name.chars().enumerate() {
455 if c.is_uppercase() {
456 if i != 0 {
457 out.push('_');
458 }
459 out.push(c.to_ascii_lowercase());
460 } else {
461 out.push(c);
462 }
463 }
464 out
465}
466
467/// Derive macro for generating simple keypath methods.
468///
469/// Generates one method per field: `StructName::field_name()` that returns a `Kp`.
470/// Intelligently handles wrapper types (Option, Vec, Box, Arc, etc.) to generate appropriate keypaths.
471///
472/// # Example
473///
474/// ```ignore
475/// #[derive(Kp)]
476/// struct Person {
477/// name: String,
478/// age: i32,
479/// email: Option<String>,
480/// addresses: Vec<String>,
481/// }
482///
483/// // Generates:
484/// // impl Person {
485/// // pub fn name() -> Kp<...> { ... }
486/// // pub fn age() -> Kp<...> { ... }
487/// // pub fn email() -> Kp<...> { ... } // unwraps Option
488/// // pub fn addresses() -> Kp<...> { ... } // accesses first element
489/// // }
490/// ```
491#[proc_macro_derive(Kp)]
492pub fn derive_keypaths(input: TokenStream) -> TokenStream {
493 let input = parse_macro_input!(input as DeriveInput);
494 let name = &input.ident;
495 let input_span = input.span();
496
497 let methods = match input.data {
498 Data::Struct(data_struct) => match data_struct.fields {
499 Fields::Named(fields_named) => {
500 let mut tokens = proc_macro2::TokenStream::new();
501
502 // Generate identity methods for the struct
503 tokens.extend(quote! {
504 /// Returns a generic identity keypath for this type
505 #[inline(always)]
506 pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
507 #name,
508 #name,
509 Root,
510 Root,
511 MutRoot,
512 MutRoot,
513 fn(Root) -> Option<Root>,
514 fn(MutRoot) -> Option<MutRoot>,
515 >
516 where
517 Root: std::borrow::Borrow<#name>,
518 MutRoot: std::borrow::BorrowMut<#name>,
519 {
520 rust_key_paths::Kp::new(
521 |r: Root| Some(r),
522 |r: MutRoot| Some(r)
523 )
524 }
525
526 /// Returns a simple identity keypath for this type
527 #[inline(always)]
528 pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
529 rust_key_paths::Kp::new(
530 |r: &#name| Some(r),
531 |r: &mut #name| Some(r)
532 )
533 }
534 });
535
536 // When struct has #[pin] fields, generated code calls this.project() which must
537 // be provided by #[pin_project]. If missing, user gets: no method named `project`.
538
539 for field in fields_named.named.iter() {
540 let field_ident = field.ident.as_ref().unwrap();
541 let ty = &field.ty;
542 // Centralized keypath method names – change here to adjust for all types
543 let kp_fn = format_ident!("{}", field_ident);
544 let kp_at_fn = format_ident!("{}_at", field_ident);
545
546 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
547
548 // Override kind when field has #[pin] (pin_project pattern)
549 let (kind, inner_ty) = if field_has_pin_attr(field) {
550 let pinned_kind = if let Some(output_ty) = extract_future_output(ty) {
551 if matches!(kind, WrapperKind::Box) {
552 (WrapperKind::PinnedBoxFuture, Some(output_ty))
553 } else {
554 (WrapperKind::PinnedFuture, Some(output_ty))
555 }
556 } else if is_future_type(ty) {
557 (WrapperKind::PinnedFuture, inner_ty.clone())
558 } else {
559 (WrapperKind::PinnedField, inner_ty.clone())
560 };
561 pinned_kind
562 } else {
563 (kind, inner_ty.clone())
564 };
565
566 match (kind, inner_ty) {
567 (WrapperKind::Option, Some(inner_ty)) => {
568 // For Option<T>, unwrap and access inner type
569 tokens.extend(quote! {
570 #[inline(always)]
571 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
572 rust_key_paths::Kp::new(
573 |root: &#name| root.#field_ident.as_ref(),
574 |root: &mut #name| root.#field_ident.as_mut(),
575 )
576 }
577 });
578 }
579 (WrapperKind::Vec, Some(inner_ty)) => {
580 tokens.extend(quote! {
581 #[inline(always)]
582 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
583 rust_key_paths::Kp::new(
584 |root: &#name| Some(&root.#field_ident),
585 |root: &mut #name| Some(&mut root.#field_ident),
586 )
587 }
588 #[inline(always)]
589 pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
590 rust_key_paths::Kp::new(
591 Box::new(move |root: &#name| root.#field_ident.get(index)),
592 Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
593 )
594 }
595 });
596 }
597 (WrapperKind::HashMap, Some(inner_ty)) => {
598 if let Some((key_ty, _)) = extract_map_key_value(ty) {
599 tokens.extend(quote! {
600 #[inline(always)]
601 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
602 rust_key_paths::Kp::new(
603 |root: &#name| Some(&root.#field_ident),
604 |root: &mut #name| Some(&mut root.#field_ident),
605 )
606 }
607 #[inline(always)]
608 pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
609 where
610 #key_ty: Clone + std::hash::Hash + Eq + 'static,
611 {
612 let key2 = key.clone();
613 rust_key_paths::Kp::new(
614 Box::new(move |root: &#name| root.#field_ident.get(&key)),
615 Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
616 )
617 }
618 });
619 } else {
620 tokens.extend(quote! {
621 #[inline(always)]
622 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
623 rust_key_paths::Kp::new(
624 |root: &#name| Some(&root.#field_ident),
625 |root: &mut #name| Some(&mut root.#field_ident),
626 )
627 }
628 });
629 }
630 }
631 (WrapperKind::BTreeMap, Some(inner_ty)) => {
632 if let Some((key_ty, _)) = extract_map_key_value(ty) {
633 tokens.extend(quote! {
634 #[inline(always)]
635 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
636 rust_key_paths::Kp::new(
637 |root: &#name| Some(&root.#field_ident),
638 |root: &mut #name| Some(&mut root.#field_ident),
639 )
640 }
641 #[inline(always)]
642 pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
643 where
644 #key_ty: Clone + Ord + 'static,
645 {
646 let key2 = key.clone();
647 rust_key_paths::Kp::new(
648 Box::new(move |root: &#name| root.#field_ident.get(&key)),
649 Box::new(move |root: &mut #name| root.#field_ident.get_mut(&key2)),
650 )
651 }
652 });
653 } else {
654 tokens.extend(quote! {
655 #[inline(always)]
656 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
657 rust_key_paths::Kp::new(
658 |root: &#name| Some(&root.#field_ident),
659 |root: &mut #name| Some(&mut root.#field_ident),
660 )
661 }
662 });
663 }
664 }
665 (WrapperKind::Box, Some(inner_ty)) => {
666 // For Box<T>, deref to inner type (returns &T / &mut T, not &Box<T>)
667 tokens.extend(quote! {
668 #[inline(always)]
669 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
670 rust_key_paths::Kp::new(
671 |root: &#name| Some(&*root.#field_ident),
672 |root: &mut #name| Some(&mut *root.#field_ident),
673 )
674 }
675 });
676 }
677 (WrapperKind::Pin, Some(inner_ty)) => {
678 let kp_inner_fn = format_ident!("{}_inner", field_ident);
679 tokens.extend(quote! {
680 #[inline(always)]
681 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
682 rust_key_paths::Kp::new(
683 |root: &#name| Some(&root.#field_ident),
684 |root: &mut #name| Some(&mut root.#field_ident),
685 )
686 }
687 #[inline(always)]
688 pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
689 where #inner_ty: std::marker::Unpin
690 {
691 rust_key_paths::Kp::new(
692 |root: &#name| Some(std::pin::Pin::as_ref(&root.#field_ident).get_ref()),
693 |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#field_ident).get_mut()),
694 )
695 }
696 });
697 }
698 (WrapperKind::PinBox, Some(inner_ty)) => {
699 let kp_inner_fn = format_ident!("{}_inner", field_ident);
700 tokens.extend(quote! {
701 #[inline(always)]
702 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
703 rust_key_paths::Kp::new(
704 |root: &#name| Some(&root.#field_ident),
705 |root: &mut #name| Some(&mut root.#field_ident),
706 )
707 }
708 #[inline(always)]
709 pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
710 where #inner_ty: std::marker::Unpin
711 {
712 // Pin::as_ref on Pin<Box<T>> returns Pin<&T> (Box Deref target), so get_ref() already gives &T
713 rust_key_paths::Kp::new(
714 |root: &#name| Some(std::pin::Pin::as_ref(&root.#field_ident).get_ref()),
715 |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#field_ident).get_mut()),
716 )
717 }
718 });
719 }
720 (WrapperKind::PinnedField, _) => {
721 let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
722 tokens.extend(quote! {
723 #[inline(always)]
724 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
725 rust_key_paths::Kp::new(
726 |root: &#name| Some(&root.#field_ident),
727 |root: &mut #name| Some(&mut root.#field_ident),
728 )
729 }
730 /// Pinned projection for #[pin] field. Requires #[pin_project] on struct.
731 #[inline(always)]
732 pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
733 this.project().#field_ident
734 }
735 });
736 }
737 (WrapperKind::PinnedFuture, _) => {
738 let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
739 let kp_await_fn = format_ident!("{}_await", field_ident);
740 let kp_pin_future_fn = format_ident!("{}_pin_future_kp", field_ident);
741 let output_ty = quote! { <#ty as std::future::Future>::Output };
742 tokens.extend(quote! {
743 #[inline(always)]
744 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
745 rust_key_paths::Kp::new(
746 |root: &#name| Some(&root.#field_ident),
747 |root: &mut #name| Some(&mut root.#field_ident),
748 )
749 }
750 /// Pinned projection for #[pin] Future field. Requires #[pin_project] on struct.
751 #[inline(always)]
752 pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
753 this.project().#field_ident
754 }
755 /// Poll the pinned future. Requires #[pin_project] on struct.
756 pub async fn #kp_await_fn(this: std::pin::Pin<&mut #name>) -> Option<#output_ty>
757 where #ty: std::future::Future
758 {
759 use std::future::Future;
760 Some(this.project().#field_ident.await)
761 }
762 /// Keypath for [rust_key_paths::Kp::then_pin_future]. Composable pin future await.
763 #[inline(always)]
764 pub fn #kp_pin_future_fn() -> impl rust_key_paths::pin::PinFutureAwaitLike<#name, #output_ty> {
765 rust_key_paths::pin_future_await_kp!(#name, #kp_await_fn -> #output_ty)
766 }
767 });
768 }
769 (WrapperKind::PinnedBoxFuture, Some(output_ty)) => {
770 let kp_pinned_fn = format_ident!("{}_pinned", field_ident);
771 let kp_await_fn = format_ident!("{}_await", field_ident);
772 let kp_pin_future_fn = format_ident!("{}_pin_future_kp", field_ident);
773 tokens.extend(quote! {
774 #[inline(always)]
775 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
776 rust_key_paths::Kp::new(
777 |root: &#name| Some(&root.#field_ident),
778 |root: &mut #name| Some(&mut root.#field_ident),
779 )
780 }
781 /// Pinned projection for #[pin] Box<dyn Future> field. Requires #[pin_project] on struct.
782 #[inline(always)]
783 pub fn #kp_pinned_fn(this: std::pin::Pin<&mut #name>) -> std::pin::Pin<&mut #ty> {
784 this.project().#field_ident
785 }
786 /// Poll the pinned boxed future. Requires #[pin_project] on struct.
787 pub async fn #kp_await_fn(this: std::pin::Pin<&mut #name>) -> Option<#output_ty> {
788 Some(this.project().#field_ident.await)
789 }
790 /// Keypath for [rust_key_paths::Kp::then_pin_future]. Composable pin future await.
791 #[inline(always)]
792 pub fn #kp_pin_future_fn() -> impl rust_key_paths::pin::PinFutureAwaitLike<#name, #output_ty> {
793 rust_key_paths::pin_future_await_kp!(#name, #kp_await_fn -> #output_ty)
794 }
795 });
796 }
797 (WrapperKind::Rc, Some(inner_ty)) => {
798 // For Rc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
799 tokens.extend(quote! {
800 #[inline(always)]
801 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
802 rust_key_paths::Kp::new(
803 |root: &#name| Some(root.#field_ident.as_ref()),
804 |root: &mut #name| std::rc::Rc::get_mut(&mut root.#field_ident),
805 )
806 }
807 });
808 }
809 (WrapperKind::Arc, Some(inner_ty)) => {
810 // For Arc<T>, deref to inner type (returns &T; get_mut when uniquely owned)
811 tokens.extend(quote! {
812 #[inline(always)]
813 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
814 rust_key_paths::Kp::new(
815 |root: &#name| Some(root.#field_ident.as_ref()),
816 |root: &mut #name| std::sync::Arc::get_mut(&mut root.#field_ident),
817 )
818 }
819 });
820 }
821 (WrapperKind::Cow, Some(inner_ty)) => {
822 // For Cow<'_, B>, deref to inner type (as_ref/to_mut)
823 tokens.extend(quote! {
824 #[inline(always)]
825 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
826 rust_key_paths::Kp::new(
827 |root: &#name| Some(root.#field_ident.as_ref()),
828 |root: &mut #name| Some(root.#field_ident.to_mut()),
829 )
830 }
831 });
832 }
833
834 (WrapperKind::OptionCow, Some(inner_ty)) => {
835 // For Option<Cow<'_, B>>
836 tokens.extend(quote! {
837 #[inline(always)]
838 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
839 rust_key_paths::Kp::new(
840 |root: &#name| root.#field_ident.as_ref().map(|c| c.as_ref()),
841 |root: &mut #name| root.#field_ident.as_mut().map(|c| c.to_mut()),
842 )
843 }
844 });
845 }
846 (WrapperKind::OptionTagged, Some(inner_ty)) => {
847 // For Option<Tagged<Tag, T>> - Tagged implements Deref/DerefMut
848 tokens.extend(quote! {
849 #[inline(always)]
850 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
851 rust_key_paths::Kp::new(
852 |root: &#name| root.#field_ident.as_ref().map(|t| std::ops::Deref::deref(t)),
853 |root: &mut #name| root.#field_ident.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
854 )
855 }
856 });
857 }
858 (WrapperKind::OptionReference, Some(inner_ty)) => {
859 // For Option<&T>, Option<&str>, Option<&[T]> - read-only, setter returns None
860 tokens.extend(quote! {
861 #[inline(always)]
862 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
863 rust_key_paths::Kp::new(
864 |root: &#name| root.#field_ident.as_ref(),
865 |_root: &mut #name| None,
866 )
867 }
868 });
869 }
870 (WrapperKind::HashSet, Some(inner_ty)) => {
871 let kp_at_fn = format_ident!("{}_at", field_ident);
872
873 tokens.extend(quote! {
874 #[inline(always)]
875 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
876 rust_key_paths::Kp::new(
877 |root: &#name| Some(&root.#field_ident),
878 |root: &mut #name| Some(&mut root.#field_ident),
879 )
880 }
881
882 /// _at: check if element exists and get reference.
883 /// HashSet does not allow mutable element access (would break hash invariant).
884 #[inline(always)]
885 pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
886 where
887 #inner_ty: Clone + std::hash::Hash + Eq + 'static,
888 {
889 rust_key_paths::Kp::new(
890 Box::new(move |root: &#name| root.#field_ident.get(&key)),
891 Box::new(move |_root: &mut #name| None),
892 )
893 }
894 });
895 }
896 (WrapperKind::BTreeSet, Some(inner_ty)) => {
897 let kp_at_fn = format_ident!("{}_at", field_ident);
898
899 tokens.extend(quote! {
900 #[inline(always)]
901 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
902 rust_key_paths::Kp::new(
903 |root: &#name| Some(&root.#field_ident),
904 |root: &mut #name| Some(&mut root.#field_ident),
905 )
906 }
907
908 /// _at: check if element exists and get reference.
909 /// BTreeSet does not allow mutable element access (would break ordering invariant).
910 #[inline(always)]
911 pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
912 where
913 #inner_ty: Clone + Ord + 'static,
914 {
915 rust_key_paths::Kp::new(
916 Box::new(move |root: &#name| root.#field_ident.get(&key)),
917 Box::new(move |_root: &mut #name| None),
918 )
919 }
920 });
921 }
922 (WrapperKind::VecDeque, Some(inner_ty)) => {
923 tokens.extend(quote! {
924 #[inline(always)]
925 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
926 rust_key_paths::Kp::new(
927 |root: &#name| Some(&root.#field_ident),
928 |root: &mut #name| Some(&mut root.#field_ident),
929 )
930 }
931 #[inline(always)]
932 pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
933 rust_key_paths::Kp::new(
934 Box::new(move |root: &#name| root.#field_ident.get(index)),
935 Box::new(move |root: &mut #name| root.#field_ident.get_mut(index)),
936 )
937 }
938 });
939 }
940 (WrapperKind::LinkedList, Some(_inner_ty)) => {
941 tokens.extend(quote! {
942 #[inline(always)]
943 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
944 rust_key_paths::Kp::new(
945 |root: &#name| Some(&root.#field_ident),
946 |root: &mut #name| Some(&mut root.#field_ident),
947 )
948 }
949 });
950 }
951 (WrapperKind::BinaryHeap, Some(_inner_ty)) => {
952 tokens.extend(quote! {
953 #[inline(always)]
954 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
955 rust_key_paths::Kp::new(
956 |root: &#name| Some(&root.#field_ident),
957 |root: &mut #name| Some(&mut root.#field_ident),
958 )
959 }
960 });
961 }
962 (WrapperKind::Result, Some(inner_ty)) => {
963 // For Result<T, E>, access Ok value
964 tokens.extend(quote! {
965 #[inline(always)]
966 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
967 rust_key_paths::Kp::new(
968 |root: &#name| root.#field_ident.as_ref().ok(),
969 |root: &mut #name| root.#field_ident.as_mut().ok(),
970 )
971 }
972 });
973 }
974 (WrapperKind::StdArcMutex, Some(inner_ty)) => {
975 // For Arc<std::sync::Mutex<T>>
976 let kp_lock_fn = format_ident!("{}_lock", field_ident);
977 tokens.extend(quote! {
978 #[inline(always)]
979 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
980 rust_key_paths::Kp::new(
981 |root: &#name| Some(&root.#field_ident),
982 |root: &mut #name| Some(&mut root.#field_ident),
983 )
984 }
985 pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #ty, #inner_ty> {
986 rust_key_paths::lock::LockKp::new(
987 rust_key_paths::Kp::new(
988 |root: &#name| Some(&root.#field_ident),
989 |root: &mut #name| Some(&mut root.#field_ident),
990 ),
991 rust_key_paths::lock::ArcMutexAccess::new(),
992 rust_key_paths::Kp::new(
993 |v: &#inner_ty| Some(v),
994 |v: &mut #inner_ty| Some(v),
995 ),
996 )
997 }
998 });
999 }
1000 (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
1001 // For Arc<std::sync::RwLock<T>>
1002 let kp_lock_fn = format_ident!("{}_lock", field_ident);
1003 tokens.extend(quote! {
1004 #[inline(always)]
1005 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1006 rust_key_paths::Kp::new(
1007 |root: &#name| Some(&root.#field_ident),
1008 |root: &mut #name| Some(&mut root.#field_ident),
1009 )
1010 }
1011 pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #ty, #inner_ty> {
1012 rust_key_paths::lock::LockKp::new(
1013 rust_key_paths::Kp::new(
1014 |root: &#name| Some(&root.#field_ident),
1015 |root: &mut #name| Some(&mut root.#field_ident),
1016 ),
1017 rust_key_paths::lock::ArcRwLockAccess::new(),
1018 rust_key_paths::Kp::new(
1019 |v: &#inner_ty| Some(v),
1020 |v: &mut #inner_ty| Some(v),
1021 ),
1022 )
1023 }
1024 });
1025 }
1026 (WrapperKind::ArcRwLock, Some(inner_ty)) => {
1027 // For Arc<parking_lot::RwLock<T>> (requires rust-key-paths "parking_lot" feature)
1028 let kp_lock_fn = format_ident!("{}_lock", field_ident);
1029 tokens.extend(quote! {
1030 #[inline(always)]
1031 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1032 rust_key_paths::Kp::new(
1033 |root: &#name| Some(&root.#field_ident),
1034 |root: &mut #name| Some(&mut root.#field_ident),
1035 )
1036 }
1037 pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #ty, #inner_ty> {
1038 rust_key_paths::lock::LockKp::new(
1039 rust_key_paths::Kp::new(
1040 |root: &#name| Some(&root.#field_ident),
1041 |root: &mut #name| Some(&mut root.#field_ident),
1042 ),
1043 rust_key_paths::lock::ParkingLotRwLockAccess::new(),
1044 rust_key_paths::Kp::new(
1045 |v: &#inner_ty| Some(v),
1046 |v: &mut #inner_ty| Some(v),
1047 ),
1048 )
1049 }
1050 });
1051 }
1052 (WrapperKind::ArcMutex, Some(inner_ty)) => {
1053 // For Arc<parking_lot::Mutex<T>> (requires rust-key-paths "parking_lot" feature)
1054 let kp_lock_fn = format_ident!("{}_lock", field_ident);
1055 tokens.extend(quote! {
1056 #[inline(always)]
1057 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1058 rust_key_paths::Kp::new(
1059 |root: &#name| Some(&root.#field_ident),
1060 |root: &mut #name| Some(&mut root.#field_ident),
1061 )
1062 }
1063 pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #ty, #inner_ty> {
1064 rust_key_paths::lock::LockKp::new(
1065 rust_key_paths::Kp::new(
1066 |root: &#name| Some(&root.#field_ident),
1067 |root: &mut #name| Some(&mut root.#field_ident),
1068 ),
1069 rust_key_paths::lock::ParkingLotMutexAccess::new(),
1070 rust_key_paths::Kp::new(
1071 |v: &#inner_ty| Some(v),
1072 |v: &mut #inner_ty| Some(v),
1073 ),
1074 )
1075 }
1076 });
1077 }
1078 (WrapperKind::Mutex, Some(_inner_ty))
1079 | (WrapperKind::StdMutex, Some(_inner_ty)) => {
1080 // For Mutex<T>, return keypath to container
1081 tokens.extend(quote! {
1082 #[inline(always)]
1083 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1084 rust_key_paths::Kp::new(
1085 |root: &#name| Some(&root.#field_ident),
1086 |root: &mut #name| Some(&mut root.#field_ident),
1087 )
1088 }
1089 });
1090 }
1091 (WrapperKind::RwLock, Some(_inner_ty))
1092 | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
1093 // For RwLock<T>, return keypath to container
1094 tokens.extend(quote! {
1095 #[inline(always)]
1096 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1097 rust_key_paths::Kp::new(
1098 |root: &#name| Some(&root.#field_ident),
1099 |root: &mut #name| Some(&mut root.#field_ident),
1100 )
1101 }
1102 });
1103 }
1104 (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
1105 let kp_async_fn = format_ident!("{}_async", field_ident);
1106 tokens.extend(quote! {
1107 #[inline(always)]
1108 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1109 rust_key_paths::Kp::new(
1110 |root: &#name| Some(&root.#field_ident),
1111 |root: &mut #name| Some(&mut root.#field_ident),
1112 )
1113 }
1114 pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
1115 rust_key_paths::async_lock::AsyncLockKp::new(
1116 rust_key_paths::Kp::new(
1117 |root: &#name| Some(&root.#field_ident),
1118 |root: &mut #name| Some(&mut root.#field_ident),
1119 ),
1120 rust_key_paths::async_lock::TokioMutexAccess::new(),
1121 rust_key_paths::Kp::new(
1122 |v: &#inner_ty| Some(v),
1123 |v: &mut #inner_ty| Some(v),
1124 ),
1125 )
1126 }
1127 });
1128 }
1129 (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
1130 let kp_async_fn = format_ident!("{}_async", field_ident);
1131 tokens.extend(quote! {
1132 #[inline(always)]
1133 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1134 rust_key_paths::Kp::new(
1135 |root: &#name| Some(&root.#field_ident),
1136 |root: &mut #name| Some(&mut root.#field_ident),
1137 )
1138 }
1139 pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
1140 rust_key_paths::async_lock::AsyncLockKp::new(
1141 rust_key_paths::Kp::new(
1142 |root: &#name| Some(&root.#field_ident),
1143 |root: &mut #name| Some(&mut root.#field_ident),
1144 ),
1145 rust_key_paths::async_lock::TokioRwLockAccess::new(),
1146 rust_key_paths::Kp::new(
1147 |v: &#inner_ty| Some(v),
1148 |v: &mut #inner_ty| Some(v),
1149 ),
1150 )
1151 }
1152 });
1153 }
1154 (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
1155 let kp_async_fn = format_ident!("{}_async", field_ident);
1156 tokens.extend(quote! {
1157 #[inline(always)]
1158 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1159 rust_key_paths::Kp::new(
1160 |root: &#name| Some(&root.#field_ident),
1161 |root: &mut #name| Some(&mut root.#field_ident),
1162 )
1163 }
1164 pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
1165 rust_key_paths::async_lock::AsyncLockKp::new(
1166 rust_key_paths::Kp::new(
1167 |root: &#name| root.#field_ident.as_ref(),
1168 |root: &mut #name| root.#field_ident.as_mut(),
1169 ),
1170 rust_key_paths::async_lock::TokioMutexAccess::new(),
1171 rust_key_paths::Kp::new(
1172 |v: &#inner_ty| Some(v),
1173 |v: &mut #inner_ty| Some(v),
1174 ),
1175 )
1176 }
1177 });
1178 }
1179 (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
1180 let kp_async_fn = format_ident!("{}_async", field_ident);
1181 tokens.extend(quote! {
1182 #[inline(always)]
1183 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1184 rust_key_paths::Kp::new(
1185 |root: &#name| Some(&root.#field_ident),
1186 |root: &mut #name| Some(&mut root.#field_ident),
1187 )
1188 }
1189 pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
1190 rust_key_paths::async_lock::AsyncLockKp::new(
1191 rust_key_paths::Kp::new(
1192 |root: &#name| root.#field_ident.as_ref(),
1193 |root: &mut #name| root.#field_ident.as_mut(),
1194 ),
1195 rust_key_paths::async_lock::TokioRwLockAccess::new(),
1196 rust_key_paths::Kp::new(
1197 |v: &#inner_ty| Some(v),
1198 |v: &mut #inner_ty| Some(v),
1199 ),
1200 )
1201 }
1202 });
1203 }
1204 (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
1205 let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1206 let kp_lock_fn = format_ident!("{}_lock", field_ident);
1207 tokens.extend(quote! {
1208 #[inline(always)]
1209 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1210 rust_key_paths::Kp::new(
1211 |root: &#name| Some(&root.#field_ident),
1212 |root: &mut #name| Some(&mut root.#field_ident),
1213 )
1214 }
1215 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
1216 rust_key_paths::Kp::new(
1217 |root: &#name| root.#field_ident.as_ref(),
1218 |root: &mut #name| root.#field_ident.as_mut(),
1219 )
1220 }
1221 pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
1222 rust_key_paths::lock::LockKp::new(
1223 rust_key_paths::Kp::new(
1224 |root: &#name| root.#field_ident.as_ref(),
1225 |root: &mut #name| root.#field_ident.as_mut(),
1226 ),
1227 rust_key_paths::lock::ArcMutexAccess::new(),
1228 rust_key_paths::Kp::new(
1229 |v: &#inner_ty| Some(v),
1230 |v: &mut #inner_ty| Some(v),
1231 ),
1232 )
1233 }
1234 });
1235 }
1236 (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
1237 let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1238 let kp_lock_fn = format_ident!("{}_lock", field_ident);
1239 tokens.extend(quote! {
1240 #[inline(always)]
1241 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1242 rust_key_paths::Kp::new(
1243 |root: &#name| Some(&root.#field_ident),
1244 |root: &mut #name| Some(&mut root.#field_ident),
1245 )
1246 }
1247 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
1248 rust_key_paths::Kp::new(
1249 |root: &#name| root.#field_ident.as_ref(),
1250 |root: &mut #name| root.#field_ident.as_mut(),
1251 )
1252 }
1253 pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>, #inner_ty> {
1254 rust_key_paths::lock::LockKp::new(
1255 rust_key_paths::Kp::new(
1256 |root: &#name| root.#field_ident.as_ref(),
1257 |root: &mut #name| root.#field_ident.as_mut(),
1258 ),
1259 rust_key_paths::lock::ParkingLotMutexAccess::new(),
1260 rust_key_paths::Kp::new(
1261 |v: &#inner_ty| Some(v),
1262 |v: &mut #inner_ty| Some(v),
1263 ),
1264 )
1265 }
1266 });
1267 }
1268 (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
1269 let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1270 let kp_lock_fn = format_ident!("{}_lock", field_ident);
1271 tokens.extend(quote! {
1272 #[inline(always)]
1273 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1274 rust_key_paths::Kp::new(
1275 |root: &#name| Some(&root.#field_ident),
1276 |root: &mut #name| Some(&mut root.#field_ident),
1277 )
1278 }
1279 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
1280 rust_key_paths::Kp::new(
1281 |root: &#name| root.#field_ident.as_ref(),
1282 |root: &mut #name| root.#field_ident.as_mut(),
1283 )
1284 }
1285 pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
1286 rust_key_paths::lock::LockKp::new(
1287 rust_key_paths::Kp::new(
1288 |root: &#name| root.#field_ident.as_ref(),
1289 |root: &mut #name| root.#field_ident.as_mut(),
1290 ),
1291 rust_key_paths::lock::ArcRwLockAccess::new(),
1292 rust_key_paths::Kp::new(
1293 |v: &#inner_ty| Some(v),
1294 |v: &mut #inner_ty| Some(v),
1295 ),
1296 )
1297 }
1298 });
1299 }
1300 (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
1301 let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1302 let kp_lock_fn = format_ident!("{}_lock", field_ident);
1303 tokens.extend(quote! {
1304 #[inline(always)]
1305 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1306 rust_key_paths::Kp::new(
1307 |root: &#name| Some(&root.#field_ident),
1308 |root: &mut #name| Some(&mut root.#field_ident),
1309 )
1310 }
1311 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
1312 rust_key_paths::Kp::new(
1313 |root: &#name| root.#field_ident.as_ref(),
1314 |root: &mut #name| root.#field_ident.as_mut(),
1315 )
1316 }
1317 pub fn #kp_lock_fn() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>, #inner_ty> {
1318 rust_key_paths::lock::LockKp::new(
1319 rust_key_paths::Kp::new(
1320 |root: &#name| root.#field_ident.as_ref(),
1321 |root: &mut #name| root.#field_ident.as_mut(),
1322 ),
1323 rust_key_paths::lock::ParkingLotRwLockAccess::new(),
1324 rust_key_paths::Kp::new(
1325 |v: &#inner_ty| Some(v),
1326 |v: &mut #inner_ty| Some(v),
1327 ),
1328 )
1329 }
1330 });
1331 }
1332 (WrapperKind::OptionStdMutex, Some(inner_ty))
1333 | (WrapperKind::OptionMutex, Some(inner_ty)) => {
1334 let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1335 tokens.extend(quote! {
1336 #[inline(always)]
1337 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1338 rust_key_paths::Kp::new(
1339 |root: &#name| Some(&root.#field_ident),
1340 |root: &mut #name| Some(&mut root.#field_ident),
1341 )
1342 }
1343 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
1344 rust_key_paths::Kp::new(
1345 |root: &#name| root.#field_ident.as_ref(),
1346 |root: &mut #name| root.#field_ident.as_mut(),
1347 )
1348 }
1349 });
1350 }
1351 (WrapperKind::OptionStdRwLock, Some(inner_ty))
1352 | (WrapperKind::OptionRwLock, Some(inner_ty)) => {
1353 let kp_unlocked_fn = format_ident!("{}_unlocked", field_ident);
1354 tokens.extend(quote! {
1355 #[inline(always)]
1356 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1357 rust_key_paths::Kp::new(
1358 |root: &#name| Some(&root.#field_ident),
1359 |root: &mut #name| Some(&mut root.#field_ident),
1360 )
1361 }
1362 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
1363 rust_key_paths::Kp::new(
1364 |root: &#name| root.#field_ident.as_ref(),
1365 |root: &mut #name| root.#field_ident.as_mut(),
1366 )
1367 }
1368 });
1369 }
1370 (WrapperKind::Weak, Some(_inner_ty)) => {
1371 // For Weak<T>, return keypath to container
1372 tokens.extend(quote! {
1373 #[inline(always)]
1374 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1375 rust_key_paths::Kp::new(
1376 |root: &#name| Some(&root.#field_ident),
1377 |_root: &mut #name| None, // Weak doesn't support mutable access
1378 )
1379 }
1380 });
1381 }
1382 (WrapperKind::Atomic, None | Some(_)) => {
1383 // For atomic types: return keypath to the atomic (user calls .load()/.store())
1384 tokens.extend(quote! {
1385 #[inline(always)]
1386 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1387 rust_key_paths::Kp::new(
1388 |root: &#name| Some(&root.#field_ident),
1389 |root: &mut #name| Some(&mut root.#field_ident),
1390 )
1391 }
1392 });
1393 }
1394 (WrapperKind::OptionAtomic, Some(inner_ty)) => {
1395 tokens.extend(quote! {
1396 #[inline(always)]
1397 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1398 rust_key_paths::Kp::new(
1399 |root: &#name| root.#field_ident.as_ref(),
1400 |root: &mut #name| root.#field_ident.as_mut(),
1401 )
1402 }
1403 });
1404 }
1405 (WrapperKind::Reference, Some(_inner_ty)) => {
1406 // For reference types (&T, &str, &[T]): read-only, setter returns None
1407 tokens.extend(quote! {
1408 #[inline(always)]
1409 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1410 rust_key_paths::Kp::new(
1411 |root: &#name| Some(&root.#field_ident),
1412 |_root: &mut #name| None, // references: read-only
1413 )
1414 }
1415 });
1416 }
1417 (WrapperKind::None, None) => {
1418 // For basic types, direct access
1419 tokens.extend(quote! {
1420 #[inline(always)]
1421 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1422 rust_key_paths::Kp::new(
1423 |root: &#name| Some(&root.#field_ident),
1424 |root: &mut #name| Some(&mut root.#field_ident),
1425 )
1426 }
1427 });
1428 }
1429 _ => {
1430 // For unknown/complex nested types, return keypath to field itself
1431 tokens.extend(quote! {
1432 #[inline(always)]
1433 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1434 rust_key_paths::Kp::new(
1435 |root: &#name| Some(&root.#field_ident),
1436 |root: &mut #name| Some(&mut root.#field_ident),
1437 )
1438 }
1439 });
1440 }
1441 }
1442 }
1443
1444 tokens
1445 }
1446 Fields::Unnamed(unnamed) => {
1447 let mut tokens = proc_macro2::TokenStream::new();
1448
1449 // Generate identity methods for the tuple struct
1450 tokens.extend(quote! {
1451 /// Returns a generic identity keypath for this type
1452 #[inline(always)]
1453 pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
1454 #name,
1455 #name,
1456 Root,
1457 Root,
1458 MutRoot,
1459 MutRoot,
1460 fn(Root) -> Option<Root>,
1461 fn(MutRoot) -> Option<MutRoot>,
1462 >
1463 where
1464 Root: std::borrow::Borrow<#name>,
1465 MutRoot: std::borrow::BorrowMut<#name>,
1466 {
1467 rust_key_paths::Kp::new(
1468 |r: Root| Some(r),
1469 |r: MutRoot| Some(r)
1470 )
1471 }
1472
1473 /// Returns a simple identity keypath for this type
1474 #[inline(always)]
1475 pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
1476 rust_key_paths::Kp::new(
1477 |r: &#name| Some(r),
1478 |r: &mut #name| Some(r)
1479 )
1480 }
1481 });
1482
1483 for (idx, field) in unnamed.unnamed.iter().enumerate() {
1484 let idx_lit = syn::Index::from(idx);
1485 let ty = &field.ty;
1486 // Centralized keypath method names for tuple fields – change here to adjust for all types
1487 let kp_fn = format_ident!("f{}", idx);
1488 let kp_at_fn = format_ident!("f{}_at", idx);
1489
1490 let (kind, inner_ty) = extract_wrapper_inner_type(ty);
1491
1492 match (kind, inner_ty.clone()) {
1493 (WrapperKind::Option, Some(inner_ty)) => {
1494 tokens.extend(quote! {
1495 #[inline(always)]
1496 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1497 rust_key_paths::Kp::new(
1498 |root: &#name| root.#idx_lit.as_ref(),
1499 |root: &mut #name| root.#idx_lit.as_mut(),
1500 )
1501 }
1502 });
1503 }
1504 (WrapperKind::Vec, Some(inner_ty)) => {
1505 tokens.extend(quote! {
1506 #[inline(always)]
1507 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1508 rust_key_paths::Kp::new(
1509 |root: &#name| Some(&root.#idx_lit),
1510 |root: &mut #name| Some(&mut root.#idx_lit),
1511 )
1512 }
1513 #[inline(always)]
1514 pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1515 rust_key_paths::Kp::new(
1516 Box::new(move |root: &#name| root.#idx_lit.get(index)),
1517 Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
1518 )
1519 }
1520 });
1521 }
1522 (WrapperKind::HashMap, Some(inner_ty)) => {
1523 if let Some((key_ty, _)) = extract_map_key_value(ty) {
1524 tokens.extend(quote! {
1525 #[inline(always)]
1526 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1527 rust_key_paths::Kp::new(
1528 |root: &#name| Some(&root.#idx_lit),
1529 |root: &mut #name| Some(&mut root.#idx_lit),
1530 )
1531 }
1532 #[inline(always)]
1533 pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1534 where
1535 #key_ty: Clone + std::hash::Hash + Eq + 'static,
1536 {
1537 let key2 = key.clone();
1538 rust_key_paths::Kp::new(
1539 Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1540 Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
1541 )
1542 }
1543 });
1544 } else {
1545 tokens.extend(quote! {
1546 #[inline(always)]
1547 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1548 rust_key_paths::Kp::new(
1549 |root: &#name| Some(&root.#idx_lit),
1550 |root: &mut #name| Some(&mut root.#idx_lit),
1551 )
1552 }
1553 });
1554 }
1555 }
1556 (WrapperKind::BTreeMap, Some(inner_ty)) => {
1557 if let Some((key_ty, _)) = extract_map_key_value(ty) {
1558 tokens.extend(quote! {
1559 #[inline(always)]
1560 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1561 rust_key_paths::Kp::new(
1562 |root: &#name| Some(&root.#idx_lit),
1563 |root: &mut #name| Some(&mut root.#idx_lit),
1564 )
1565 }
1566 #[inline(always)]
1567 pub fn #kp_at_fn(key: #key_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1568 where
1569 #key_ty: Clone + Ord + 'static,
1570 {
1571 let key2 = key.clone();
1572 rust_key_paths::Kp::new(
1573 Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1574 Box::new(move |root: &mut #name| root.#idx_lit.get_mut(&key2)),
1575 )
1576 }
1577 });
1578 } else {
1579 tokens.extend(quote! {
1580 #[inline(always)]
1581 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1582 rust_key_paths::Kp::new(
1583 |root: &#name| Some(&root.#idx_lit),
1584 |root: &mut #name| Some(&mut root.#idx_lit),
1585 )
1586 }
1587 });
1588 }
1589 }
1590 (WrapperKind::Box, Some(inner_ty)) => {
1591 // Box: deref to inner (returns &T / &mut T)
1592 tokens.extend(quote! {
1593 #[inline(always)]
1594 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1595 rust_key_paths::Kp::new(
1596 |root: &#name| Some(&*root.#idx_lit),
1597 |root: &mut #name| Some(&mut *root.#idx_lit),
1598 )
1599 }
1600 });
1601 }
1602 (WrapperKind::Pin, Some(inner_ty)) => {
1603 let kp_inner_fn = format_ident!("{}_inner", kp_fn);
1604 tokens.extend(quote! {
1605 #[inline(always)]
1606 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1607 rust_key_paths::Kp::new(
1608 |root: &#name| Some(&root.#idx_lit),
1609 |root: &mut #name| Some(&mut root.#idx_lit),
1610 )
1611 }
1612 #[inline(always)]
1613 pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
1614 where #inner_ty: std::marker::Unpin
1615 {
1616 rust_key_paths::Kp::new(
1617 |root: &#name| Some(std::pin::Pin::as_ref(&root.#idx_lit).get_ref()),
1618 |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#idx_lit).get_mut()),
1619 )
1620 }
1621 });
1622 }
1623 (WrapperKind::PinBox, Some(inner_ty)) => {
1624 let kp_inner_fn = format_ident!("{}_inner", kp_fn);
1625 tokens.extend(quote! {
1626 #[inline(always)]
1627 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1628 rust_key_paths::Kp::new(
1629 |root: &#name| Some(&root.#idx_lit),
1630 |root: &mut #name| Some(&mut root.#idx_lit),
1631 )
1632 }
1633 #[inline(always)]
1634 pub fn #kp_inner_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty>
1635 where #inner_ty: std::marker::Unpin
1636 {
1637 rust_key_paths::Kp::new(
1638 |root: &#name| Some(std::pin::Pin::as_ref(&root.#idx_lit).get_ref()),
1639 |root: &mut #name| Some(std::pin::Pin::as_mut(&mut root.#idx_lit).get_mut()),
1640 )
1641 }
1642 });
1643 }
1644 (WrapperKind::Rc, Some(inner_ty)) => {
1645 tokens.extend(quote! {
1646 #[inline(always)]
1647 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1648 rust_key_paths::Kp::new(
1649 |root: &#name| Some(root.#idx_lit.as_ref()),
1650 |root: &mut #name| std::rc::Rc::get_mut(&mut root.#idx_lit),
1651 )
1652 }
1653 });
1654 }
1655 (WrapperKind::Arc, Some(inner_ty)) => {
1656 tokens.extend(quote! {
1657 #[inline(always)]
1658 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1659 rust_key_paths::Kp::new(
1660 |root: &#name| Some(root.#idx_lit.as_ref()),
1661 |root: &mut #name| std::sync::Arc::get_mut(&mut root.#idx_lit),
1662 )
1663 }
1664 });
1665 }
1666
1667 (WrapperKind::Cow, Some(inner_ty)) => {
1668 tokens.extend(quote! {
1669 #[inline(always)]
1670 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1671 rust_key_paths::Kp::new(
1672 |root: &#name| Some(root.#idx_lit.as_ref()),
1673 |root: &mut #name| Some(root.#idx_lit.to_mut()),
1674 )
1675 }
1676 });
1677 }
1678
1679 (WrapperKind::OptionCow, Some(inner_ty)) => {
1680 tokens.extend(quote! {
1681 #[inline(always)]
1682 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1683 rust_key_paths::Kp::new(
1684 |root: &#name| root.#idx_lit.as_ref().map(|c| c.as_ref()),
1685 |root: &mut #name| root.#idx_lit.as_mut().map(|c| c.to_mut()),
1686 )
1687 }
1688 });
1689 }
1690 (WrapperKind::OptionTagged, Some(inner_ty)) => {
1691 tokens.extend(quote! {
1692 #[inline(always)]
1693 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1694 rust_key_paths::Kp::new(
1695 |root: &#name| root.#idx_lit.as_ref().map(|t| std::ops::Deref::deref(t)),
1696 |root: &mut #name| root.#idx_lit.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
1697 )
1698 }
1699 });
1700 }
1701 (WrapperKind::OptionReference, Some(inner_ty)) => {
1702 tokens.extend(quote! {
1703 #[inline(always)]
1704 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1705 rust_key_paths::Kp::new(
1706 |root: &#name| root.#idx_lit.as_ref(),
1707 |_root: &mut #name| None,
1708 )
1709 }
1710 });
1711 }
1712 (WrapperKind::HashSet, Some(inner_ty)) => {
1713 let kp_at_fn = format_ident!("f{}_at", idx);
1714
1715 tokens.extend(quote! {
1716 #[inline(always)]
1717 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1718 rust_key_paths::Kp::new(
1719 |root: &#name| Some(&root.#idx_lit),
1720 |root: &mut #name| Some(&mut root.#idx_lit),
1721 )
1722 }
1723
1724 /// _at: check if element exists and get reference.
1725 /// HashSet does not allow mutable element access (would break hash invariant).
1726 #[inline(always)]
1727 pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1728 where
1729 #inner_ty: Clone + std::hash::Hash + Eq + 'static,
1730 {
1731 rust_key_paths::Kp::new(
1732 Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1733 Box::new(move |_root: &mut #name| None),
1734 )
1735 }
1736 });
1737 }
1738 (WrapperKind::BTreeSet, Some(inner_ty)) => {
1739 let kp_at_fn = format_ident!("f{}_at", idx);
1740
1741 tokens.extend(quote! {
1742 #[inline(always)]
1743 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1744 rust_key_paths::Kp::new(
1745 |root: &#name| Some(&root.#idx_lit),
1746 |root: &mut #name| Some(&mut root.#idx_lit),
1747 )
1748 }
1749
1750 /// _at: check if element exists and get reference.
1751 /// BTreeSet does not allow mutable element access (would break ordering invariant).
1752 #[inline(always)]
1753 pub fn #kp_at_fn(key: #inner_ty) -> rust_key_paths::KpDynamic<#name, #inner_ty>
1754 where
1755 #inner_ty: Clone + Ord + 'static,
1756 {
1757 rust_key_paths::Kp::new(
1758 Box::new(move |root: &#name| root.#idx_lit.get(&key)),
1759 Box::new(move |_root: &mut #name| None),
1760 )
1761 }
1762 });
1763 }
1764 (WrapperKind::VecDeque, Some(inner_ty)) => {
1765 tokens.extend(quote! {
1766 #[inline(always)]
1767 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1768 rust_key_paths::Kp::new(
1769 |root: &#name| Some(&root.#idx_lit),
1770 |root: &mut #name| Some(&mut root.#idx_lit),
1771 )
1772 }
1773 #[inline(always)]
1774 pub fn #kp_at_fn(index: usize) -> rust_key_paths::KpDynamic<#name, #inner_ty> {
1775 rust_key_paths::Kp::new(
1776 Box::new(move |root: &#name| root.#idx_lit.get(index)),
1777 Box::new(move |root: &mut #name| root.#idx_lit.get_mut(index)),
1778 )
1779 }
1780 });
1781 }
1782 (WrapperKind::LinkedList, Some(_inner_ty)) => {
1783 tokens.extend(quote! {
1784 #[inline(always)]
1785 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1786 rust_key_paths::Kp::new(
1787 |root: &#name| Some(&root.#idx_lit),
1788 |root: &mut #name| Some(&mut root.#idx_lit),
1789 )
1790 }
1791 });
1792 }
1793 (WrapperKind::BinaryHeap, Some(_inner_ty)) => {
1794 tokens.extend(quote! {
1795 #[inline(always)]
1796 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1797 rust_key_paths::Kp::new(
1798 |root: &#name| Some(&root.#idx_lit),
1799 |root: &mut #name| Some(&mut root.#idx_lit),
1800 )
1801 }
1802 });
1803 }
1804 (WrapperKind::Result, Some(inner_ty)) => {
1805 tokens.extend(quote! {
1806 #[inline(always)]
1807 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
1808 rust_key_paths::Kp::new(
1809 |root: &#name| root.#idx_lit.as_ref().ok(),
1810 |root: &mut #name| root.#idx_lit.as_mut().ok(),
1811 )
1812 }
1813 });
1814 }
1815 (WrapperKind::Mutex, Some(_inner_ty))
1816 | (WrapperKind::StdMutex, Some(_inner_ty)) => {
1817 tokens.extend(quote! {
1818 #[inline(always)]
1819 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1820 rust_key_paths::Kp::new(
1821 |root: &#name| Some(&root.#idx_lit),
1822 |root: &mut #name| Some(&mut root.#idx_lit),
1823 )
1824 }
1825 });
1826 }
1827 (WrapperKind::RwLock, Some(_inner_ty))
1828 | (WrapperKind::StdRwLock, Some(_inner_ty)) => {
1829 tokens.extend(quote! {
1830 #[inline(always)]
1831 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1832 rust_key_paths::Kp::new(
1833 |root: &#name| Some(&root.#idx_lit),
1834 |root: &mut #name| Some(&mut root.#idx_lit),
1835 )
1836 }
1837 });
1838 }
1839 (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
1840 let kp_async_fn = format_ident!("f{}_async", idx);
1841 tokens.extend(quote! {
1842 #[inline(always)]
1843 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1844 rust_key_paths::Kp::new(
1845 |root: &#name| Some(&root.#idx_lit),
1846 |root: &mut #name| Some(&mut root.#idx_lit),
1847 )
1848 }
1849 pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #ty, #inner_ty> {
1850 rust_key_paths::async_lock::AsyncLockKp::new(
1851 rust_key_paths::Kp::new(
1852 |root: &#name| Some(&root.#idx_lit),
1853 |root: &mut #name| Some(&mut root.#idx_lit),
1854 ),
1855 rust_key_paths::async_lock::TokioMutexAccess::new(),
1856 rust_key_paths::Kp::new(
1857 |v: &#inner_ty| Some(v),
1858 |v: &mut #inner_ty| Some(v),
1859 ),
1860 )
1861 }
1862 });
1863 }
1864 (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
1865 let kp_async_fn = format_ident!("f{}_async", idx);
1866 tokens.extend(quote! {
1867 #[inline(always)]
1868 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1869 rust_key_paths::Kp::new(
1870 |root: &#name| Some(&root.#idx_lit),
1871 |root: &mut #name| Some(&mut root.#idx_lit),
1872 )
1873 }
1874 pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #ty, #inner_ty> {
1875 rust_key_paths::async_lock::AsyncLockKp::new(
1876 rust_key_paths::Kp::new(
1877 |root: &#name| Some(&root.#idx_lit),
1878 |root: &mut #name| Some(&mut root.#idx_lit),
1879 ),
1880 rust_key_paths::async_lock::TokioRwLockAccess::new(),
1881 rust_key_paths::Kp::new(
1882 |v: &#inner_ty| Some(v),
1883 |v: &mut #inner_ty| Some(v),
1884 ),
1885 )
1886 }
1887 });
1888 }
1889 (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
1890 let kp_async_fn = format_ident!("f{}_async", idx);
1891 tokens.extend(quote! {
1892 #[inline(always)]
1893 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1894 rust_key_paths::Kp::new(
1895 |root: &#name| Some(&root.#idx_lit),
1896 |root: &mut #name| Some(&mut root.#idx_lit),
1897 )
1898 }
1899 pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
1900 rust_key_paths::async_lock::AsyncLockKp::new(
1901 rust_key_paths::Kp::new(
1902 |root: &#name| root.#idx_lit.as_ref(),
1903 |root: &mut #name| root.#idx_lit.as_mut(),
1904 ),
1905 rust_key_paths::async_lock::TokioMutexAccess::new(),
1906 rust_key_paths::Kp::new(
1907 |v: &#inner_ty| Some(v),
1908 |v: &mut #inner_ty| Some(v),
1909 ),
1910 )
1911 }
1912 });
1913 }
1914 (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
1915 let kp_async_fn = format_ident!("f{}_async", idx);
1916 tokens.extend(quote! {
1917 #[inline(always)]
1918 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1919 rust_key_paths::Kp::new(
1920 |root: &#name| Some(&root.#idx_lit),
1921 |root: &mut #name| Some(&mut root.#idx_lit),
1922 )
1923 }
1924 pub fn #kp_async_fn() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
1925 rust_key_paths::async_lock::AsyncLockKp::new(
1926 rust_key_paths::Kp::new(
1927 |root: &#name| root.#idx_lit.as_ref(),
1928 |root: &mut #name| root.#idx_lit.as_mut(),
1929 ),
1930 rust_key_paths::async_lock::TokioRwLockAccess::new(),
1931 rust_key_paths::Kp::new(
1932 |v: &#inner_ty| Some(v),
1933 |v: &mut #inner_ty| Some(v),
1934 ),
1935 )
1936 }
1937 });
1938 }
1939 (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
1940 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1941 tokens.extend(quote! {
1942 #[inline(always)]
1943 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1944 rust_key_paths::Kp::new(
1945 |root: &#name| Some(&root.#idx_lit),
1946 |root: &mut #name| Some(&mut root.#idx_lit),
1947 )
1948 }
1949 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
1950 rust_key_paths::Kp::new(
1951 |root: &#name| root.#idx_lit.as_ref(),
1952 |root: &mut #name| root.#idx_lit.as_mut(),
1953 )
1954 }
1955 });
1956 }
1957 (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
1958 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1959 tokens.extend(quote! {
1960 #[inline(always)]
1961 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1962 rust_key_paths::Kp::new(
1963 |root: &#name| Some(&root.#idx_lit),
1964 |root: &mut #name| Some(&mut root.#idx_lit),
1965 )
1966 }
1967 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
1968 rust_key_paths::Kp::new(
1969 |root: &#name| root.#idx_lit.as_ref(),
1970 |root: &mut #name| root.#idx_lit.as_mut(),
1971 )
1972 }
1973 });
1974 }
1975 (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
1976 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1977 tokens.extend(quote! {
1978 #[inline(always)]
1979 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1980 rust_key_paths::Kp::new(
1981 |root: &#name| Some(&root.#idx_lit),
1982 |root: &mut #name| Some(&mut root.#idx_lit),
1983 )
1984 }
1985 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
1986 rust_key_paths::Kp::new(
1987 |root: &#name| root.#idx_lit.as_ref(),
1988 |root: &mut #name| root.#idx_lit.as_mut(),
1989 )
1990 }
1991 });
1992 }
1993 (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
1994 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
1995 tokens.extend(quote! {
1996 #[inline(always)]
1997 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
1998 rust_key_paths::Kp::new(
1999 |root: &#name| Some(&root.#idx_lit),
2000 |root: &mut #name| Some(&mut root.#idx_lit),
2001 )
2002 }
2003 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
2004 rust_key_paths::Kp::new(
2005 |root: &#name| root.#idx_lit.as_ref(),
2006 |root: &mut #name| root.#idx_lit.as_mut(),
2007 )
2008 }
2009 });
2010 }
2011 (WrapperKind::OptionStdMutex, Some(inner_ty))
2012 | (WrapperKind::OptionMutex, Some(inner_ty)) => {
2013 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2014 tokens.extend(quote! {
2015 #[inline(always)]
2016 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2017 rust_key_paths::Kp::new(
2018 |root: &#name| Some(&root.#idx_lit),
2019 |root: &mut #name| Some(&mut root.#idx_lit),
2020 )
2021 }
2022 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::Mutex<#inner_ty>> {
2023 rust_key_paths::Kp::new(
2024 |root: &#name| root.#idx_lit.as_ref(),
2025 |root: &mut #name| root.#idx_lit.as_mut(),
2026 )
2027 }
2028 });
2029 }
2030 (WrapperKind::OptionStdRwLock, Some(inner_ty))
2031 | (WrapperKind::OptionRwLock, Some(inner_ty)) => {
2032 let kp_unlocked_fn = format_ident!("f{}_unlocked", idx);
2033 tokens.extend(quote! {
2034 #[inline(always)]
2035 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2036 rust_key_paths::Kp::new(
2037 |root: &#name| Some(&root.#idx_lit),
2038 |root: &mut #name| Some(&mut root.#idx_lit),
2039 )
2040 }
2041 pub fn #kp_unlocked_fn() -> rust_key_paths::KpType<'static, #name, std::sync::RwLock<#inner_ty>> {
2042 rust_key_paths::Kp::new(
2043 |root: &#name| root.#idx_lit.as_ref(),
2044 |root: &mut #name| root.#idx_lit.as_mut(),
2045 )
2046 }
2047 });
2048 }
2049 (WrapperKind::Weak, Some(_inner_ty)) => {
2050 tokens.extend(quote! {
2051 #[inline(always)]
2052 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2053 rust_key_paths::Kp::new(
2054 |root: &#name| Some(&root.#idx_lit),
2055 |_root: &mut #name| None,
2056 )
2057 }
2058 });
2059 }
2060 (WrapperKind::Atomic, None | Some(_)) => {
2061 tokens.extend(quote! {
2062 #[inline(always)]
2063 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2064 rust_key_paths::Kp::new(
2065 |root: &#name| Some(&root.#idx_lit),
2066 |root: &mut #name| Some(&mut root.#idx_lit),
2067 )
2068 }
2069 });
2070 }
2071 (WrapperKind::OptionAtomic, Some(inner_ty)) => {
2072 tokens.extend(quote! {
2073 #[inline(always)]
2074 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2075 rust_key_paths::Kp::new(
2076 |root: &#name| root.#idx_lit.as_ref(),
2077 |root: &mut #name| root.#idx_lit.as_mut(),
2078 )
2079 }
2080 });
2081 }
2082 (WrapperKind::Reference, Some(_inner_ty)) => {
2083 tokens.extend(quote! {
2084 #[inline(always)]
2085 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2086 rust_key_paths::Kp::new(
2087 |root: &#name| Some(&root.#idx_lit),
2088 |_root: &mut #name| None,
2089 )
2090 }
2091 });
2092 }
2093 (WrapperKind::None, None) => {
2094 tokens.extend(quote! {
2095 #[inline(always)]
2096 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2097 rust_key_paths::Kp::new(
2098 |root: &#name| Some(&root.#idx_lit),
2099 |root: &mut #name| Some(&mut root.#idx_lit),
2100 )
2101 }
2102 });
2103 }
2104 _ => {
2105 tokens.extend(quote! {
2106 #[inline(always)]
2107 pub fn #kp_fn() -> rust_key_paths::KpType<'static, #name, #ty> {
2108 rust_key_paths::Kp::new(
2109 |root: &#name| Some(&root.#idx_lit),
2110 |root: &mut #name| Some(&mut root.#idx_lit),
2111 )
2112 }
2113 });
2114 }
2115 }
2116 }
2117
2118 tokens
2119 }
2120 Fields::Unit => {
2121 return syn::Error::new(input_span, "Kp derive does not support unit structs")
2122 .to_compile_error()
2123 .into();
2124 }
2125 },
2126 Data::Enum(data_enum) => {
2127 let mut tokens = proc_macro2::TokenStream::new();
2128
2129 // Generate identity methods for the enum
2130 tokens.extend(quote! {
2131 /// Returns a generic identity keypath for this type
2132 #[inline(always)]
2133 pub fn identity_typed<Root, MutRoot>() -> rust_key_paths::Kp<
2134 #name,
2135 #name,
2136 Root,
2137 Root,
2138 MutRoot,
2139 MutRoot,
2140 fn(Root) -> Option<Root>,
2141 fn(MutRoot) -> Option<MutRoot>,
2142 >
2143 where
2144 Root: std::borrow::Borrow<#name>,
2145 MutRoot: std::borrow::BorrowMut<#name>,
2146 {
2147 rust_key_paths::Kp::new(
2148 |r: Root| Some(r),
2149 |r: MutRoot| Some(r)
2150 )
2151 }
2152
2153 /// Returns a simple identity keypath for this type
2154 #[inline(always)]
2155 pub fn identity() -> rust_key_paths::KpType<'static, #name, #name> {
2156 rust_key_paths::Kp::new(
2157 |r: &#name| Some(r),
2158 |r: &mut #name| Some(r)
2159 )
2160 }
2161 });
2162
2163 for variant in data_enum.variants.iter() {
2164 let v_ident = &variant.ident;
2165 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
2166
2167 match &variant.fields {
2168 Fields::Unit => {
2169 // Unit variant - return keypath that checks if enum matches variant
2170 tokens.extend(quote! {
2171 #[inline(always)]
2172 pub fn #snake() -> rust_key_paths::KpType<'static, #name, ()> {
2173 rust_key_paths::Kp::new(
2174 |root: &#name| match root {
2175 #name::#v_ident => {
2176 static UNIT: () = ();
2177 Some(&UNIT)
2178 },
2179 _ => None,
2180 },
2181 |_root: &mut #name| None, // Can't mutate unit variant
2182 )
2183 }
2184 });
2185 }
2186 Fields::Unnamed(unnamed) => {
2187 if unnamed.unnamed.len() == 1 {
2188 // Single-field tuple variant
2189 let field_ty = &unnamed.unnamed[0].ty;
2190 let (kind, inner_ty) = extract_wrapper_inner_type(field_ty);
2191
2192 match (kind, inner_ty.clone()) {
2193 (WrapperKind::Option, Some(inner_ty)) => {
2194 tokens.extend(quote! {
2195 #[inline(always)]
2196 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2197 rust_key_paths::Kp::new(
2198 |root: &#name| match root {
2199 #name::#v_ident(inner) => inner.as_ref(),
2200 _ => None,
2201 },
2202 |root: &mut #name| match root {
2203 #name::#v_ident(inner) => inner.as_mut(),
2204 _ => None,
2205 },
2206 )
2207 }
2208 });
2209 }
2210 (WrapperKind::Vec, Some(inner_ty)) => {
2211 tokens.extend(quote! {
2212 #[inline(always)]
2213 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2214 rust_key_paths::Kp::new(
2215 |root: &#name| match root {
2216 #name::#v_ident(inner) => inner.first(),
2217 _ => None,
2218 },
2219 |root: &mut #name| match root {
2220 #name::#v_ident(inner) => inner.first_mut(),
2221 _ => None,
2222 },
2223 )
2224 }
2225 });
2226 }
2227 (WrapperKind::Box, Some(inner_ty)) => {
2228 // Box in enum: deref to inner (&T / &mut T)
2229 tokens.extend(quote! {
2230 #[inline(always)]
2231 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2232 rust_key_paths::Kp::new(
2233 |root: &#name| match root {
2234 #name::#v_ident(inner) => Some(&**inner),
2235 _ => None,
2236 },
2237 |root: &mut #name| match root {
2238 #name::#v_ident(inner) => Some(&mut **inner),
2239 _ => None,
2240 },
2241 )
2242 }
2243 });
2244 }
2245 (WrapperKind::Pin, Some(inner_ty)) => {
2246 let snake_inner = format_ident!("{}_inner", snake);
2247 tokens.extend(quote! {
2248 #[inline(always)]
2249 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2250 rust_key_paths::Kp::new(
2251 |root: &#name| match root {
2252 #name::#v_ident(inner) => Some(inner),
2253 _ => None,
2254 },
2255 |root: &mut #name| match root {
2256 #name::#v_ident(inner) => Some(inner),
2257 _ => None,
2258 },
2259 )
2260 }
2261 #[inline(always)]
2262 pub fn #snake_inner() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2263 where #inner_ty: std::marker::Unpin
2264 {
2265 rust_key_paths::Kp::new(
2266 |root: &#name| match root {
2267 #name::#v_ident(inner) => Some(std::pin::Pin::as_ref(inner).get_ref()),
2268 _ => None,
2269 },
2270 |root: &mut #name| match root {
2271 #name::#v_ident(inner) => Some(std::pin::Pin::as_mut(inner).get_mut()),
2272 _ => None,
2273 },
2274 )
2275 }
2276 });
2277 }
2278 (WrapperKind::PinBox, Some(inner_ty)) => {
2279 let snake_inner = format_ident!("{}_inner", snake);
2280 tokens.extend(quote! {
2281 #[inline(always)]
2282 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2283 rust_key_paths::Kp::new(
2284 |root: &#name| match root {
2285 #name::#v_ident(inner) => Some(inner),
2286 _ => None,
2287 },
2288 |root: &mut #name| match root {
2289 #name::#v_ident(inner) => Some(inner),
2290 _ => None,
2291 },
2292 )
2293 }
2294 #[inline(always)]
2295 pub fn #snake_inner() -> rust_key_paths::KpType<'static, #name, #inner_ty>
2296 where #inner_ty: std::marker::Unpin
2297 {
2298 rust_key_paths::Kp::new(
2299 |root: &#name| match root {
2300 #name::#v_ident(inner) => Some(std::pin::Pin::as_ref(inner).get_ref()),
2301 _ => None,
2302 },
2303 |root: &mut #name| match root {
2304 #name::#v_ident(inner) => Some(std::pin::Pin::as_mut(inner).get_mut()),
2305 _ => None,
2306 },
2307 )
2308 }
2309 });
2310 }
2311 (WrapperKind::Rc, Some(inner_ty)) => {
2312 tokens.extend(quote! {
2313 #[inline(always)]
2314 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2315 rust_key_paths::Kp::new(
2316 |root: &#name| match root {
2317 #name::#v_ident(inner) => Some(inner.as_ref()),
2318 _ => None,
2319 },
2320 |root: &mut #name| match root {
2321 #name::#v_ident(inner) => std::rc::Rc::get_mut(inner),
2322 _ => None,
2323 },
2324 )
2325 }
2326 });
2327 }
2328 (WrapperKind::Arc, Some(inner_ty)) => {
2329 tokens.extend(quote! {
2330 #[inline(always)]
2331 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2332 rust_key_paths::Kp::new(
2333 |root: &#name| match root {
2334 #name::#v_ident(inner) => Some(inner.as_ref()),
2335 _ => None,
2336 },
2337 |root: &mut #name| match root {
2338 #name::#v_ident(inner) => std::sync::Arc::get_mut(inner),
2339 _ => None,
2340 },
2341 )
2342 }
2343 });
2344 }
2345 (WrapperKind::StdArcRwLock, Some(inner_ty)) => {
2346 let snake_lock = format_ident!("{}_lock", snake);
2347 tokens.extend(quote! {
2348 #[inline(always)]
2349 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2350 rust_key_paths::Kp::new(
2351 |root: &#name| match root {
2352 #name::#v_ident(inner) => Some(inner),
2353 _ => None,
2354 },
2355 |root: &mut #name| match root {
2356 #name::#v_ident(inner) => Some(inner),
2357 _ => None,
2358 },
2359 )
2360 }
2361 pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, #field_ty, #inner_ty> {
2362 rust_key_paths::lock::LockKp::new(
2363 rust_key_paths::Kp::new(
2364 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2365 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2366 ),
2367 rust_key_paths::lock::ArcRwLockAccess::new(),
2368 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2369 )
2370 }
2371 });
2372 }
2373 (WrapperKind::StdArcMutex, Some(inner_ty)) => {
2374 let snake_lock = format_ident!("{}_lock", snake);
2375 tokens.extend(quote! {
2376 #[inline(always)]
2377 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2378 rust_key_paths::Kp::new(
2379 |root: &#name| match root {
2380 #name::#v_ident(inner) => Some(inner),
2381 _ => None,
2382 },
2383 |root: &mut #name| match root {
2384 #name::#v_ident(inner) => Some(inner),
2385 _ => None,
2386 },
2387 )
2388 }
2389 pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexFor<#name, #field_ty, #inner_ty> {
2390 rust_key_paths::lock::LockKp::new(
2391 rust_key_paths::Kp::new(
2392 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2393 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2394 ),
2395 rust_key_paths::lock::ArcMutexAccess::new(),
2396 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2397 )
2398 }
2399 });
2400 }
2401 (WrapperKind::ArcRwLock, Some(inner_ty)) => {
2402 let snake_lock = format_ident!("{}_lock", snake);
2403 tokens.extend(quote! {
2404 #[inline(always)]
2405 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2406 rust_key_paths::Kp::new(
2407 |root: &#name| match root {
2408 #name::#v_ident(inner) => Some(inner),
2409 _ => None,
2410 },
2411 |root: &mut #name| match root {
2412 #name::#v_ident(inner) => Some(inner),
2413 _ => None,
2414 },
2415 )
2416 }
2417 pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, #field_ty, #inner_ty> {
2418 rust_key_paths::lock::LockKp::new(
2419 rust_key_paths::Kp::new(
2420 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2421 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2422 ),
2423 rust_key_paths::lock::ParkingLotRwLockAccess::new(),
2424 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2425 )
2426 }
2427 });
2428 }
2429 (WrapperKind::ArcMutex, Some(inner_ty)) => {
2430 let snake_lock = format_ident!("{}_lock", snake);
2431 tokens.extend(quote! {
2432 #[inline(always)]
2433 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2434 rust_key_paths::Kp::new(
2435 |root: &#name| match root {
2436 #name::#v_ident(inner) => Some(inner),
2437 _ => None,
2438 },
2439 |root: &mut #name| match root {
2440 #name::#v_ident(inner) => Some(inner),
2441 _ => None,
2442 },
2443 )
2444 }
2445 pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, #field_ty, #inner_ty> {
2446 rust_key_paths::lock::LockKp::new(
2447 rust_key_paths::Kp::new(
2448 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2449 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2450 ),
2451 rust_key_paths::lock::ParkingLotMutexAccess::new(),
2452 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2453 )
2454 }
2455 });
2456 }
2457 (WrapperKind::TokioArcMutex, Some(inner_ty)) => {
2458 let snake_async = format_ident!("{}_async", snake);
2459 tokens.extend(quote! {
2460 #[inline(always)]
2461 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2462 rust_key_paths::Kp::new(
2463 |root: &#name| match root {
2464 #name::#v_ident(inner) => Some(inner),
2465 _ => None,
2466 },
2467 |root: &mut #name| match root {
2468 #name::#v_ident(inner) => Some(inner),
2469 _ => None,
2470 },
2471 )
2472 }
2473 pub fn #snake_async() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, #field_ty, #inner_ty> {
2474 rust_key_paths::async_lock::AsyncLockKp::new(
2475 rust_key_paths::Kp::new(
2476 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2477 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2478 ),
2479 rust_key_paths::async_lock::TokioMutexAccess::new(),
2480 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2481 )
2482 }
2483 });
2484 }
2485 (WrapperKind::TokioArcRwLock, Some(inner_ty)) => {
2486 let snake_async = format_ident!("{}_async", snake);
2487 tokens.extend(quote! {
2488 #[inline(always)]
2489 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2490 rust_key_paths::Kp::new(
2491 |root: &#name| match root {
2492 #name::#v_ident(inner) => Some(inner),
2493 _ => None,
2494 },
2495 |root: &mut #name| match root {
2496 #name::#v_ident(inner) => Some(inner),
2497 _ => None,
2498 },
2499 )
2500 }
2501 pub fn #snake_async() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, #field_ty, #inner_ty> {
2502 rust_key_paths::async_lock::AsyncLockKp::new(
2503 rust_key_paths::Kp::new(
2504 |root: &#name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2505 |root: &mut #name| match root { #name::#v_ident(inner) => Some(inner), _ => None },
2506 ),
2507 rust_key_paths::async_lock::TokioRwLockAccess::new(),
2508 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2509 )
2510 }
2511 });
2512 }
2513 (WrapperKind::OptionTokioArcMutex, Some(inner_ty)) => {
2514 let snake_async = format_ident!("{}_async", snake);
2515 tokens.extend(quote! {
2516 #[inline(always)]
2517 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2518 rust_key_paths::Kp::new(
2519 |root: &#name| match root {
2520 #name::#v_ident(inner) => Some(inner),
2521 _ => None,
2522 },
2523 |root: &mut #name| match root {
2524 #name::#v_ident(inner) => Some(inner),
2525 _ => None,
2526 },
2527 )
2528 }
2529 pub fn #snake_async() -> rust_key_paths::async_lock::AsyncLockKpMutexFor<#name, std::sync::Arc<tokio::sync::Mutex<#inner_ty>>, #inner_ty> {
2530 rust_key_paths::async_lock::AsyncLockKp::new(
2531 rust_key_paths::Kp::new(
2532 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2533 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2534 ),
2535 rust_key_paths::async_lock::TokioMutexAccess::new(),
2536 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2537 )
2538 }
2539 });
2540 }
2541 (WrapperKind::OptionTokioArcRwLock, Some(inner_ty)) => {
2542 let snake_async = format_ident!("{}_async", snake);
2543 tokens.extend(quote! {
2544 #[inline(always)]
2545 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2546 rust_key_paths::Kp::new(
2547 |root: &#name| match root {
2548 #name::#v_ident(inner) => Some(inner),
2549 _ => None,
2550 },
2551 |root: &mut #name| match root {
2552 #name::#v_ident(inner) => Some(inner),
2553 _ => None,
2554 },
2555 )
2556 }
2557 pub fn #snake_async() -> rust_key_paths::async_lock::AsyncLockKpRwLockFor<#name, std::sync::Arc<tokio::sync::RwLock<#inner_ty>>, #inner_ty> {
2558 rust_key_paths::async_lock::AsyncLockKp::new(
2559 rust_key_paths::Kp::new(
2560 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2561 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2562 ),
2563 rust_key_paths::async_lock::TokioRwLockAccess::new(),
2564 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2565 )
2566 }
2567 });
2568 }
2569 (WrapperKind::OptionStdArcMutex, Some(inner_ty)) => {
2570 let snake_unlocked = format_ident!("{}_unlocked", snake);
2571 let snake_lock = format_ident!("{}_lock", snake);
2572 tokens.extend(quote! {
2573 #[inline(always)]
2574 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2575 rust_key_paths::Kp::new(
2576 |root: &#name| match root {
2577 #name::#v_ident(inner) => Some(inner),
2578 _ => None,
2579 },
2580 |root: &mut #name| match root {
2581 #name::#v_ident(inner) => Some(inner),
2582 _ => None,
2583 },
2584 )
2585 }
2586 pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::Mutex<#inner_ty>>> {
2587 rust_key_paths::Kp::new(
2588 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2589 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2590 )
2591 }
2592 pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcMutexFor<#name, std::sync::Arc<std::sync::Mutex<#inner_ty>>, #inner_ty> {
2593 rust_key_paths::lock::LockKp::new(
2594 rust_key_paths::Kp::new(
2595 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2596 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2597 ),
2598 rust_key_paths::lock::ArcMutexAccess::new(),
2599 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2600 )
2601 }
2602 });
2603 }
2604 (WrapperKind::OptionArcMutex, Some(inner_ty)) => {
2605 let snake_unlocked = format_ident!("{}_unlocked", snake);
2606 let snake_lock = format_ident!("{}_lock", snake);
2607 tokens.extend(quote! {
2608 #[inline(always)]
2609 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2610 rust_key_paths::Kp::new(
2611 |root: &#name| match root {
2612 #name::#v_ident(inner) => Some(inner),
2613 _ => None,
2614 },
2615 |root: &mut #name| match root {
2616 #name::#v_ident(inner) => Some(inner),
2617 _ => None,
2618 },
2619 )
2620 }
2621 pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>> {
2622 rust_key_paths::Kp::new(
2623 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2624 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2625 )
2626 }
2627 pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotMutexFor<#name, std::sync::Arc<parking_lot::Mutex<#inner_ty>>, #inner_ty> {
2628 rust_key_paths::lock::LockKp::new(
2629 rust_key_paths::Kp::new(
2630 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2631 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2632 ),
2633 rust_key_paths::lock::ParkingLotMutexAccess::new(),
2634 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2635 )
2636 }
2637 });
2638 }
2639 (WrapperKind::OptionStdArcRwLock, Some(inner_ty)) => {
2640 let snake_unlocked = format_ident!("{}_unlocked", snake);
2641 let snake_lock = format_ident!("{}_lock", snake);
2642 tokens.extend(quote! {
2643 #[inline(always)]
2644 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2645 rust_key_paths::Kp::new(
2646 |root: &#name| match root {
2647 #name::#v_ident(inner) => Some(inner),
2648 _ => None,
2649 },
2650 |root: &mut #name| match root {
2651 #name::#v_ident(inner) => Some(inner),
2652 _ => None,
2653 },
2654 )
2655 }
2656 pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<std::sync::RwLock<#inner_ty>>> {
2657 rust_key_paths::Kp::new(
2658 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2659 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2660 )
2661 }
2662 pub fn #snake_lock() -> rust_key_paths::lock::LockKpArcRwLockFor<#name, std::sync::Arc<std::sync::RwLock<#inner_ty>>, #inner_ty> {
2663 rust_key_paths::lock::LockKp::new(
2664 rust_key_paths::Kp::new(
2665 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2666 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2667 ),
2668 rust_key_paths::lock::ArcRwLockAccess::new(),
2669 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2670 )
2671 }
2672 });
2673 }
2674 (WrapperKind::OptionArcRwLock, Some(inner_ty)) => {
2675 let snake_unlocked = format_ident!("{}_unlocked", snake);
2676 let snake_lock = format_ident!("{}_lock", snake);
2677 tokens.extend(quote! {
2678 #[inline(always)]
2679 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2680 rust_key_paths::Kp::new(
2681 |root: &#name| match root {
2682 #name::#v_ident(inner) => Some(inner),
2683 _ => None,
2684 },
2685 |root: &mut #name| match root {
2686 #name::#v_ident(inner) => Some(inner),
2687 _ => None,
2688 },
2689 )
2690 }
2691 pub fn #snake_unlocked() -> rust_key_paths::KpType<'static, #name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>> {
2692 rust_key_paths::Kp::new(
2693 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2694 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2695 )
2696 }
2697 pub fn #snake_lock() -> rust_key_paths::lock::LockKpParkingLotRwLockFor<#name, std::sync::Arc<parking_lot::RwLock<#inner_ty>>, #inner_ty> {
2698 rust_key_paths::lock::LockKp::new(
2699 rust_key_paths::Kp::new(
2700 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2701 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2702 ),
2703 rust_key_paths::lock::ParkingLotRwLockAccess::new(),
2704 rust_key_paths::Kp::new(|v: &#inner_ty| Some(v), |v: &mut #inner_ty| Some(v)),
2705 )
2706 }
2707 });
2708 }
2709 (WrapperKind::StdMutex, Some(_inner_ty))
2710 | (WrapperKind::Mutex, Some(_inner_ty))
2711 | (WrapperKind::StdRwLock, Some(_inner_ty))
2712 | (WrapperKind::RwLock, Some(_inner_ty)) => {
2713 tokens.extend(quote! {
2714 #[inline(always)]
2715 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2716 rust_key_paths::Kp::new(
2717 |root: &#name| match root {
2718 #name::#v_ident(inner) => Some(inner),
2719 _ => None,
2720 },
2721 |root: &mut #name| match root {
2722 #name::#v_ident(inner) => Some(inner),
2723 _ => None,
2724 },
2725 )
2726 }
2727 });
2728 }
2729 (WrapperKind::Tagged, Some(inner_ty)) => {
2730 tokens.extend(quote! {
2731 #[inline(always)]
2732 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2733 rust_key_paths::Kp::new(
2734 |root: &#name| match root {
2735 #name::#v_ident(inner) => Some(std::ops::Deref::deref(inner)),
2736 _ => None,
2737 },
2738 |root: &mut #name| match root {
2739 #name::#v_ident(inner) => Some(std::ops::DerefMut::deref_mut(inner)),
2740 _ => None,
2741 },
2742 )
2743 }
2744 });
2745 }
2746 (WrapperKind::Atomic, None | Some(_)) => {
2747 tokens.extend(quote! {
2748 #[inline(always)]
2749 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2750 rust_key_paths::Kp::new(
2751 |root: &#name| match root {
2752 #name::#v_ident(inner) => Some(inner),
2753 _ => None,
2754 },
2755 |root: &mut #name| match root {
2756 #name::#v_ident(inner) => Some(inner),
2757 _ => None,
2758 },
2759 )
2760 }
2761 });
2762 }
2763 (WrapperKind::OptionAtomic, Some(inner_ty)) => {
2764 tokens.extend(quote! {
2765 #[inline(always)]
2766 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2767 rust_key_paths::Kp::new(
2768 |root: &#name| match root { #name::#v_ident(inner) => inner.as_ref(), _ => None },
2769 |root: &mut #name| match root { #name::#v_ident(inner) => inner.as_mut(), _ => None },
2770 )
2771 }
2772 });
2773 }
2774 (WrapperKind::Reference, Some(_inner_ty)) => {
2775 tokens.extend(quote! {
2776 #[inline(always)]
2777 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2778 rust_key_paths::Kp::new(
2779 |root: &#name| match root {
2780 #name::#v_ident(inner) => Some(inner),
2781 _ => None,
2782 },
2783 |_root: &mut #name| None,
2784 )
2785 }
2786 });
2787 }
2788 (WrapperKind::Weak, Some(_inner_ty)) => {
2789 tokens.extend(quote! {
2790 #[inline(always)]
2791 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2792 rust_key_paths::Kp::new(
2793 |root: &#name| match root {
2794 #name::#v_ident(inner) => Some(inner),
2795 _ => None,
2796 },
2797 |_root: &mut #name| None,
2798 )
2799 }
2800 });
2801 }
2802 (WrapperKind::Cow, Some(inner_ty)) => {
2803 tokens.extend(quote! {
2804 #[inline(always)]
2805 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2806 rust_key_paths::Kp::new(
2807 |root: &#name| match root {
2808 #name::#v_ident(inner) => Some(inner.as_ref()),
2809 _ => None,
2810 },
2811 |root: &mut #name| match root {
2812 #name::#v_ident(inner) => Some(inner.to_mut()),
2813 _ => None,
2814 },
2815 )
2816 }
2817 });
2818 }
2819 (WrapperKind::OptionCow, Some(inner_ty)) => {
2820 tokens.extend(quote! {
2821 #[inline(always)]
2822 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2823 rust_key_paths::Kp::new(
2824 |root: &#name| match root {
2825 #name::#v_ident(inner) => inner.as_ref().map(|c| c.as_ref()),
2826 _ => None,
2827 },
2828 |root: &mut #name| match root {
2829 #name::#v_ident(inner) => inner.as_mut().map(|c| c.to_mut()),
2830 _ => None,
2831 },
2832 )
2833 }
2834 });
2835 }
2836 (WrapperKind::OptionTagged, Some(inner_ty)) => {
2837 tokens.extend(quote! {
2838 #[inline(always)]
2839 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2840 rust_key_paths::Kp::new(
2841 |root: &#name| match root {
2842 #name::#v_ident(inner) => inner.as_ref().map(|t| std::ops::Deref::deref(t)),
2843 _ => None,
2844 },
2845 |root: &mut #name| match root {
2846 #name::#v_ident(inner) => inner.as_mut().map(|t| std::ops::DerefMut::deref_mut(t)),
2847 _ => None,
2848 },
2849 )
2850 }
2851 });
2852 }
2853 (WrapperKind::OptionReference, Some(inner_ty)) => {
2854 tokens.extend(quote! {
2855 #[inline(always)]
2856 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #inner_ty> {
2857 rust_key_paths::Kp::new(
2858 |root: &#name| match root {
2859 #name::#v_ident(inner) => inner.as_ref(),
2860 _ => None,
2861 },
2862 |_root: &mut #name| None,
2863 )
2864 }
2865 });
2866 }
2867 (WrapperKind::None, None) => {
2868 // Basic type
2869 tokens.extend(quote! {
2870 #[inline(always)]
2871 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2872 rust_key_paths::Kp::new(
2873 |root: &#name| match root {
2874 #name::#v_ident(inner) => Some(inner),
2875 _ => None,
2876 },
2877 |root: &mut #name| match root {
2878 #name::#v_ident(inner) => Some(inner),
2879 _ => None,
2880 },
2881 )
2882 }
2883 });
2884 }
2885 _ => {
2886 // Other wrapper types - return keypath to field
2887 tokens.extend(quote! {
2888 #[inline(always)]
2889 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #field_ty> {
2890 rust_key_paths::Kp::new(
2891 |root: &#name| match root {
2892 #name::#v_ident(inner) => Some(inner),
2893 _ => None,
2894 },
2895 |root: &mut #name| match root {
2896 #name::#v_ident(inner) => Some(inner),
2897 _ => None,
2898 },
2899 )
2900 }
2901 });
2902 }
2903 }
2904 } else {
2905 // Multi-field tuple variant - return keypath to variant itself
2906 tokens.extend(quote! {
2907 #[inline(always)]
2908 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
2909 rust_key_paths::Kp::new(
2910 |root: &#name| match root {
2911 #name::#v_ident(..) => Some(root),
2912 _ => None,
2913 },
2914 |root: &mut #name| match root {
2915 #name::#v_ident(..) => Some(root),
2916 _ => None,
2917 },
2918 )
2919 }
2920 });
2921 }
2922 }
2923 Fields::Named(_) => {
2924 // Named field variant - return keypath to variant itself
2925 tokens.extend(quote! {
2926 pub fn #snake() -> rust_key_paths::KpType<'static, #name, #name> {
2927 rust_key_paths::Kp::new(
2928 |root: &#name| match root {
2929 #name::#v_ident { .. } => Some(root),
2930 _ => None,
2931 },
2932 |root: &mut #name| match root {
2933 #name::#v_ident { .. } => Some(root),
2934 _ => None,
2935 },
2936 )
2937 }
2938 });
2939 }
2940 }
2941 }
2942
2943 tokens
2944 }
2945 Data::Union(_) => {
2946 return syn::Error::new(input_span, "Kp derive does not support unions")
2947 .to_compile_error()
2948 .into();
2949 }
2950 };
2951
2952 let expanded = quote! {
2953 impl #name {
2954 #methods
2955 }
2956 };
2957
2958 TokenStream::from(expanded)
2959}
2960
2961/// Derive macro that generates `partial_kps() -> Vec<PKp<Self>>` returning all field/variant keypaths.
2962/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
2963///
2964/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
2965/// (using the same methods Kp generates, e.g. `some_variant()`).
2966///
2967/// # Example
2968/// ```
2969/// use key_paths_derive::{Kp, Pkp};
2970/// use rust_key_paths::PKp;
2971///
2972/// #[derive(Kp, Pkp)]
2973/// struct Person {
2974/// name: String,
2975/// age: i32,
2976/// }
2977///
2978/// let kps = Person::partial_kps();
2979/// assert_eq!(kps.len(), 2);
2980/// ```
2981#[proc_macro_derive(Pkp)]
2982pub fn derive_partial_keypaths(input: TokenStream) -> TokenStream {
2983 let input = parse_macro_input!(input as DeriveInput);
2984 let name = &input.ident;
2985
2986 let kp_calls = match &input.data {
2987 Data::Struct(data_struct) => match &data_struct.fields {
2988 Fields::Named(fields_named) => {
2989 let calls: Vec<_> = fields_named
2990 .named
2991 .iter()
2992 .filter_map(|f| f.ident.as_ref())
2993 .map(|field_ident| {
2994 quote! { rust_key_paths::PKp::new(Self::#field_ident()) }
2995 })
2996 .collect();
2997 quote! { #(#calls),* }
2998 }
2999 Fields::Unnamed(unnamed) => {
3000 let calls: Vec<_> = (0..unnamed.unnamed.len())
3001 .map(|idx| {
3002 let kp_fn = format_ident!("f{}", idx);
3003 quote! { rust_key_paths::PKp::new(Self::#kp_fn()) }
3004 })
3005 .collect();
3006 quote! { #(#calls),* }
3007 }
3008 Fields::Unit => quote! {},
3009 },
3010 Data::Enum(data_enum) => {
3011 let calls: Vec<_> = data_enum
3012 .variants
3013 .iter()
3014 .map(|variant| {
3015 let v_ident = &variant.ident;
3016 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
3017 quote! { rust_key_paths::PKp::new(Self::#snake()) }
3018 })
3019 .collect();
3020 quote! { #(#calls),* }
3021 }
3022 Data::Union(_) => {
3023 return syn::Error::new(
3024 input.ident.span(),
3025 "Pkp derive does not support unions",
3026 )
3027 .to_compile_error()
3028 .into();
3029 }
3030 };
3031
3032 let expanded = quote! {
3033 impl #name {
3034 /// Returns a vec of all field keypaths as partial keypaths (type-erased).
3035 #[inline(always)]
3036 pub fn partial_kps() -> Vec<rust_key_paths::PKp<#name>> {
3037 vec![#kp_calls]
3038 }
3039 }
3040 };
3041
3042 TokenStream::from(expanded)
3043}
3044
3045/// Derive macro that generates `any_kps() -> Vec<AKp>` returning all field/variant keypaths as any keypaths.
3046/// **Requires `#[derive(Kp)]`** so the keypath accessor methods exist.
3047/// AKp type-erases both Root and Value, enabling heterogeneous collections of keypaths.
3048///
3049/// For structs: returns keypaths for each field. For enums: returns keypaths for each variant
3050/// (using the same methods Kp generates, e.g. `some_variant()`).
3051///
3052/// # Example
3053/// ```
3054/// use key_paths_derive::{Kp, Akp};
3055/// use rust_key_paths::AKp;
3056///
3057/// #[derive(Kp, Akp)]
3058/// struct Person {
3059/// name: String,
3060/// age: i32,
3061/// }
3062///
3063/// let kps = Person::any_kps();
3064/// assert_eq!(kps.len(), 2);
3065/// let person = Person { name: "Alice".into(), age: 30 };
3066/// let name: Option<&String> = kps[0].get(&person as &dyn std::any::Any).and_then(|v| v.downcast_ref());
3067/// assert_eq!(name, Some(&"Alice".to_string()));
3068/// ```
3069#[proc_macro_derive(Akp)]
3070pub fn derive_any_keypaths(input: TokenStream) -> TokenStream {
3071 let input = parse_macro_input!(input as DeriveInput);
3072 let name = &input.ident;
3073
3074 let kp_calls = match &input.data {
3075 Data::Struct(data_struct) => match &data_struct.fields {
3076 Fields::Named(fields_named) => {
3077 let calls: Vec<_> = fields_named
3078 .named
3079 .iter()
3080 .filter_map(|f| f.ident.as_ref())
3081 .map(|field_ident| {
3082 quote! { rust_key_paths::AKp::new(Self::#field_ident()) }
3083 })
3084 .collect();
3085 quote! { #(#calls),* }
3086 }
3087 Fields::Unnamed(unnamed) => {
3088 let calls: Vec<_> = (0..unnamed.unnamed.len())
3089 .map(|idx| {
3090 let kp_fn = format_ident!("f{}", idx);
3091 quote! { rust_key_paths::AKp::new(Self::#kp_fn()) }
3092 })
3093 .collect();
3094 quote! { #(#calls),* }
3095 }
3096 Fields::Unit => quote! {},
3097 },
3098 Data::Enum(data_enum) => {
3099 let calls: Vec<_> = data_enum
3100 .variants
3101 .iter()
3102 .map(|variant| {
3103 let v_ident = &variant.ident;
3104 let snake = format_ident!("{}", to_snake_case(&v_ident.to_string()));
3105 quote! { rust_key_paths::AKp::new(Self::#snake()) }
3106 })
3107 .collect();
3108 quote! { #(#calls),* }
3109 }
3110 Data::Union(_) => {
3111 return syn::Error::new(
3112 input.ident.span(),
3113 "Akp derive does not support unions",
3114 )
3115 .to_compile_error()
3116 .into();
3117 }
3118 };
3119
3120 let expanded = quote! {
3121 impl #name {
3122 /// Returns a vec of all field keypaths as any keypaths (fully type-erased).
3123 #[inline(always)]
3124 pub fn any_kps() -> Vec<rust_key_paths::AKp> {
3125 vec![#kp_calls]
3126 }
3127 }
3128 };
3129
3130 TokenStream::from(expanded)
3131}