1use std::rc::Rc;
2
3pub enum KeyPaths<Root, Value> {
5 Readable(Rc<dyn for<'a> Fn(&'a Root) -> &'a Value>),
6 Writable(Rc<dyn for<'a> Fn(&'a mut Root) -> &'a mut Value>),
7 FailableReadable(Rc<dyn for<'a> Fn(&'a Root) -> Option<&'a Value>>),
8 FailableWritable(Rc<dyn for<'a> Fn(&'a mut Root) -> Option<&'a mut Value>>),
9 }
15
16impl<Root, Value> KeyPaths<Root, Value> {
17 pub fn readable(get: impl for<'a> Fn(&'a Root) -> &'a Value + 'static) -> Self {
18 Self::Readable(Rc::new(get))
19 }
20
21 pub fn writable(get_mut: impl for<'a> Fn(&'a mut Root) -> &'a mut Value + 'static) -> Self {
22 Self::Writable(Rc::new(get_mut))
23 }
24
25 pub fn failable_readable(
26 get: impl for<'a> Fn(&'a Root) -> Option<&'a Value> + 'static,
27 ) -> Self {
28 Self::FailableReadable(Rc::new(get))
29 }
30
31 pub fn failable_writable(
32 get_mut: impl for<'a> Fn(&'a mut Root) -> Option<&'a mut Value> + 'static,
33 ) -> Self {
34 Self::FailableWritable(Rc::new(get_mut))
35 }
36
37 }
41
42impl<Root, Value> KeyPaths<Root, Value> {
43 pub fn get<'a>(&'a self, root: &'a Root) -> Option<&'a Value> {
45 match self {
46 KeyPaths::Readable(f) => Some(f(root)),
47 KeyPaths::Writable(_) => None, KeyPaths::FailableReadable(f) => f(root),
49 KeyPaths::FailableWritable(_) => None, }
52 }
53
54 pub fn get_mut<'a>(&'a self, root: &'a mut Root) -> Option<&'a mut Value> {
56 match self {
57 KeyPaths::Readable(_) => None, KeyPaths::Writable(f) => Some(f(root)),
59 KeyPaths::FailableReadable(_) => None, KeyPaths::FailableWritable(f) => f(root),
61 }
62 }
63 pub fn iter<'a, T>(&'a self, root: &'a Root) -> Option<<&'a Value as IntoIterator>::IntoIter>
65 where
66 &'a Value: IntoIterator<Item = &'a T>,
67 T: 'a,
68 {
69 self.get(root).map(|v| v.into_iter())
70 }
71
72 pub fn iter_mut<'a, T>(
74 &'a self,
75 root: &'a mut Root,
76 ) -> Option<<&'a mut Value as IntoIterator>::IntoIter>
77 where
78 &'a mut Value: IntoIterator<Item = &'a mut T>,
79 T: 'a,
80 {
81 self.get_mut(root).map(|v| v.into_iter())
82 }
83
84 pub fn into_iter<T>(self, root: Root) -> Option<<Value as IntoIterator>::IntoIter>
86 where
87 Value: IntoIterator<Item = T> + Clone,
88 {
89 match self {
90 KeyPaths::Readable(f) => Some(f(&root).clone().into_iter()), KeyPaths::Writable(_) => None,
92 KeyPaths::FailableReadable(f) => f(&root).map(|v| v.clone().into_iter()),
93 KeyPaths::FailableWritable(_) => None,
94 }
95 }
96}
97
98impl<Root, Mid> KeyPaths<Root, Mid>
99where
100 Root: 'static,
101 Mid: 'static,
102{
103 pub fn compose<Value>(self, mid: KeyPaths<Mid, Value>) -> KeyPaths<Root, Value>
104 where
105 Value: 'static,
106 {
107 use KeyPaths::*;
108
109 match (self, mid) {
110 (Readable(f1), Readable(f2)) => Readable(Rc::new(move |r| f2(f1(r)))),
111
112 (Writable(f1), Writable(f2)) => Writable(Rc::new(move |r| f2(f1(r)))),
113
114 (FailableReadable(f1), Readable(f2)) => {
115 FailableReadable(Rc::new(move |r| f1(r).map(|m| f2(m))))
116 }
117
118 (Readable(f1), FailableReadable(f2)) => FailableReadable(Rc::new(move |r| f2(f1(r)))),
119
120 (FailableReadable(f1), FailableReadable(f2)) => {
121 FailableReadable(Rc::new(move |r| f1(r).and_then(|m| f2(m))))
122 }
123
124 (FailableWritable(f1), Writable(f2)) => {
125 FailableWritable(Rc::new(move |r| f1(r).map(|m| f2(m))))
126 }
127
128 (Writable(f1), FailableWritable(f2)) => FailableWritable(Rc::new(move |r| f2(f1(r)))),
129
130 (FailableWritable(f1), FailableWritable(f2)) => {
131 FailableWritable(Rc::new(move |r| f1(r).and_then(|m| f2(m))))
132 }
133
134 (a, b) => panic!(
135 "Unsupported composition: {:?} then {:?}",
136 kind_name(&a),
137 kind_name(&b)
138 ),
139 }
140 }
141}
142
143fn kind_name<Root, Value>(k: &KeyPaths<Root, Value>) -> &'static str {
144 use KeyPaths::*;
145 match k {
146 Readable(_) => "Readable",
147 Writable(_) => "Writable",
148 FailableReadable(_) => "FailableReadable",
149 FailableWritable(_) => "FailableWritable",
150 }
151}