1use std::rc::Rc;
2use std::sync::Arc;
3
4#[derive(Clone)]
5pub enum KeyPaths<Root, Value> {
8 Readable(Rc<dyn for<'a> Fn(&'a Root) -> &'a Value>),
9 ReadableEnum {
10 extract: Rc<dyn for<'a> Fn(&'a Root) -> Option<&'a Value>>,
11 embed: Rc<dyn Fn(Value) -> Root>,
12 },
13 FailableReadable(Rc<dyn for<'a> Fn(&'a Root) -> Option<&'a Value>>),
14
15 Writable(Rc<dyn for<'a> Fn(&'a mut Root) -> &'a mut Value>),
16 FailableWritable(Rc<dyn for<'a> Fn(&'a mut Root) -> Option<&'a mut Value>>),
17 WritableEnum {
18 extract: Rc<dyn for<'a> Fn(&'a Root) -> Option<&'a Value>>,
19 extract_mut: Rc<dyn for<'a> Fn(&'a mut Root) -> Option<&'a mut Value>>,
20 embed: Rc<dyn Fn(Value) -> Root>,
21 },
22
23
24
25 Owned(Rc<dyn Fn(Root) -> Value>),
27 FailableOwned(Rc<dyn Fn(Root) -> Option<Value>>),
28}
29
30impl<Root, Value> KeyPaths<Root, Value> {
31 #[inline]
32 pub fn readable(get: impl for<'a> Fn(&'a Root) -> &'a Value + 'static) -> Self {
33 Self::Readable(Rc::new(get))
34 }
35
36 #[inline]
37 pub fn writable(get_mut: impl for<'a> Fn(&'a mut Root) -> &'a mut Value + 'static) -> Self {
38 Self::Writable(Rc::new(get_mut))
39 }
40
41 #[inline]
42 pub fn failable_readable(
43 get: impl for<'a> Fn(&'a Root) -> Option<&'a Value> + 'static,
44 ) -> Self {
45 Self::FailableReadable(Rc::new(get))
46 }
47
48 #[inline]
49 pub fn failable_writable(
50 get_mut: impl for<'a> Fn(&'a mut Root) -> Option<&'a mut Value> + 'static,
51 ) -> Self {
52 Self::FailableWritable(Rc::new(get_mut))
53 }
54
55 #[inline]
56 pub fn readable_enum(
57 embed: impl Fn(Value) -> Root + 'static,
58 extract: impl for<'a> Fn(&'a Root) -> Option<&'a Value> + 'static,
59 ) -> Self {
60 Self::ReadableEnum {
61 extract: Rc::new(extract),
62 embed: Rc::new(embed),
63 }
64 }
65
66 #[inline]
67 pub fn writable_enum(
68 embed: impl Fn(Value) -> Root + 'static,
69 extract: impl for<'a> Fn(&'a Root) -> Option<&'a Value> + 'static,
70 extract_mut: impl for<'a> Fn(&'a mut Root) -> Option<&'a mut Value> + 'static,
71 ) -> Self {
72 Self::WritableEnum {
73 extract: Rc::new(extract),
74 embed: Rc::new(embed),
75 extract_mut: Rc::new(extract_mut),
76 }
77 }
78
79
80 #[inline]
82 pub fn owned(get: impl Fn(Root) -> Value + 'static) -> Self {
83 Self::Owned(Rc::new(get))
84 }
85
86 #[inline]
87 pub fn failable_owned(get: impl Fn(Root) -> Option<Value> + 'static) -> Self {
88 Self::FailableOwned(Rc::new(get))
89 }
90
91 #[inline]
92 pub fn owned_writable(get: impl Fn(Root) -> Value + 'static) -> Self {
93 Self::Owned(Rc::new(get))
94 }
95
96 #[inline]
97 pub fn failable_owned_writable(get: impl Fn(Root) -> Option<Value> + 'static) -> Self {
98 Self::FailableOwned(Rc::new(get))
99 }
100}
101
102impl<Root, Value> KeyPaths<Root, Value> {
103 #[inline]
105 pub fn get<'a>(&'a self, root: &'a Root) -> Option<&'a Value> {
106 match self {
107 KeyPaths::Readable(f) => Some(f(root)),
108 KeyPaths::Writable(_) => None, KeyPaths::FailableReadable(f) => f(root),
110 KeyPaths::FailableWritable(_) => None, KeyPaths::ReadableEnum { extract, .. } => extract(root),
112 KeyPaths::WritableEnum { extract, .. } => extract(root),
113 KeyPaths::Owned(_) => None, KeyPaths::FailableOwned(_) => None, }
117 }
118
119 #[inline]
122 pub fn get_ref<'a, 'b>(&'a self, root: &'b &Root) -> Option<&'b Value>
123 where
124 'a: 'b,
125 {
126 self.get(*root)
127 }
128
129 #[inline]
131 pub fn get_mut<'a>(&'a self, root: &'a mut Root) -> Option<&'a mut Value> {
132 match self {
133 KeyPaths::Readable(_) => None, KeyPaths::Writable(f) => Some(f(root)),
135 KeyPaths::FailableReadable(_) => None, KeyPaths::FailableWritable(f) => f(root),
137 KeyPaths::ReadableEnum { .. } => None, KeyPaths::WritableEnum { extract_mut, .. } => extract_mut(root),
139 KeyPaths::Owned(_) => None, KeyPaths::FailableOwned(_) => None, }
143 }
144
145 #[inline]
148 pub fn get_mut_ref<'a, 'b>(&'a self, root: &'b mut &mut Root) -> Option<&'b mut Value>
149 where
150 'a: 'b,
151 {
152 self.get_mut(*root)
153 }
154
155 #[inline]
162 pub fn for_arc(self) -> KeyPaths<Arc<Root>, Value>
163 where
164 Root: 'static,
165 Value: 'static,
166 {
167 match self {
168 KeyPaths::Readable(f) => KeyPaths::Readable(Rc::new(move |root: &Arc<Root>| {
169 f(&**root)
170 })),
171 KeyPaths::Writable(_) => {
172 panic!("Cannot create writable keypath for Arc (Arc is immutable)")
174 }
175 KeyPaths::FailableReadable(f) => {
176 KeyPaths::FailableReadable(Rc::new(move |root: &Arc<Root>| f(&**root)))
177 }
178 KeyPaths::ReadableEnum { extract, embed } => KeyPaths::ReadableEnum {
179 extract: Rc::new(move |root: &Arc<Root>| extract(&**root)),
180 embed: Rc::new(move |value| Arc::new(embed(value))),
181 },
182 other => panic!("Unsupported keypath variant for Arc adapter: {:?}", kind_name(&other)),
183 }
184 }
185
186 #[inline]
189 pub fn for_box(self) -> KeyPaths<Box<Root>, Value>
190 where
191 Root: 'static,
192 Value: 'static,
193 {
194 match self {
195 KeyPaths::Readable(f) => KeyPaths::Readable(Rc::new(move |root: &Box<Root>| {
196 f(&**root)
197 })),
198 KeyPaths::Writable(f) => KeyPaths::Writable(Rc::new(move |root: &mut Box<Root>| {
199 f(&mut **root)
200 })),
201 KeyPaths::FailableReadable(f) => {
202 KeyPaths::FailableReadable(Rc::new(move |root: &Box<Root>| f(&**root)))
203 }
204 KeyPaths::FailableWritable(f) => {
205 KeyPaths::FailableWritable(Rc::new(move |root: &mut Box<Root>| f(&mut **root)))
206 }
207 KeyPaths::ReadableEnum { extract, embed } => KeyPaths::ReadableEnum {
208 extract: Rc::new(move |root: &Box<Root>| extract(&**root)),
209 embed: Rc::new(move |value| Box::new(embed(value))),
210 },
211 KeyPaths::WritableEnum { extract, extract_mut, embed } => KeyPaths::WritableEnum {
212 extract: Rc::new(move |root: &Box<Root>| extract(&**root)),
213 extract_mut: Rc::new(move |root: &mut Box<Root>| extract_mut(&mut **root)),
214 embed: Rc::new(move |value| Box::new(embed(value))),
215 },
216 other => panic!("Unsupported keypath variant for Box adapter: {:?}", kind_name(&other)),
217 }
218 }
219
220 #[inline]
223 pub fn for_rc(self) -> KeyPaths<Rc<Root>, Value>
224 where
225 Root: 'static,
226 Value: 'static,
227 {
228 match self {
229 KeyPaths::Readable(f) => KeyPaths::Readable(Rc::new(move |root: &Rc<Root>| {
230 f(&**root)
231 })),
232 KeyPaths::Writable(_) => {
233 panic!("Cannot create writable keypath for Rc (Rc is immutable)")
235 }
236 KeyPaths::FailableReadable(f) => {
237 KeyPaths::FailableReadable(Rc::new(move |root: &Rc<Root>| f(&**root)))
238 }
239 KeyPaths::ReadableEnum { extract, embed } => KeyPaths::ReadableEnum {
240 extract: Rc::new(move |root: &Rc<Root>| extract(&**root)),
241 embed: Rc::new(move |value| Rc::new(embed(value))),
242 },
243 other => panic!("Unsupported keypath variant for Rc adapter: {:?}", kind_name(&other)),
244 }
245 }
246
247 pub fn embed(&self, value: Value) -> Option<Root>
248 where
249 Value: Clone,
250 {
251 match self {
252 KeyPaths::ReadableEnum { embed, .. } => Some(embed(value)),
253 _ => None,
254 }
255 }
256
257 pub fn embed_mut(&self, value: Value) -> Option<Root>
258 where
259 Value: Clone,
260 {
261 match self {
262 KeyPaths::WritableEnum { embed, .. } => Some(embed(value)),
263 _ => None,
264 }
265 }
266
267
268 #[inline]
272 pub fn get_owned(self, root: Root) -> Value {
273 match self {
274 KeyPaths::Owned(f) => f(root),
275 _ => panic!("get_owned only works with owned keypaths"),
276 }
277 }
278
279 #[inline]
281 pub fn get_failable_owned(self, root: Root) -> Option<Value> {
282 match self {
283 KeyPaths::FailableOwned(f) => f(root),
284 _ => panic!("get_failable_owned only works with failable owned keypaths"),
285 }
286 }
287
288 pub fn iter<'a, T>(&'a self, root: &'a Root) -> Option<<&'a Value as IntoIterator>::IntoIter>
290 where
291 &'a Value: IntoIterator<Item = &'a T>,
292 T: 'a,
293 {
294 self.get(root).map(|v| v.into_iter())
295 }
296
297 pub fn iter_mut<'a, T>(
299 &'a self,
300 root: &'a mut Root,
301 ) -> Option<<&'a mut Value as IntoIterator>::IntoIter>
302 where
303 &'a mut Value: IntoIterator<Item = &'a mut T>,
304 T: 'a,
305 {
306 self.get_mut(root).map(|v| v.into_iter())
307 }
308
309 #[inline]
311 pub fn into_iter<T>(self, root: Root) -> Option<<Value as IntoIterator>::IntoIter>
312 where
313 Value: IntoIterator<Item = T> + Clone,
314 {
315 match self {
316 KeyPaths::Readable(f) => Some(f(&root).clone().into_iter()), KeyPaths::Writable(_) => None,
318 KeyPaths::FailableReadable(f) => f(&root).map(|v| v.clone().into_iter()),
319 KeyPaths::FailableWritable(_) => None,
320 KeyPaths::ReadableEnum { extract, .. } => extract(&root).map(|v| v.clone().into_iter()),
321 KeyPaths::WritableEnum { extract, .. } => extract(&root).map(|v| v.clone().into_iter()),
322 KeyPaths::Owned(f) => Some(f(root).into_iter()),
324 KeyPaths::FailableOwned(f) => f(root).map(|v| v.into_iter()),
325 }
326 }
327}
328
329impl<Root, Mid> KeyPaths<Root, Mid>
330where
331 Root: 'static,
332 Mid: 'static,
333{
334 #[inline]
336 pub fn then<Value>(self, mid: KeyPaths<Mid, Value>) -> KeyPaths<Root, Value>
337 where
338 Value: 'static,
339 {
340 self.compose(mid)
341 }
342
343 pub fn compose<Value>(self, mid: KeyPaths<Mid, Value>) -> KeyPaths<Root, Value>
344 where
345 Value: 'static,
346 {
347 use KeyPaths::*;
348
349 match (self, mid) {
350 (Readable(f1), Readable(f2)) => Readable(Rc::new(move |r| f2(f1(r)))),
351
352 (Writable(f1), Writable(f2)) => Writable(Rc::new(move |r| f2(f1(r)))),
353
354 (FailableReadable(f1), Readable(f2)) => {
355 FailableReadable(Rc::new(move |r| f1(r).map(|m| f2(m))))
356 }
357
358 (Readable(f1), FailableReadable(f2)) => FailableReadable(Rc::new(move |r| f2(f1(r)))),
359
360 (FailableReadable(f1), FailableReadable(f2)) => {
361 FailableReadable(Rc::new(move |r| f1(r).and_then(|m| f2(m))))
362 }
363
364 (FailableWritable(f1), Writable(f2)) => {
365 FailableWritable(Rc::new(move |r| f1(r).map(|m| f2(m))))
366 }
367
368 (Writable(f1), FailableWritable(f2)) => FailableWritable(Rc::new(move |r| f2(f1(r)))),
369
370 (FailableWritable(f1), FailableWritable(f2)) => {
371 FailableWritable(Rc::new(move |r| f1(r).and_then(|m| f2(m))))
372 }
373 (FailableReadable(f1), ReadableEnum { extract, .. }) => {
374 FailableReadable(Rc::new(move |r| f1(r).and_then(|m| extract(m))))
375 }
376 (ReadableEnum { extract, .. }, Readable(f2)) => {
380 FailableReadable(Rc::new(move |r| extract(r).map(|m| f2(m))))
381 }
382
383 (ReadableEnum { extract, .. }, FailableReadable(f2)) => {
384 FailableReadable(Rc::new(move |r| extract(r).and_then(|m| f2(m))))
385 }
386
387 (WritableEnum { extract, .. }, Readable(f2)) => {
388 FailableReadable(Rc::new(move |r| extract(r).map(|m| f2(m))))
389 }
390
391 (WritableEnum { extract, .. }, FailableReadable(f2)) => {
392 FailableReadable(Rc::new(move |r| extract(r).and_then(|m| f2(m))))
393 }
394
395 (WritableEnum { extract_mut, .. }, Writable(f2)) => {
396 FailableWritable(Rc::new(move |r| extract_mut(r).map(|m| f2(m))))
397 }
398
399 (
400 FailableWritable(f_root_mid),
401 WritableEnum {
402 extract_mut: exm_mid_val,
403 ..
404 },
405 ) => {
406 FailableWritable(Rc::new(move |r: &mut Root| {
407 let intermediate_mid_ref = f_root_mid(r);
410
411 intermediate_mid_ref.and_then(|intermediate_mid| exm_mid_val(intermediate_mid))
414 }))
415 }
416
417 (WritableEnum { extract_mut, .. }, FailableWritable(f2)) => {
418 FailableWritable(Rc::new(move |r| extract_mut(r).and_then(|m| f2(m))))
419 }
420
421 (Writable(f1), WritableEnum { extract_mut, .. }) => {
423 FailableWritable(Rc::new(move |r: &mut Root| {
424 let mid: &mut Mid = f1(r);
425 extract_mut(mid)
426 }))
427 }
428
429 (
430 ReadableEnum {
431 extract: ex1,
432 embed: em1,
433 },
434 ReadableEnum {
435 extract: ex2,
436 embed: em2,
437 },
438 ) => ReadableEnum {
439 extract: Rc::new(move |r| ex1(r).and_then(|m| ex2(m))),
440 embed: Rc::new(move |v| em1(em2(v))),
441 },
442
443 (
444 WritableEnum {
445 extract: ex1,
446 extract_mut: _,
447 embed: em1,
448 },
449 ReadableEnum {
450 extract: ex2,
451 embed: em2,
452 },
453 ) => ReadableEnum {
454 extract: Rc::new(move |r| ex1(r).and_then(|m| ex2(m))),
455 embed: Rc::new(move |v| em1(em2(v))),
456 },
457
458 (
459 WritableEnum {
460 extract: ex1,
461 extract_mut: exm1,
462 embed: em1,
463 },
464 WritableEnum {
465 extract: ex2,
466 extract_mut: exm2,
467 embed: em2,
468 },
469 ) => WritableEnum {
470 extract: Rc::new(move |r| ex1(r).and_then(|m| ex2(m))),
471 extract_mut: Rc::new(move |r| exm1(r).and_then(|m| exm2(m))),
472 embed: Rc::new(move |v| em1(em2(v))),
473 },
474
475
476 (Owned(f1), Owned(f2)) => {
478 Owned(Rc::new(move |r| f2(f1(r))))
479 }
480 (FailableOwned(f1), Owned(f2)) => {
481 FailableOwned(Rc::new(move |r| f1(r).map(|m| f2(m))))
482 }
483 (Owned(f1), FailableOwned(f2)) => {
484 FailableOwned(Rc::new(move |r| f2(f1(r))))
485 }
486 (FailableOwned(f1), FailableOwned(f2)) => {
487 FailableOwned(Rc::new(move |r| f1(r).and_then(|m| f2(m))))
488 }
489
490 (a, b) => panic!(
495 "Unsupported composition: {:?} then {:?}",
496 kind_name(&a),
497 kind_name(&b)
498 ),
499 }
500 }
501
502 #[inline]
504 pub fn kind_name(&self) -> &'static str {
505 kind_name(self)
506 }
507}
508
509fn kind_name<Root, Value>(k: &KeyPaths<Root, Value>) -> &'static str {
510 use KeyPaths::*;
511 match k {
512 Readable(_) => "Readable",
513 Writable(_) => "Writable",
514 FailableReadable(_) => "FailableReadable",
515 FailableWritable(_) => "FailableWritable",
516 ReadableEnum { .. } => "ReadableEnum",
517 WritableEnum { .. } => "WritableEnum",
518 Owned(_) => "Owned",
520 FailableOwned(_) => "FailableOwned",
521 }
522}
523
524pub fn compose<Root, Mid, Value>(
533 kp1: KeyPaths<Root, Mid>,
534 kp2: KeyPaths<Mid, Value>,
535) -> KeyPaths<Root, Value>
536where
537 Root: 'static,
538 Mid: 'static,
539 Value: 'static,
540{
541 kp1.compose(kp2)
542}
543
544#[macro_export]
547macro_rules! readable_enum_macro {
548 ($enum:path, $variant:ident) => {{
550 $crate::KeyPaths::readable_enum(
551 |_| <$enum>::$variant,
552 |e: &$enum| match e {
553 <$enum>::$variant => Some(&()),
554 _ => None,
555 },
556 )
557 }};
558 ($enum:path, $variant:ident($inner:ty)) => {{
560 $crate::KeyPaths::readable_enum(
561 |v: $inner| <$enum>::$variant(v),
562 |e: &$enum| match e {
563 <$enum>::$variant(v) => Some(v),
564 _ => None,
565 },
566 )
567 }};
568}
569
570#[macro_export]
571macro_rules! writable_enum_macro {
572 ($enum:path, $variant:ident) => {{
574 $crate::KeyPaths::writable_enum(
575 |_| <$enum>::$variant,
576 |e: &$enum| match e {
577 <$enum>::$variant => Some(&()),
578 _ => None,
579 },
580 |e: &mut $enum| match e {
581 <$enum>::$variant => Some(&mut ()),
582 _ => None,
583 },
584 )
585 }};
586 ($enum:path, $variant:ident($inner:ty)) => {{
588 $crate::KeyPaths::writable_enum(
589 |v: $inner| <$enum>::$variant(v),
590 |e: &$enum| match e {
591 <$enum>::$variant(v) => Some(v),
592 _ => None,
593 },
594 |e: &mut $enum| match e {
595 <$enum>::$variant(v) => Some(v),
596 _ => None,
597 },
598 )
599 }};
600}