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