key_paths_core/
lib.rs

1use std::rc::Rc;
2use std::sync::{Arc, Mutex, RwLock};
3use std::cell::RefCell;
4
5/// Trait for no-clone callback-based access to container types
6/// Provides methods to execute closures with references to values inside containers
7/// without requiring cloning of the values
8pub trait WithContainer<Root, Value> {
9    /// Execute a closure with a reference to the value inside an Arc
10    /// This avoids cloning by working with references directly
11    fn with_arc<F, R>(self, arc: &Arc<Root>, f: F) -> R
12    where
13        F: FnOnce(&Value) -> R;
14
15    /// Execute a closure with a reference to the value inside a Box
16    /// This avoids cloning by working with references directly
17    fn with_box<F, R>(self, boxed: &Box<Root>, f: F) -> R
18    where
19        F: FnOnce(&Value) -> R;
20
21    /// Execute a closure with a mutable reference to the value inside a Box
22    /// This avoids cloning by working with references directly
23    fn with_box_mut<F, R>(self, boxed: &mut Box<Root>, f: F) -> R
24    where
25        F: FnOnce(&mut Value) -> R;
26
27    /// Execute a closure with a reference to the value inside an Rc
28    /// This avoids cloning by working with references directly
29    fn with_rc<F, R>(self, rc: &Rc<Root>, f: F) -> R
30    where
31        F: FnOnce(&Value) -> R;
32
33    /// Execute a closure with a reference to the value inside a Result
34    /// This avoids cloning by working with references directly
35    fn with_result<F, R, E>(self, result: &Result<Root, E>, f: F) -> Option<R>
36    where
37        F: FnOnce(&Value) -> R;
38
39    /// Execute a closure with a mutable reference to the value inside a Result
40    /// This avoids cloning by working with references directly
41    fn with_result_mut<F, R, E>(self, result: &mut Result<Root, E>, f: F) -> Option<R>
42    where
43        F: FnOnce(&mut Value) -> R;
44
45    /// Execute a closure with a reference to the value inside an Option
46    /// This avoids cloning by working with references directly
47    fn with_option<F, R>(self, option: &Option<Root>, f: F) -> Option<R>
48    where
49        F: FnOnce(&Value) -> R;
50
51    /// Execute a closure with a mutable reference to the value inside an Option
52    /// This avoids cloning by working with references directly
53    fn with_option_mut<F, R>(self, option: &mut Option<Root>, f: F) -> Option<R>
54    where
55        F: FnOnce(&mut Value) -> R;
56
57    /// Execute a closure with a reference to the value inside a RefCell
58    /// This avoids cloning by working with references directly
59    fn with_refcell<F, R>(self, refcell: &RefCell<Root>, f: F) -> Option<R>
60    where
61        F: FnOnce(&Value) -> R;
62
63    /// Execute a closure with a mutable reference to the value inside a RefCell
64    /// This avoids cloning by working with references directly
65    fn with_refcell_mut<F, R>(self, refcell: &RefCell<Root>, f: F) -> Option<R>
66    where
67        F: FnOnce(&mut Value) -> R;
68
69    /// Execute a closure with a reference to the value inside a Mutex
70    /// This avoids cloning by working with references while the guard is alive
71    fn with_mutex<F, R>(self, mutex: &Mutex<Root>, f: F) -> Option<R>
72    where
73        F: FnOnce(&Value) -> R;
74
75    /// Execute a closure with a mutable reference to the value inside a Mutex
76    /// This avoids cloning by working with references while the guard is alive
77    fn with_mutex_mut<F, R>(self, mutex: &mut Mutex<Root>, f: F) -> Option<R>
78    where
79        F: FnOnce(&mut Value) -> R;
80
81    /// Execute a closure with a reference to the value inside an RwLock
82    /// This avoids cloning by working with references while the guard is alive
83    fn with_rwlock<F, R>(self, rwlock: &RwLock<Root>, f: F) -> Option<R>
84    where
85        F: FnOnce(&Value) -> R;
86
87    /// Execute a closure with a mutable reference to the value inside an RwLock
88    /// This avoids cloning by working with references while the guard is alive
89    fn with_rwlock_mut<F, R>(self, rwlock: &mut RwLock<Root>, f: F) -> Option<R>
90    where
91        F: FnOnce(&mut Value) -> R;
92}
93
94#[derive(Clone)]
95/// Go to examples section to see the implementations
96///
97pub enum KeyPaths<Root, Value> {
98    Readable(Rc<dyn for<'a> Fn(&'a Root) -> &'a Value>),
99    ReadableEnum {
100        extract: Rc<dyn for<'a> Fn(&'a Root) -> Option<&'a Value>>,
101        embed: Rc<dyn Fn(Value) -> Root>,
102    },
103    FailableReadable(Rc<dyn for<'a> Fn(&'a Root) -> Option<&'a Value>>),
104
105    Writable(Rc<dyn for<'a> Fn(&'a mut Root) -> &'a mut Value>),
106    FailableWritable(Rc<dyn for<'a> Fn(&'a mut Root) -> Option<&'a mut Value>>),
107    WritableEnum {
108        extract: Rc<dyn for<'a> Fn(&'a Root) -> Option<&'a Value>>,
109        extract_mut: Rc<dyn for<'a> Fn(&'a mut Root) -> Option<&'a mut Value>>,
110        embed: Rc<dyn Fn(Value) -> Root>,
111    },
112
113
114
115    // New Owned KeyPath types (value semantics)
116    Owned(Rc<dyn Fn(Root) -> Value>),
117    FailableOwned(Rc<dyn Fn(Root) -> Option<Value>>),    
118}
119
120impl<Root, Value> KeyPaths<Root, Value> {
121    #[inline]
122    pub fn readable(get: impl for<'a> Fn(&'a Root) -> &'a Value + 'static) -> Self {
123        Self::Readable(Rc::new(get))
124    }
125
126    #[inline]
127    pub fn writable(get_mut: impl for<'a> Fn(&'a mut Root) -> &'a mut Value + 'static) -> Self {
128        Self::Writable(Rc::new(get_mut))
129    }
130
131    #[inline]
132    pub fn failable_readable(
133        get: impl for<'a> Fn(&'a Root) -> Option<&'a Value> + 'static,
134    ) -> Self {
135        Self::FailableReadable(Rc::new(get))
136    }
137
138    #[inline]
139    pub fn failable_writable(
140        get_mut: impl for<'a> Fn(&'a mut Root) -> Option<&'a mut Value> + 'static,
141    ) -> Self {
142        Self::FailableWritable(Rc::new(get_mut))
143    }
144
145    #[inline]
146    pub fn readable_enum(
147        embed: impl Fn(Value) -> Root + 'static,
148        extract: impl for<'a> Fn(&'a Root) -> Option<&'a Value> + 'static,
149    ) -> Self {
150        Self::ReadableEnum {
151            extract: Rc::new(extract),
152            embed: Rc::new(embed),
153        }
154    }
155
156    #[inline]
157    pub fn writable_enum(
158        embed: impl Fn(Value) -> Root + 'static,
159        extract: impl for<'a> Fn(&'a Root) -> Option<&'a Value> + 'static,
160        extract_mut: impl for<'a> Fn(&'a mut Root) -> Option<&'a mut Value> + 'static,
161    ) -> Self {
162        Self::WritableEnum {
163            extract: Rc::new(extract),
164            embed: Rc::new(embed),
165            extract_mut: Rc::new(extract_mut),
166        }
167    }
168
169
170    // New Owned KeyPath constructors
171    #[inline]
172    pub fn owned(get: impl Fn(Root) -> Value + 'static) -> Self {
173        Self::Owned(Rc::new(get))
174    }
175
176    #[inline]
177    pub fn failable_owned(get: impl Fn(Root) -> Option<Value> + 'static) -> Self {
178        Self::FailableOwned(Rc::new(get))
179    }
180
181    #[inline]
182    pub fn owned_writable(get: impl Fn(Root) -> Value + 'static) -> Self {
183        Self::Owned(Rc::new(get))
184    }
185    
186    #[inline]
187    pub fn failable_owned_writable(get: impl Fn(Root) -> Option<Value> + 'static) -> Self {
188        Self::FailableOwned(Rc::new(get))
189    }
190}
191
192impl<Root, Value> KeyPaths<Root, Value> {
193    /// Get an immutable reference if possible
194    #[inline]
195    pub fn get<'a>(&'a self, root: &'a Root) -> Option<&'a Value> {
196        match self {
197            KeyPaths::Readable(f) => Some(f(root)),
198            KeyPaths::Writable(_) => None, // Writable requires mut
199            KeyPaths::FailableReadable(f) => f(root),
200            KeyPaths::FailableWritable(_) => None, // needs mut
201            KeyPaths::ReadableEnum { extract, .. } => extract(root),
202            KeyPaths::WritableEnum { extract, .. } => extract(root),
203            // New owned keypath types (don't work with references)
204            KeyPaths::Owned(_) => None, // Owned keypaths don't work with references
205            KeyPaths::FailableOwned(_) => None, // Owned keypaths don't work with references
206        }
207    }
208
209    /// Get an immutable reference when Root is itself a reference (&T)
210    /// This enables using keypaths with collections of references like Vec<&T>
211    #[inline]
212    pub fn get_ref<'a, 'b>(&'a self, root: &'b &Root) -> Option<&'b Value> 
213    where
214        'a: 'b,
215    {
216        self.get(*root)
217    }
218
219    /// Get a mutable reference if possible
220    #[inline]
221    pub fn get_mut<'a>(&'a self, root: &'a mut Root) -> Option<&'a mut Value> {
222        match self {
223            KeyPaths::Readable(_) => None, // immutable only
224            KeyPaths::Writable(f) => Some(f(root)),
225            KeyPaths::FailableReadable(_) => None, // immutable only
226            KeyPaths::FailableWritable(f) => f(root),
227            KeyPaths::ReadableEnum { .. } => None, // immutable only
228            KeyPaths::WritableEnum { extract_mut, .. } => extract_mut(root),
229            // New owned keypath types (don't work with references)
230            KeyPaths::Owned(_) => None, // Owned keypaths don't work with references
231            KeyPaths::FailableOwned(_) => None, // Owned keypaths don't work with references
232        }
233    }
234
235    /// Get a mutable reference when Root is itself a mutable reference (&mut T)
236    /// This enables using writable keypaths with collections of mutable references
237    #[inline]
238    pub fn get_mut_ref<'a, 'b>(&'a self, root: &'b mut &mut Root) -> Option<&'b mut Value> 
239    where
240        'a: 'b,
241    {
242        self.get_mut(*root)
243    }
244
245    // ===== Smart Pointer / Container Adapter Methods =====
246    // These methods create new keypaths that work with wrapped types
247    // Enables using KeyPaths<T, V> with Vec<Arc<T>>, Vec<Box<T>>, etc.
248
249    /// Adapt this keypath to work with Arc<Root>
250    /// Enables using KeyPaths<T, V> with collections like Vec<Arc<T>>
251    #[inline]
252    pub fn for_arc(self) -> KeyPaths<Arc<Root>, Value>
253    where
254        Root: 'static,
255        Value: 'static,
256    {
257        match self {
258            KeyPaths::Readable(f) => KeyPaths::Readable(Rc::new(move |root: &Arc<Root>| {
259                f(&**root)
260            })),
261            KeyPaths::Writable(_) => {
262                // Writable doesn't work with Arc (no mutable access)
263                panic!("Cannot create writable keypath for Arc (Arc is immutable)")
264            }
265            KeyPaths::FailableReadable(f) => {
266                KeyPaths::FailableReadable(Rc::new(move |root: &Arc<Root>| f(&**root)))
267            }
268            KeyPaths::ReadableEnum { extract, embed } => KeyPaths::ReadableEnum {
269                extract: Rc::new(move |root: &Arc<Root>| extract(&**root)),
270                embed: Rc::new(move |value| Arc::new(embed(value))),
271            },
272            other => panic!("Unsupported keypath variant for Arc adapter: {:?}", kind_name(&other)),
273        }
274    }
275
276    /// Adapt this keypath to work with Box<Root>
277    /// Enables using KeyPaths<T, V> with collections like Vec<Box<T>>
278    #[inline]
279    pub fn for_box(self) -> KeyPaths<Box<Root>, Value>
280    where
281        Root: 'static,
282        Value: 'static,
283    {
284        match self {
285            KeyPaths::Readable(f) => KeyPaths::Readable(Rc::new(move |root: &Box<Root>| {
286                f(&**root)
287            })),
288            KeyPaths::Writable(f) => KeyPaths::Writable(Rc::new(move |root: &mut Box<Root>| {
289                f(&mut **root)
290            })),
291            KeyPaths::FailableReadable(f) => {
292                KeyPaths::FailableReadable(Rc::new(move |root: &Box<Root>| f(&**root)))
293            }
294            KeyPaths::FailableWritable(f) => {
295                KeyPaths::FailableWritable(Rc::new(move |root: &mut Box<Root>| f(&mut **root)))
296            }
297            KeyPaths::ReadableEnum { extract, embed } => KeyPaths::ReadableEnum {
298                extract: Rc::new(move |root: &Box<Root>| extract(&**root)),
299                embed: Rc::new(move |value| Box::new(embed(value))),
300            },
301            KeyPaths::WritableEnum { extract, extract_mut, embed } => KeyPaths::WritableEnum {
302                extract: Rc::new(move |root: &Box<Root>| extract(&**root)),
303                extract_mut: Rc::new(move |root: &mut Box<Root>| extract_mut(&mut **root)),
304                embed: Rc::new(move |value| Box::new(embed(value))),
305            },
306            other => panic!("Unsupported keypath variant for Box adapter: {:?}", kind_name(&other)),
307        }
308    }
309
310    /// Adapt this keypath to work with Rc<Root>
311    /// Enables using KeyPaths<T, V> with collections like Vec<Rc<T>>
312    #[inline]
313    pub fn for_rc(self) -> KeyPaths<Rc<Root>, Value>
314    where
315        Root: 'static,
316        Value: 'static,
317    {
318        match self {
319            KeyPaths::Readable(f) => KeyPaths::Readable(Rc::new(move |root: &Rc<Root>| {
320                f(&**root)
321            })),
322            KeyPaths::Writable(_) => {
323                // Writable doesn't work with Rc (no mutable access)
324                panic!("Cannot create writable keypath for Rc (Rc is immutable)")
325            }
326            KeyPaths::FailableReadable(f) => {
327                KeyPaths::FailableReadable(Rc::new(move |root: &Rc<Root>| f(&**root)))
328            }
329            KeyPaths::ReadableEnum { extract, embed } => KeyPaths::ReadableEnum {
330                extract: Rc::new(move |root: &Rc<Root>| extract(&**root)),
331                embed: Rc::new(move |value| Rc::new(embed(value))),
332            },
333            other => panic!("Unsupported keypath variant for Rc adapter: {:?}", kind_name(&other)),
334        }
335    }
336
337    /// Adapt this keypath to work with Result<Root, E>
338    /// Enables using KeyPaths<T, V> with Result types
339    /// Note: This creates a FailableReadable keypath since Result can be Err
340    #[inline]
341    pub fn for_result<E>(self) -> KeyPaths<Result<Root, E>, Value>
342    where
343        Root: 'static,
344        Value: 'static,
345        E: 'static,
346    {
347        match self {
348            KeyPaths::Readable(f) => KeyPaths::FailableReadable(Rc::new(move |root: &Result<Root, E>| {
349                root.as_ref().ok().map(|r| f(r))
350            })),
351            KeyPaths::Writable(f) => KeyPaths::FailableWritable(Rc::new(move |root: &mut Result<Root, E>| {
352                root.as_mut().ok().map(|r| f(r))
353            })),
354            KeyPaths::FailableReadable(f) => {
355                KeyPaths::FailableReadable(Rc::new(move |root: &Result<Root, E>| {
356                    root.as_ref().ok().and_then(|r| f(r))
357                }))
358            }
359            KeyPaths::FailableWritable(f) => {
360                KeyPaths::FailableWritable(Rc::new(move |root: &mut Result<Root, E>| {
361                    root.as_mut().ok().and_then(|r| f(r))
362                }))
363            }
364            KeyPaths::ReadableEnum { extract, embed } => KeyPaths::ReadableEnum {
365                extract: Rc::new(move |root: &Result<Root, E>| {
366                    root.as_ref().ok().and_then(|r| extract(r))
367                }),
368                embed: Rc::new(move |value| Ok(embed(value))),
369            },
370            KeyPaths::WritableEnum { extract, extract_mut, embed } => KeyPaths::WritableEnum {
371                extract: Rc::new(move |root: &Result<Root, E>| {
372                    root.as_ref().ok().and_then(|r| extract(r))
373                }),
374                extract_mut: Rc::new(move |root: &mut Result<Root, E>| {
375                    root.as_mut().ok().and_then(|r| extract_mut(r))
376                }),
377                embed: Rc::new(move |value| Ok(embed(value))),
378            },
379            other => panic!("Unsupported keypath variant for Result adapter: {:?}", kind_name(&other)),
380        }
381    }
382
383    /// Adapt this keypath to work with Option<Root>
384    /// Enables using KeyPaths<T, V> with Option types
385    /// Note: This creates a FailableReadable/FailableWritable keypath since Option can be None
386    #[inline]
387    pub fn for_option(self) -> KeyPaths<Option<Root>, Value>
388    where
389        Root: 'static,
390        Value: 'static,
391    {
392        match self {
393            KeyPaths::Readable(f) => KeyPaths::FailableReadable(Rc::new(move |root: &Option<Root>| {
394                root.as_ref().map(|r| f(r))
395            })),
396            KeyPaths::Writable(f) => KeyPaths::FailableWritable(Rc::new(move |root: &mut Option<Root>| {
397                root.as_mut().map(|r| f(r))
398            })),
399            KeyPaths::FailableReadable(f) => {
400                KeyPaths::FailableReadable(Rc::new(move |root: &Option<Root>| {
401                    root.as_ref().and_then(|r| f(r))
402                }))
403            }
404            KeyPaths::FailableWritable(f) => {
405                KeyPaths::FailableWritable(Rc::new(move |root: &mut Option<Root>| {
406                    root.as_mut().and_then(|r| f(r))
407                }))
408            }
409            KeyPaths::ReadableEnum { extract, embed } => KeyPaths::ReadableEnum {
410                extract: Rc::new(move |root: &Option<Root>| {
411                    root.as_ref().and_then(|r| extract(r))
412                }),
413                embed: Rc::new(move |value| Some(embed(value))),
414            },
415            KeyPaths::WritableEnum { extract, extract_mut, embed } => KeyPaths::WritableEnum {
416                extract: Rc::new(move |root: &Option<Root>| {
417                    root.as_ref().and_then(|r| extract(r))
418                }),
419                extract_mut: Rc::new(move |root: &mut Option<Root>| {
420                    root.as_mut().and_then(|r| extract_mut(r))
421                }),
422                embed: Rc::new(move |value| Some(embed(value))),
423            },
424            other => panic!("Unsupported keypath variant for Option adapter: {:?}", kind_name(&other)),
425        }
426    }
427
428    // ===== WithContainer Trait Implementation =====
429    // All with_* methods are now implemented via the WithContainer trait
430
431    pub fn embed(&self, value: Value) -> Option<Root>
432    where
433        Value: Clone,
434    {
435        match self {
436            KeyPaths::ReadableEnum { embed, .. } => Some(embed(value)),
437            _ => None,
438        }
439    }
440
441    pub fn embed_mut(&self, value: Value) -> Option<Root>
442    where
443        Value: Clone,
444    {
445        match self {
446            KeyPaths::WritableEnum { embed, .. } => Some(embed(value)),
447            _ => None,
448        }
449    }
450
451
452    // ===== Owned KeyPath Accessor Methods =====
453
454    /// Get an owned value (primary method for owned keypaths)
455    #[inline]
456    pub fn get_owned(self, root: Root) -> Value {
457        match self {
458            KeyPaths::Owned(f) => f(root),
459            _ => panic!("get_owned only works with owned keypaths"),
460        }
461    }
462
463    /// Get an owned value with failable access
464    #[inline]
465    pub fn get_failable_owned(self, root: Root) -> Option<Value> {
466        match self {
467            KeyPaths::FailableOwned(f) => f(root),
468            _ => panic!("get_failable_owned only works with failable owned keypaths"),
469        }
470    }
471
472    /// Iter over immutable references if `Value: IntoIterator`
473    pub fn iter<'a, T>(&'a self, root: &'a Root) -> Option<<&'a Value as IntoIterator>::IntoIter>
474    where
475        &'a Value: IntoIterator<Item = &'a T>,
476        T: 'a,
477    {
478        self.get(root).map(|v| v.into_iter())
479    }
480
481    /// Iter over mutable references if `&mut Value: IntoIterator`
482    pub fn iter_mut<'a, T>(
483        &'a self,
484        root: &'a mut Root,
485    ) -> Option<<&'a mut Value as IntoIterator>::IntoIter>
486    where
487        &'a mut Value: IntoIterator<Item = &'a mut T>,
488        T: 'a,
489    {
490        self.get_mut(root).map(|v| v.into_iter())
491    }
492
493    /// Consume root and iterate if `Value: IntoIterator`
494    #[inline]
495    pub fn into_iter<T>(self, root: Root) -> Option<<Value as IntoIterator>::IntoIter>
496    where
497        Value: IntoIterator<Item = T> + Clone,
498    {
499        match self {
500            KeyPaths::Readable(f) => Some(f(&root).clone().into_iter()), // requires Clone
501            KeyPaths::Writable(_) => None,
502            KeyPaths::FailableReadable(f) => f(&root).map(|v| v.clone().into_iter()),
503            KeyPaths::FailableWritable(_) => None,
504            KeyPaths::ReadableEnum { extract, .. } => extract(&root).map(|v| v.clone().into_iter()),
505            KeyPaths::WritableEnum { extract, .. } => extract(&root).map(|v| v.clone().into_iter()),
506            // New owned keypath types
507            KeyPaths::Owned(f) => Some(f(root).into_iter()),
508            KeyPaths::FailableOwned(f) => f(root).map(|v| v.into_iter()),
509        }
510    }
511}
512
513// ===== WithContainer Trait Implementation =====
514impl<Root, Value> WithContainer<Root, Value> for KeyPaths<Root, Value> {
515    /// Execute a closure with a reference to the value inside an Arc
516    /// This avoids cloning by working with references directly
517    #[inline]
518    fn with_arc<F, R>(self, arc: &Arc<Root>, f: F) -> R
519    where
520        F: FnOnce(&Value) -> R,
521    {
522        match self {
523            KeyPaths::Readable(get) => f(get(&**arc)),
524            KeyPaths::FailableReadable(get) => {
525                if let Some(value) = get(&**arc) {
526                    f(value)
527                } else {
528                    panic!("FailableReadable keypath returned None for Arc")
529                }
530            }
531            _ => panic!("with_arc only works with readable keypaths"),
532        }
533    }
534
535    /// Execute a closure with a reference to the value inside a Box
536    /// This avoids cloning by working with references directly
537    #[inline]
538    fn with_box<F, R>(self, boxed: &Box<Root>, f: F) -> R
539    where
540        F: FnOnce(&Value) -> R,
541    {
542        match self {
543            KeyPaths::Readable(get) => f(get(&**boxed)),
544            KeyPaths::FailableReadable(get) => {
545                if let Some(value) = get(&**boxed) {
546                    f(value)
547                } else {
548                    panic!("FailableReadable keypath returned None for Box")
549                }
550            }
551            _ => panic!("with_box only works with readable keypaths"),
552        }
553    }
554
555    /// Execute a closure with a mutable reference to the value inside a Box
556    /// This avoids cloning by working with references directly
557    #[inline]
558    fn with_box_mut<F, R>(self, boxed: &mut Box<Root>, f: F) -> R
559    where
560        F: FnOnce(&mut Value) -> R,
561    {
562        match self {
563            KeyPaths::Writable(get) => f(get(&mut **boxed)),
564            KeyPaths::FailableWritable(get) => {
565                if let Some(value) = get(&mut **boxed) {
566                    f(value)
567                } else {
568                    panic!("FailableWritable keypath returned None for Box")
569                }
570            }
571            _ => panic!("with_box_mut only works with writable keypaths"),
572        }
573    }
574
575    /// Execute a closure with a reference to the value inside an Rc
576    /// This avoids cloning by working with references directly
577    #[inline]
578    fn with_rc<F, R>(self, rc: &Rc<Root>, f: F) -> R
579    where
580        F: FnOnce(&Value) -> R,
581    {
582        match self {
583            KeyPaths::Readable(get) => f(get(&**rc)),
584            KeyPaths::FailableReadable(get) => {
585                if let Some(value) = get(&**rc) {
586                    f(value)
587                } else {
588                    panic!("FailableReadable keypath returned None for Rc")
589                }
590            }
591            _ => panic!("with_rc only works with readable keypaths"),
592        }
593    }
594
595    /// Execute a closure with a reference to the value inside a Result
596    /// This avoids cloning by working with references directly
597    #[inline]
598    fn with_result<F, R, E>(self, result: &Result<Root, E>, f: F) -> Option<R>
599    where
600        F: FnOnce(&Value) -> R,
601    {
602        match self {
603            KeyPaths::Readable(get) => {
604                result.as_ref().ok().map(|root| f(get(root)))
605            }
606            KeyPaths::FailableReadable(get) => {
607                result.as_ref().ok().and_then(|root| get(root).map(|v| f(v)))
608            }
609            _ => panic!("with_result only works with readable keypaths"),
610        }
611    }
612
613    /// Execute a closure with a mutable reference to the value inside a Result
614    /// This avoids cloning by working with references directly
615    #[inline]
616    fn with_result_mut<F, R, E>(self, result: &mut Result<Root, E>, f: F) -> Option<R>
617    where
618        F: FnOnce(&mut Value) -> R,
619    {
620        match self {
621            KeyPaths::Writable(get) => {
622                result.as_mut().ok().map(|root| f(get(root)))
623            }
624            KeyPaths::FailableWritable(get) => {
625                result.as_mut().ok().and_then(|root| get(root).map(|v| f(v)))
626            }
627            _ => panic!("with_result_mut only works with writable keypaths"),
628        }
629    }
630
631    /// Execute a closure with a reference to the value inside an Option
632    /// This avoids cloning by working with references directly
633    #[inline]
634    fn with_option<F, R>(self, option: &Option<Root>, f: F) -> Option<R>
635    where
636        F: FnOnce(&Value) -> R,
637    {
638        match self {
639            KeyPaths::Readable(get) => {
640                option.as_ref().map(|root| f(get(root)))
641            }
642            KeyPaths::FailableReadable(get) => {
643                option.as_ref().and_then(|root| get(root).map(|v| f(v)))
644            }
645            _ => panic!("with_option only works with readable keypaths"),
646        }
647    }
648
649    /// Execute a closure with a mutable reference to the value inside an Option
650    /// This avoids cloning by working with references directly
651    #[inline]
652    fn with_option_mut<F, R>(self, option: &mut Option<Root>, f: F) -> Option<R>
653    where
654        F: FnOnce(&mut Value) -> R,
655    {
656        match self {
657            KeyPaths::Writable(get) => {
658                option.as_mut().map(|root| f(get(root)))
659            }
660            KeyPaths::FailableWritable(get) => {
661                option.as_mut().and_then(|root| get(root).map(|v| f(v)))
662            }
663            _ => panic!("with_option_mut only works with writable keypaths"),
664        }
665    }
666
667    /// Execute a closure with a reference to the value inside a RefCell
668    /// This avoids cloning by working with references directly
669    #[inline]
670    fn with_refcell<F, R>(self, refcell: &RefCell<Root>, f: F) -> Option<R>
671    where
672        F: FnOnce(&Value) -> R,
673    {
674        match self {
675            KeyPaths::Readable(get) => {
676                refcell.try_borrow().ok().map(|borrow| f(get(&*borrow)))
677            }
678            KeyPaths::FailableReadable(get) => {
679                refcell.try_borrow().ok().and_then(|borrow| get(&*borrow).map(|v| f(v)))
680            }
681            _ => panic!("with_refcell only works with readable keypaths"),
682        }
683    }
684
685    /// Execute a closure with a mutable reference to the value inside a RefCell
686    /// This avoids cloning by working with references directly
687    #[inline]
688    fn with_refcell_mut<F, R>(self, refcell: &RefCell<Root>, f: F) -> Option<R>
689    where
690        F: FnOnce(&mut Value) -> R,
691    {
692        match self {
693            KeyPaths::Writable(get) => {
694                refcell.try_borrow_mut().ok().map(|mut borrow| f(get(&mut *borrow)))
695            }
696            KeyPaths::FailableWritable(get) => {
697                refcell.try_borrow_mut().ok().and_then(|mut borrow| get(&mut *borrow).map(|v| f(v)))
698            }
699            _ => panic!("with_refcell_mut only works with writable keypaths"),
700        }
701    }
702
703    /// Execute a closure with a reference to the value inside a Mutex
704    /// This avoids cloning by working with references while the guard is alive
705    #[inline]
706    fn with_mutex<F, R>(self, mutex: &Mutex<Root>, f: F) -> Option<R>
707    where
708        F: FnOnce(&Value) -> R,
709    {
710        match self {
711            KeyPaths::Readable(get) => {
712                mutex.try_lock().ok().map(|guard| f(get(&*guard)))
713            }
714            KeyPaths::FailableReadable(get) => {
715                mutex.try_lock().ok().and_then(|guard| get(&*guard).map(|v| f(v)))
716            }
717            _ => panic!("with_mutex only works with readable keypaths"),
718        }
719    }
720
721    /// Execute a closure with a mutable reference to the value inside a Mutex
722    /// This avoids cloning by working with references while the guard is alive
723    #[inline]
724    fn with_mutex_mut<F, R>(self, mutex: &mut Mutex<Root>, f: F) -> Option<R>
725    where
726        F: FnOnce(&mut Value) -> R,
727    {
728        match self {
729            KeyPaths::Writable(get) => {
730                mutex.try_lock().ok().map(|mut guard| f(get(&mut *guard)))
731            }
732            KeyPaths::FailableWritable(get) => {
733                mutex.try_lock().ok().and_then(|mut guard| get(&mut *guard).map(|v| f(v)))
734            }
735            _ => panic!("with_mutex_mut only works with writable keypaths"),
736        }
737    }
738
739    /// Execute a closure with a reference to the value inside an RwLock
740    /// This avoids cloning by working with references while the guard is alive
741    #[inline]
742    fn with_rwlock<F, R>(self, rwlock: &RwLock<Root>, f: F) -> Option<R>
743    where
744        F: FnOnce(&Value) -> R,
745    {
746        match self {
747            KeyPaths::Readable(get) => {
748                rwlock.try_read().ok().map(|guard| f(get(&*guard)))
749            }
750            KeyPaths::FailableReadable(get) => {
751                rwlock.try_read().ok().and_then(|guard| get(&*guard).map(|v| f(v)))
752            }
753            _ => panic!("with_rwlock only works with readable keypaths"),
754        }
755    }
756
757    /// Execute a closure with a mutable reference to the value inside an RwLock
758    /// This avoids cloning by working with references while the guard is alive
759    #[inline]
760    fn with_rwlock_mut<F, R>(self, rwlock: &mut RwLock<Root>, f: F) -> Option<R>
761    where
762        F: FnOnce(&mut Value) -> R,
763    {
764        match self {
765            KeyPaths::Writable(get) => {
766                rwlock.try_write().ok().map(|mut guard| f(get(&mut *guard)))
767            }
768            KeyPaths::FailableWritable(get) => {
769                rwlock.try_write().ok().and_then(|mut guard| get(&mut *guard).map(|v| f(v)))
770            }
771            _ => panic!("with_rwlock_mut only works with writable keypaths"),
772        }
773    }
774}
775
776impl<Root, Mid> KeyPaths<Root, Mid>
777where
778    Root: 'static,
779    Mid: 'static,
780{
781    /// Alias for `compose` for ergonomic chaining.
782    #[inline]
783    pub fn then<Value>(self, mid: KeyPaths<Mid, Value>) -> KeyPaths<Root, Value>
784    where
785        Value: 'static,
786    {
787        self.compose(mid)
788    }
789
790    pub fn compose<Value>(self, mid: KeyPaths<Mid, Value>) -> KeyPaths<Root, Value>
791    where
792        Value: 'static,
793    {
794        use KeyPaths::*;
795
796        match (self, mid) {
797            (Readable(f1), Readable(f2)) => Readable(Rc::new(move |r| f2(f1(r)))),
798
799            (Writable(f1), Writable(f2)) => Writable(Rc::new(move |r| f2(f1(r)))),
800
801            (FailableReadable(f1), Readable(f2)) => {
802                FailableReadable(Rc::new(move |r| f1(r).map(|m| f2(m))))
803            }
804
805            (Readable(f1), FailableReadable(f2)) => FailableReadable(Rc::new(move |r| f2(f1(r)))),
806
807            (FailableReadable(f1), FailableReadable(f2)) => {
808                FailableReadable(Rc::new(move |r| f1(r).and_then(|m| f2(m))))
809            }
810
811            (FailableWritable(f1), Writable(f2)) => {
812                FailableWritable(Rc::new(move |r| f1(r).map(|m| f2(m))))
813            }
814
815            (Writable(f1), FailableWritable(f2)) => FailableWritable(Rc::new(move |r| f2(f1(r)))),
816
817            (FailableWritable(f1), FailableWritable(f2)) => {
818                FailableWritable(Rc::new(move |r| f1(r).and_then(|m| f2(m))))
819            }
820            (FailableReadable(f1), ReadableEnum { extract, .. }) => {
821                FailableReadable(Rc::new(move |r| f1(r).and_then(|m| extract(m))))
822            }
823            // (ReadableEnum { extract, .. }, FailableReadable(f2)) => {
824            //     FailableReadable(Rc::new(move |r| extract(r).map(|m| f2(m).unwrap())))
825            // }
826            (ReadableEnum { extract, .. }, Readable(f2)) => {
827                FailableReadable(Rc::new(move |r| extract(r).map(|m| f2(m))))
828            }
829
830            (ReadableEnum { extract, .. }, FailableReadable(f2)) => {
831                FailableReadable(Rc::new(move |r| extract(r).and_then(|m| f2(m))))
832            }
833
834            (WritableEnum { extract, .. }, Readable(f2)) => {
835                FailableReadable(Rc::new(move |r| extract(r).map(|m| f2(m))))
836            }
837
838            (WritableEnum { extract, .. }, FailableReadable(f2)) => {
839                FailableReadable(Rc::new(move |r| extract(r).and_then(|m| f2(m))))
840            }
841
842            (WritableEnum { extract_mut, .. }, Writable(f2)) => {
843                FailableWritable(Rc::new(move |r| extract_mut(r).map(|m| f2(m))))
844            }
845
846            (
847                FailableWritable(f_root_mid),
848                WritableEnum {
849                    extract_mut: exm_mid_val,
850                    ..
851                },
852            ) => {
853                FailableWritable(Rc::new(move |r: &mut Root| {
854                    // First, apply the function that operates on Root.
855                    // This will give us `Option<&mut Mid>`.
856                    let intermediate_mid_ref = f_root_mid(r);
857
858                    // Then, apply the function that operates on Mid.
859                    // This will give us `Option<&mut Value>`.
860                    intermediate_mid_ref.and_then(|intermediate_mid| exm_mid_val(intermediate_mid))
861                }))
862            }
863
864            (WritableEnum { extract_mut, .. }, FailableWritable(f2)) => {
865                FailableWritable(Rc::new(move |r| extract_mut(r).and_then(|m| f2(m))))
866            }
867
868            // New: Writable then WritableEnum => FailableWritable
869            (Writable(f1), WritableEnum { extract_mut, .. }) => {
870                FailableWritable(Rc::new(move |r: &mut Root| {
871                    let mid: &mut Mid = f1(r);
872                    extract_mut(mid)
873                }))
874            }
875
876            (
877                ReadableEnum {
878                    extract: ex1,
879                    embed: em1,
880                },
881                ReadableEnum {
882                    extract: ex2,
883                    embed: em2,
884                },
885            ) => ReadableEnum {
886                extract: Rc::new(move |r| ex1(r).and_then(|m| ex2(m))),
887                embed: Rc::new(move |v| em1(em2(v))),
888            },
889
890            (
891                WritableEnum {
892                    extract: ex1,
893                    extract_mut: _,
894                    embed: em1,
895                },
896                ReadableEnum {
897                    extract: ex2,
898                    embed: em2,
899                },
900            ) => ReadableEnum {
901                extract: Rc::new(move |r| ex1(r).and_then(|m| ex2(m))),
902                embed: Rc::new(move |v| em1(em2(v))),
903            },
904
905            (
906                WritableEnum {
907                    extract: ex1,
908                    extract_mut: exm1,
909                    embed: em1,
910                },
911                WritableEnum {
912                    extract: ex2,
913                    extract_mut: exm2,
914                    embed: em2,
915                },
916            ) => WritableEnum {
917                extract: Rc::new(move |r| ex1(r).and_then(|m| ex2(m))),
918                extract_mut: Rc::new(move |r| exm1(r).and_then(|m| exm2(m))),
919                embed: Rc::new(move |v| em1(em2(v))),
920            },
921
922
923            // New owned keypath compositions
924            (Owned(f1), Owned(f2)) => {
925                Owned(Rc::new(move |r| f2(f1(r))))
926            }
927            (FailableOwned(f1), Owned(f2)) => {
928                FailableOwned(Rc::new(move |r| f1(r).map(|m| f2(m))))
929            }
930            (Owned(f1), FailableOwned(f2)) => {
931                FailableOwned(Rc::new(move |r| f2(f1(r))))
932            }
933            (FailableOwned(f1), FailableOwned(f2)) => {
934                FailableOwned(Rc::new(move |r| f1(r).and_then(|m| f2(m))))
935            }
936
937            // Cross-composition between owned and regular keypaths
938            // Note: These compositions require Clone bounds which may not always be available
939            // For now, we'll skip these complex compositions
940
941            (a, b) => panic!(
942                "Unsupported composition: {:?} then {:?}",
943                kind_name(&a),
944                kind_name(&b)
945            ),
946        }
947    }
948
949    /// Get the kind name of this keypath
950    #[inline]
951    pub fn kind_name(&self) -> &'static str {
952        kind_name(self)
953    }
954}
955
956fn kind_name<Root, Value>(k: &KeyPaths<Root, Value>) -> &'static str {
957    use KeyPaths::*;
958    match k {
959        Readable(_) => "Readable",
960        Writable(_) => "Writable",
961        FailableReadable(_) => "FailableReadable",
962        FailableWritable(_) => "FailableWritable",
963        ReadableEnum { .. } => "ReadableEnum",
964        WritableEnum { .. } => "WritableEnum",
965        // New owned keypath types
966        Owned(_) => "Owned",
967        FailableOwned(_) => "FailableOwned",
968    }
969}
970
971// ===== Helper functions for creating reusable getter functions =====
972// Note: These helper functions have lifetime constraints that make them
973// difficult to implement in Rust's current type system. The keypath
974// instances themselves can be used directly for access.
975
976// ===== Global compose function =====
977
978/// Global compose function that combines two compatible key paths
979pub fn compose<Root, Mid, Value>(
980    kp1: KeyPaths<Root, Mid>,
981    kp2: KeyPaths<Mid, Value>,
982) -> KeyPaths<Root, Value>
983where
984    Root: 'static,
985    Mid: 'static,
986    Value: 'static,
987{
988    kp1.compose(kp2)
989}
990
991// ===== Helper macros for enum case keypaths =====
992
993#[macro_export]
994macro_rules! readable_enum_macro {
995    // Unit variant: Enum::Variant
996    ($enum:path, $variant:ident) => {{
997        $crate::KeyPaths::readable_enum(
998            |_| <$enum>::$variant,
999            |e: &$enum| match e {
1000                <$enum>::$variant => Some(&()),
1001                _ => None,
1002            },
1003        )
1004    }};
1005    // Single-field tuple variant: Enum::Variant(Inner)
1006    ($enum:path, $variant:ident($inner:ty)) => {{
1007        $crate::KeyPaths::readable_enum(
1008            |v: $inner| <$enum>::$variant(v),
1009            |e: &$enum| match e {
1010                <$enum>::$variant(v) => Some(v),
1011                _ => None,
1012            },
1013        )
1014    }};
1015}
1016
1017#[macro_export]
1018macro_rules! writable_enum_macro {
1019    // Unit variant: Enum::Variant (creates prism to and from ())
1020    ($enum:path, $variant:ident) => {{
1021        $crate::KeyPaths::writable_enum(
1022            |_| <$enum>::$variant,
1023            |e: &$enum| match e {
1024                <$enum>::$variant => Some(&()),
1025                _ => None,
1026            },
1027            |e: &mut $enum| match e {
1028                <$enum>::$variant => Some(&mut ()),
1029                _ => None,
1030            },
1031        )
1032    }};
1033    // Single-field tuple variant: Enum::Variant(Inner)
1034    ($enum:path, $variant:ident($inner:ty)) => {{
1035        $crate::KeyPaths::writable_enum(
1036            |v: $inner| <$enum>::$variant(v),
1037            |e: &$enum| match e {
1038                <$enum>::$variant(v) => Some(v),
1039                _ => None,
1040            },
1041            |e: &mut $enum| match e {
1042                <$enum>::$variant(v) => Some(v),
1043                _ => None,
1044            },
1045        )
1046    }};
1047}